2

我有一个通用类:

public class Facet<C extends Component>
{
    private final C child;

    public Facet(C child) { this.child = child; }

    public C getChild() { return this.child; }

    public UIComponent getViewComponent() {
        return PrimeFacesComponentFactory.create(facesContext, this.getChild());
    }
}

我有一个组件工厂,它也有一堆方法,其中几个看起来像这样:

public static UIComponent create(FacesContext fc, Component component) {
    throw new UnsupportedOperationException("Method not yet implemented for class: " + component.getClass().getName());
}

public static UIRow create(FacesContext fc, Row modelRow) { ... }

public static UIColumn create(FacesContext fc, Column modelColumn) { ... }

注意:在每个工厂方法中,第二个参数是扩展 Component 的对象,返回的始终是 UIComponent 的子类。第一个工厂方法(引发异常的那个)旨在成为“全部捕获”,如果没有为特定组件编写特定的工厂方法,则会调用该方法。

我正在尝试做的事情:应该调用正确的工厂方法,具体取决于组件方面的子组件类型。发生的事情是第一个工厂方法总是被调用(例如,抛出异常的那个)。这对我来说是违反直觉的,因为 C 的类型在运行时是已知的,而 C 是“扩展组件的某些特定类型”。

调试时,我在 处设置了一个断点Facet#getViewComponent,当我知道它facet.getChild()会返回一个 Row 类型的对象时调用它。所以在这个例子中,C 是 Row。令我惊讶的是,当调用工厂方法时,例如

PrimeFacesComponentFactory.create(facesContext, facet.getChild());

程序执行流向“catch all”工厂方法!但是,如果我显式转换 facet.getChild() 如下:

PrimeFacesComponentFactory.create(facesContext, (Row)facet.getChild());

然后调用特定的方法。很奇怪,因为我只是/冗余地将一行转换为一行。

我已经阅读了一些关于为什么会发生这种情况的信息,但它仍然让我感到模糊和违反直觉。无论如何,我该如何解决这个问题?

4

2 回答 2

3

重载决议在编译时发生一次,对于Facet类,而不是每个Cin Facet<C>,而不是在运行时。一个潜在的解决方案是让你的包罗万象的方法更智能:

public static UIComponent create(FacesContext fc, Component component) {
    if (component instanceof Row)
        return create(fc, (Row)component);
    else if (component instanceof Column)
        return create(fc, (Column)component);
    // include other types, and lastly
    else
        throw new UnsupportedOperationException("Method not yet implemented for class: " + component.getClass().getName());
}
于 2013-10-15T18:00:32.190 回答
0

带有以下声明

public C getChild() { return this.child; }

public UIComponent getViewComponent() {
    return PrimeFacesComponentFactory.create(facesContext, facet.getChild());
}

假设facet意味着this,在编译时,关于类型参数的唯一已知C就是它扩展了Component。因此编译器将此方法调用与声明为接受Component.

public static UIComponent create(FacesContext fc, Component component) {
    throw new UnsupportedOperationException("Method not yet implemented for class: " + component.getClass().getName());
}
于 2013-10-15T18:23:19.393 回答