简体   繁体   English

方法重载无法正常使用Java泛型

[英]Method overloading not working as expected with Java generics

I have a generic class: 我有一个通用类:

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());
    }
}

I have a component factory that also has a bunch of methods, several of which look like this: 我有一个组件工厂,其中也有很多方法,其中一些看起来像这样:

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) { ... }

NOTE: in each of the factory methods the 2nd argument is an object that extends Component and what is returned is always a subclass of UIComponent. 注意:在每个工厂方法中,第二个参数是扩展Component的对象,返回的始终是UIComponent的子类。 The first factory method (the one that throws the exception) is intended to be a "catch all," which is invoked if there is no specific factory method written for a particular component. 第一个工厂方法(引发异常的方法)旨在成为“全部捕获”,如果没有为特定组件编写特定的工厂方法,则将调用该方法。

What I'm trying to do: the correct factory method should be invoked depending on what type of component facet's child is. 我正在尝试做的事情:应根据组件构面子代的类型来调用正确的工厂方法。 What's happening is that the first factory method is always invoked (eg the one that throws the exception). 发生的事情是总是调用第一个工厂方法(例如,引发异常的方法)。 This is counterintuitive to me, since the type of C is known at runtime and C is "some specific type that extends Component." 这与我的直觉相反,因为C的类型在运行时是已知的,并且C是“扩展Component的某些特定类型”。

Debugging, I set a breakpoint at Facet#getViewComponent , invoking it when I knew that facet.getChild() would return an object of type Row. 调试时,我在Facet#getViewComponent处设置了一个断点,当我知道facet.getChild()将返回Row类型的对象时调用该断点。 So in this example C was Row. 因此,在此示例中,C为行。 It surprised me to see that when the factory method was invoked eg 看到工厂方法被调用时,我感到很惊讶

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

program execution flowed to the "catch all" factory method! 程序执行流向“全部捕获”工厂方法! If, however, I explicitly cast facet.getChild() as follows: 但是,如果我显式地将facet.getChild()强制转换为以下形式:

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

then the specific method was invoked. 然后调用特定方法。 Weird, because I simply/redundantly cast a Row to a Row. 很奇怪,因为我简单地/冗余地将Row投射到Row。

I've read some about why this is happening , but it's still hazy and counterintuitive to my mind. 我已经读过一些关于为什么会发生这种情况的信息 ,但是对我来说,它仍然是朦胧的和违反直觉的。 At any rate, how can I resolve this problem? 无论如何,我该如何解决这个问题?

The overload resolution happens once, at compile-time, for the Facet class, not for each C in Facet<C> , and not at run time. 对于Facet类,重载解析仅在编译时发生一次,而不是Facet<C>每个C发生一次,而不是在运行时发生。 A potential solution is to make your catch-all method smarter: 潜在的解决方案是使您的通用方法更智能:

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());
}

With the following declaration 带有以下声明

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

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

assuming facet is meant to be this , at compile time, the only thing that is known about the type parameter C is that it extends Component . 假设facet就是this ,在编译时,关于类型参数C的唯一已知信息就是它扩展了Component So the compiler binds this method call with the method declared to accept a Component . 因此,编译器将此方法调用与声明为接受Component的方法绑定。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM