19

我对 Interface 和 BeanInfo Introspector 中的默认方法有一点问题。在这个例子中,有接口:接口

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 方法中,app 从 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 中不作为属性可见?是错误还是功能?

4

4 回答 4

5

我想,即使使用 Java 8 虚拟扩展方法(又名防御者,默认方法),接口也Introspector不会处理interface层次结构链,但接口可以有一些有点像属性方法的东西。这是一个相当简单的自省器,声称它确实如此:BeanIntrospector

这是否可以被认为是一个错误在某种程度上是一个灰色地带,这就是我这么认为的原因。

显然,现在一个类可以从接口“继承”一个方法,该方法具有官方认为的 getter/setter/mutator 的所有品质。但与此同时,这一切都违背了接口的目的——接口不可能提供任何可以被视为属性的东西,因为它是无状态和无行为的,它只是用来描述行为。即使是防御者方法也基本上是静态的,除非它们访问具体实现的真实属性。

另一方面,如果我们假设防御者是官方继承的(而不是提供默认实现,这是一个相当模糊的定义),它们应该导致在实现类中创建合成方法,并且那些属于该类并被遍历为PropertyDescriptor查找的一部分。显然这不是它的方式,否则整个事情都会起作用。:)似乎防御者方法在这里得到了某种特殊待遇。

于 2014-04-22T20:33:43.593 回答
2

调试显示此方法在以下位置被过滤掉Introspector#getPublicDeclaredMethods()

if (!method.getDeclaringClass().equals(clz)) {
    result[i] = null; // ignore methods declared elsewhere
}

whereclz是相关类的完全限定名称。

由于ClassB有此方法的自定义实现,因此它成功通过了检查,而ClassA没有通过。

于 2014-04-22T20:31:38.083 回答
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;
}
于 2018-04-27T12:35:17.330 回答
0

这是因为您只有在 Interface 和 ClassB 上拥有您的方法,而不是直接在 ClassA 上。然而,这对我来说听起来像是一个错误,因为我希望该属性会出现在列表中。我怀疑 Inrospector 还没有赶上 Java 8 的特性。

于 2014-04-22T19:39:15.923 回答