gpt4 book ai didi

How to check if a class is capable of implementing an interface at runtime in Java (JDK 17)(如何在Java中检查类是否能够在运行时实现接口(JDK 17))

转载 作者:bug小助手 更新时间:2023-10-25 14:11:44 33 4
gpt4 key购买 nike



I need to determine whether a class is capable of implementing an interface when it does not explicitly implement that interface. I would like to determine this at runtime, I am using reflections to gather classes.

我需要确定一个类在没有显式实现接口时是否能够实现该接口。我想在运行时确定这一点,我使用反射来收集类。


For example:

例如:


Lets say I have the following class:

假设我有以下类:


public class Clazz {
public void doSomething() {
// ... do it
}
}

And the following interface:

和以下接口:


public interface ClazzInterface {
public void doSomething();
}

Clazz does not implement ClazzInterface, however it is compatible with ClazzInterface and could implement it without any modification. I am looking for a way to check this at runtime.

Clazz不实现ClazzInterface,但它与ClazzInterface兼容,无需任何修改即可实现。我正在寻找一种在运行时检查这一点的方法。


Something like:

类似于:


boolean canImplement = Clazz.class canImplement ClazzInterface.class

Is this possible either through a built in library or method or some logic I could write myself?

通过内置库或方法或我可以自己编写的逻辑,这是可能的吗?


I have tried using reflections isAssignableFrom and this does not work, returning false for the above example.

我尝试使用反射isAssignableFrom,但这不起作用,上面的例子返回false。


更多回答

How did you try isAssignableFrom? It should be the way to go.

您是如何尝试使用isAssignable From的?这应该是一条可行的道路。

@daniu are you sure that Class::isAssignableFrom (docs.oracle.com) should work? IIRC, isAssignableFrom(...) checks the object hierarchy. Since the class in question does not implements the interface, I think this would not work.

@daniu您确定Class::isAssignableFrom(docs.oracle.com)应该起作用吗?IIRC,isAssignableFrom(...)检查对象层次结构。由于所讨论的类不实现该接口,我认为这是行不通的。

It is definitively possible to implement a check for this; the compiler does this check (otherwise it would not be able to find certain errors when we implement an interface). I wonder, however, what the end goal here is. We'd need to either manipulate the bytecode of the (already compiled) class, or modify the (source code of the) class and recompile. This smells like an XY problem (xyproblem.info). What are you actually trying to achieve?

实现对此的检查是绝对可能的;编译器进行此检查(否则,当我们实现接口时,它将无法发现某些错误)。然而,我想知道这里的最终目标是什么。我们需要操作(已经编译的)类的字节码,或者修改(类的源代码)并重新编译。这闻起来像是XY问题(xyproblem.info)。你到底想要达到什么目的?

Yet another idea is to let the Interface return Object. We can then test the runtime type of the returned value with instanceof ... or .getClass().getCanonocalName() or ... as part of the test procedure. Of course, we should then mention that the interface returns Object because part of the exercise is to determine the return type.

还有一个想法是让接口返回对象。然后,我们可以使用instanceof测试返回值的运行时类型。或.getClass().getCanonocalName()或...作为测试程序的一部分。当然,接下来我们应该提到接口返回对象,因为练习的一部分是确定返回类型。

Voting to re-open. Closing for "seeking recommendations for books, tools, software libraries" is an over-reaction and a misinterpretation. This is actually a question about the intricacies of using reflection.

投票决定重新开业。以“为书籍、工具、软件库寻找推荐”来结尾是一种过度反应和误解。这实际上是一个关于使用反射的复杂性的问题。

优秀答案推荐

There is no such concept of "is capable of implementing" an interface. A class either does (or does not) implement an interface. However, you can use reflection to dynamically call some method. It has caveats and limitations (of course). For example, it's usually slow. But here is a doSomething with "duck-typing".

不存在这样的概念,即“能够实现”接口。类实现(或不实现)接口。但是,您可以使用反射来动态调用某些方法。当然,它有一些警告和局限性。例如,它通常很慢。但这里有一件事是“打鸭子”的。


public static final void doSomething(Object o) {
if (o == null) {
return;
}
Class<?> cls = o.getClass();
try {
Method m = cls.getMethod("doSomething", new Class<?>[] {});
if (m != null) {
m.invoke(o, new Object[] {});
}
} catch (final Exception e) {
e.printStackTrace();
}
}

Note the line if (m != null), that does check if doSomething is available in the actual instance o. You could test for the presence of all necessary methods in the same manner.

注意if(m!=空)这一行,它检查DoSomething在实际实例o中是否可用。您可以用同样的方式测试是否存在所有必要的方法。



Problem statement


OP clarified in the comments that the goal is to build an evaluation system for exercises given to students, I see some approaches that do not require reflection.

OP在评论中澄清,我们的目标是为学生提供的练习建立一个评估系统,我看到了一些不需要反思的方法。


Approach 1: return Object


We can release the interface-definition to the students, but replace the return-type with Object. We can then check the runtime-type of the return value via instanceof or Class::isAssignableFrom (docs.oracle.com) (or really any other way we see fit).

我们可以将接口定义发布给学生,但将返回类型替换为Object。然后,我们可以通过instanceof或Class::isAssignableFrom(docs.oracle.com)(或者实际上我们认为合适的任何其他方式)检查返回值的运行时类型。


Approach 2: Modify the source code to add implements <interface>


There are many way we could do this, e.g. a simple bash-script like

我们有很多方法可以做到这一点,例如,一个简单的bash脚本,比如


find \
src/main/java \
-type f \
-name "*.java" \
-exec \
sed \
-i \
's/^\(.*class\s\+Bar\)\s\+{.*$/\1 implements Foo {/g' \
{} \;

We can then incorporate this script in a plethora of ways in our build-process. The downside of this approach is that it is OS-depndent.

然后,我们可以在构建过程中以多种方式合并该脚本。这种方法的缺点是它依赖于操作系统。


I would like to highlight another approach using OpenRewrite (docs.openrewrite.org), which is OS-independent. OpenRewrite allows us, among other things, to formulate simple rules for refactoring in a declarative way. In our example, we want to replace the string class <classname> with class <classname> implements <interfacename>. If we assume the name of the interface to be Foo and the name of the class to be Bar, a OpenRewrite recipe may look like this:

我想强调的是另一种使用OpenReWrite.org的方法,它独立于操作系统。OpenRewrite允许我们以声明式的方式制定简单的重构规则。在我们的示例中,我们希望将字符串CLASS 替换为类 Implementes 。如果我们假设接口的名称为foo,类的名称为Bar,则OpenRewrite配方可能如下所示:


type: specs.openrewrite.org/v1beta/recipe
name: de.turing85.AddFooInterfaceToBarClass
displayName: Add the Foo interface to the Bar class.
recipeList:
- org.openrewrite.text.FindAndReplace:
find: (?<classdef>class\s+Bar)\s+\{
replace: ${classdef} implements Foo {
regex: true
filePattern: src/main/java/**/*.java

Since OpenRewrite provides a maven- (docs.openrewrite.org) and a gradle-plugin (docs.openrewrite.org), we can simply incoroprate it in our build-process.

因为OpenRewrite提供了maven-(docs.OpenreWrite.org)和Gradle-plugin(docs.OpenreWrite.org),所以我们可以在构建过程中简单地将其合并。


A POC can be found in this github.com repository.

PoC可以在这个githorb.com存储库中找到。


更多回答

I think this should solve it, for the functionality I need. Thanks.

我认为这应该可以解决它,因为我需要的功能。谢谢。

cls.getMethod will never return null. A NoSuchMethodException is thrown if the method does not exist.

getMethod永远不会返回null。如果方法不存在,则抛出NoSuchMethodException。

Also, you can make use of varargs for the argument types: cls.getMethod("doSomething") is equivalent to what you typed. You want to reflectively get an equals method? Just use cls.getMethod("equals", Object.class).

此外,您还可以为参数类型使用varargs:cls.getMethod(“DoSomething”)等同于您输入的内容。你想反射地得到一个等于的方法吗?只需使用cls.getMethod(“equals”,Object.class)即可。

There is no such concept of "is capable of implementing" an interface. A class either does (or does not) implement an interface. I disagree. Imo, is capable means that you could recompile the class to implement the interface without error, requiring no further modification of the class. This might be accomplished by reflective analysis of all aspects of the interface methods to see if they match those same methods in the class.

不存在这样的概念,即“能够实现”接口。类实现(或不实现)接口。我不同意。是有能力的,这意味着您可以重新编译类来实现接口而不会出错,不需要进一步修改类。这可以通过对接口方法的所有方面进行反射分析来实现,以查看它们是否与类中的相同方法匹配。

And I don't believe this would require using an object of the class but just using Class/interface interogation.

我认为这不需要使用类的对象,而只需要使用类/接口对话。

33 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com