如何使用java反射从界面中找到“默认”方法?

时间:2014-08-24 21:23:28

标签: reflection java-8

我想通过java反射找出方法是否为"默认方法" 。我尝试打印java.lang.Iterable的方法。


代码段:

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

public class ReflectionTest {

public static void main(String[] args) {
    Class c = Iterable.class;

    for(Method m : c.getDeclaredMethods())
    {
        System.out.print(Modifier.toString(m.getModifiers()));
        System.out.println("  "+m.getName());
    }
  }
}


结果:

public abstract  iterator
public  spliterator
public  forEach

这里,spliterator()和forEach()应该打印default 如果我的解释错误,请纠正我。

2 个答案:

答案 0 :(得分:5)

在最新版本的java8更新中,我们在isDefault()类中有java.lang.reflect.Method,这就是诀窍。
稍微修改我之前的代码会产生结果。

<强>代码:

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

public class ReflectionTest {

  public static void main(String[] args) {
    Class c = Iterable.class;

    for(Method m : c.getDeclaredMethods())
    {
        System.out.print(Modifier.toString(m.getModifiers()));
        System.out.println("  "+(m.isDefault()?"default ":"")+m.getName());
    }
  }
}


输出:

public abstract  iterator
public  default spliterator
public  default forEach


注意:我在jdk8 update 20

中对此进行了测试

答案 1 :(得分:5)

不要以这种方式依赖Modifier.toString。在过去,类,字段和方法的修饰符被赋予唯一的不同值,因此您可以在不查看拥有修饰符的实体类型的情况下解释它们,就像该方法所暗示的那样。

但是随着Java的发展,添加了更多的修饰符位,并且无法保存该属性。特别是,当方法的修饰符位未经修改地传递给Modifier.toString时,您将得到以下令人惊讶的行为:

  • bridge 方法将打印为volatile
  • varargs 方法将打印为transient

因此你应该过滤这些位。 Java 7 introduced a method providing the right mask以便您可以使用Modifier.toString(m.getModifiers()&Modifier.methodModifiers())

但这只能起作用,因为旧的Java关键字映射到唯一的修饰符位,而较新的修饰符位不与关键字相关联。对于较新的Java版本,即使这可能还不够。

对于default关键字,它甚至更简单:没有与关键字关联的修饰符位。如果public,非abstract,非static方法出现在 interface 中,则必须采用default方法。这就是Method.isDefault()确定方法是否为default方法的方式。 Modifier.toString(…)无法知道声明类是interface,因此永远不会打印default