我有一个名为Element的基类。其他一些类(如Label和Image)都扩展了这个类。
我现在有一个调度类,它有以下方法:
public class Dispatcher {
public static AbstractPropertyEditor<Label> createEditor(Label e) {
...
}
public static AbstractPropertyEditor<Element> createEditor(Element e) {
...
}
}
如果现在我有一个Label实例(扩展了Element)并且我想将它传递给createEditor()
,为什么最通用的方法(第二个)被调用?调用大多数特定的方法(createEditor(Label e)
)会不正常?
我绝对需要使用Element-param的方法来“捕获”a)实现Element但在此调度类中没有自己的特定方法的所有类。
我正在使用Java 6,如何“修复”这个?
编辑:好的,我不得不承认它根本不是关于泛型的。但那是我第一次遇到它的地方。
感谢和问候
答案 0 :(得分:6)
你为什么不:
Element
抽象类,提供默认的createEditor()
实现Label
覆盖createEditor()
。因此,您将不需要静态实用程序,并将实现您的目标。
如果您需要Element
作为界面,那么:
createEditor()
定义为Element
EditorFactory
界面DefaultEditorFactory
和ListEditorFactory
在Element
:
public Editor createEditor() {
editorFactory.createEditor(this);
}
具体EditorFactory
在初始化期间或通过某种依赖注入实例化。
根据您的具体问题 - 这取决于您在那里编译的类型。如果您致电createEditor(obj)
,则取决于Element obj = ..
还是Label obj = ..
答案 1 :(得分:2)
这与泛型无关,而且与方法重载有关。在Java中,调用的方法签名是在编译时确定的,而不是在运行时确定的,因此您必须在运行时进行检查和转换。
所以替换这个:
Element label = getLabel();
AbstractPropertyEditor<?> editor = createEditor(label);
有了这个:
Element label = getLabel();
AbtractPropertyEditor<?> editor;
if(label instanceof Label) {
editor = createEditor((Label) label);
} else {
editor = createEditor(label);
}
另一种(更标准/更好)解决方法是让createEditor(Element)方法检查类型并使用强制转换方法调用子类型。但是,如果对声明的方法执行此操作,则返回参数会出现问题。
答案 2 :(得分:1)
来自Java Language Specification:
调用方法时(第15.12节), 实际参数的数量(以及任何 显式类型参数)和 参数的编译时类型 使用在编译时,到 确定方法的签名 将被调用(§15.12.2)。如果 要调用的方法是 实例方法,实际方法为 被调用将在运行时确定 时间,使用动态方法查找 (§15.12.4)。
答案 3 :(得分:0)
既然你可能在做:
Element element = new Label();
由编译器决定。
答案 4 :(得分:0)
这是重载方法的一个示例。 尽管运行时的实际对象是Label而不是Element,但是 选择哪个重载方法调用(换句话说,签名的 方法)不是在运行时动态决定的。引用类型(不是对象类型)确定调用哪个重载方法!
实施例
public class Car {
}
public class Toyota extends Car {
}
public class MyCar {
public void run(Car c) {
System.out.println("Run any Car");
}
public void run(Toyota t) {
System.out.println("Run Toyota Car");
}
public static void main(String[] args) {
MyCar myCar = new MyCar();
Car c1 = new Car();
myCar.run(c1); // Output: Run any Car
Toyota c2 = new Toyota();
myCar.run(c2); // Output: Run Toyota Car
Car c3 = new Toyota();
myCar.run(c3); // Output: Run any Car
}
}
所以,在你的情况下
Element obj1 = new Label();
Dispatcher.createEditor(obj); // Method with Element argument is called
// as you are passing Element
Label obj2 = new Label();
Dispatcher.createEditor(obj); // Method with Label argument is called
// as you are passing Label
另一方面,重写的方法调用在运行时发生,它取决于对象类型(换句话说,堆上实际实例的类型)