我对Interface和BeanInfo Introspector中的默认方法有一点问题。 在此示例中,有interface:Interface
public static interface Interface {
default public String getLetter() {
return "A";
}
}
和两个类ClassA和ClassB:
public static class ClassA implements Interface {
}
public static class ClassB implements Interface {
public String getLetter() {
return "B";
}
}
在main方法应用程序中打印来自BeanInfo的PropertyDescriptors:
public static String formatData(PropertyDescriptor[] pds) {
return Arrays.asList(pds).stream()
.map((pd) -> pd.getName()).collect(Collectors.joining(", "));
}
public static void main(String[] args) {
try {
System.out.println(
formatData(Introspector.getBeanInfo(ClassA.class)
.getPropertyDescriptors()));
System.out.println(
formatData(Introspector.getBeanInfo(ClassB.class)
.getPropertyDescriptors()));
} catch (IntrospectionException e) {
e.printStackTrace();
}
}
结果是:
class
class, letter
为什么选择默认方法"字母"在ClassA中不可见作为属性?是错误还是功能?
答案 0 :(得分:4)
我猜,Introspector
不会处理interface
层次结构链,即使使用Java 8虚拟扩展方法(也称为防御者,默认方法)接口可以使某些东西看起来像属性方法。这是一个相当简单的内省探测器,声称它:BeanIntrospector
这是否可以被认为是一个灰色区域,这就是为什么我这么认为。
显然,现在一个类可以从一个接口“继承”一个方法,该方法具有通常被认为是getter / setter / mutator的所有特性。但与此同时,这一切都违背了接口的目的 - 接口不可能提供任何可被视为属性的东西,因为它是无状态且无行为的,它只是意味着描述行为。即使是defender方法也基本上是静态的,除非它们访问具体实现的真实属性。
另一方面,如果我们假设防御者正式继承(而不是提供默认实现,这在某种程度上是一个不明确的定义),他们应该导致合成在实现类中创建的方法,以及属于该类的方法,并作为PropertyDescriptor
查找的一部分进行遍历。 显然这不是它的方式,否则整个事情都会起作用。 :)似乎防守方法在这里得到某种特殊待遇。
答案 1 :(得分:1)
我认为这也是一个错误。 你可以使用专门的BeanInfo为你的类解决这个问题,并提供类似的东西:
/* (non-Javadoc)
* @see java.beans.SimpleBeanInfo#getAdditionalBeanInfo()
*/
@Override
public BeanInfo[] getAdditionalBeanInfo()
{
Class<?> superclass = Interface.class;
BeanInfo info = null;
try
{
info = Introspector.getBeanInfo(superclass);
}
catch (IntrospectionException e)
{
//nothing to do
}
if (info != null)
return new BeanInfo[] { info };
return null;
}
答案 2 :(得分:0)
这是因为您只在Interface和ClassB上使用您的方法,而不是直接在ClassA上。然而,这听起来像是一个bug,因为我希望该属性能够在列表中显示出来。我怀疑Inrospector还没有赶上Java 8的功能。
答案 3 :(得分:0)
调试显示此方法已在Introspector#getPublicDeclaredMethods()
过滤掉:
if (!method.getDeclaringClass().equals(clz)) {
result[i] = null; // ignore methods declared elsewhere
}
其中clz
是相关类的完全限定名称。
由于ClassB
具有此方法的自定义实现,因此它会在ClassA
没有成功通过检查。