我想通过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
。
如果我的解释有误,请指正。
不要那样依赖Modifier.toString
。在过去,类、字段和方法的修饰符被赋予唯一的不同值,这样您就可以解释它们,而不必像该方法所建议的那样查看拥有修饰符的实体的类型。
但是随着Java的发展,增加了更多的修饰符位,无法保持该属性。特别是,当不加修改地将方法的修饰符位传递给Modifier.toString
时,您将得到以下令人惊讶的行为:
- a 桥接方法将打印为
volatile
- a varargs方法将打印为
transient
因此你应该过滤比特。Java 7引入了一个提供正确掩码的方法,这样您就可以使用Modifier.toString(m.getModifiers()&Modifier.methodModifiers())
。
但是这仅仅是因为旧的Java关键字映射到唯一的修饰符位,而新的修饰符位与关键字没有关联。对于较新的Java版本,即使这样也可能不够。
对于default
关键字,它甚至更简单:没有与关键字关联的修饰符位。如果在 interface
中出现public
、非abstract
、非static
方法,则该方法一定是default
方法。这就是Method.isDefault()
如何确定一个方法是否是default
方法。Modifier.toString(…)
没有机会知道声明类是否为interface
,因此永远不会打印default
。
在最近版本的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