如何使用Java反射机制找到接口中的“默认”方法?

7
我希望通过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个回答

6
不要依赖于Modifier.toString。过去,类、字段和方法的修饰符都被赋予了独特的值,因此您可以解释它们,而无需查看拥有修饰符的实体的类型,就像该方法所建议的那样。
但是,随着Java的发展,添加了更多的修饰符位,这种属性无法保持。特别是,当将方法的修饰符位传递给Modifier.toString时,您将获得以下令人惊讶的行为:
  • 桥接方法将被打印为volatile
  • 可变参数方法将被打印为transient
因此,您应该过滤这些位。Java 7 引入了一种提供正确掩码的方法,以便您可以使用Modifier.toString(m.getModifiers()&Modifier.methodModifiers())
但是,这仅适用于旧的Java关键字映射到唯一的修饰符位,并且新的修饰符位没有与关键字相关联的情况。对于更新的Java版本,甚至这也可能不足够。
对于关键字default,它更简单:没有与该关键字相关联的修饰符位。如果在interface中出现一个public、非abstract、非static方法,则必须是一个default方法。这就是Method.isDefault()确定方法是否为default方法的方式。Modifier.toString(…)无法知道声明类是否为interface,因此永远不会打印default

5
在最新的Java8更新版本中,我们在java.lang.reflect.Method类中有一个isDefault()方法,可以帮助我们实现此功能。稍微修改一下之前的代码即可得到结果。
代码:
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更新20中进行了测试


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接