5

我有一个名为 Element 的基类。其他一些类(如标签和图像)都扩展了这个类。

我现在有一个具有以下方法的调度类:

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,如何“解决”这个问题?

编辑:好的,我不得不承认这与泛型无关。但那是我第一次遇到它的地方。

谢谢并恭祝安康

4

5 回答 5

6

你为什么不:

  • 制作Element提供默认createEditor()实现的抽象类
  • 使Label覆盖createEditor().

因此,您将不需要静态实用程序并将实现您的目标。

如果你需要Element一个接口,那么:

  • 定义createEditor()为方法Element
  • 定义一个EditorFactory接口
  • 提供DefaultEditorFactoryListEditorFactory
  • 在以下实现者中使用适当的工厂Element

    public Editor createEditor() {
         editorFactory.createEditor(this);
    }
    

EditorFactory在初始化期间或通过某种依赖注入来实例化具体的地方。


根据您的具体问题 - 这取决于您在那里编译的类型。如果你打电话createEditor(obj)将取决于它Element obj = ..Label obj = ..

于 2010-02-14T21:14:53.090 回答
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) 方法检查类型并使用强制转换调用子类型的正确重载方法。但是,如果您对声明的方法执行此操作,则返回参数会出现问题。

于 2010-02-14T21:08:37.917 回答
1

来自Java 语言规范

调用方法时(第 15.12 节),在编译时使用实际参数(和任何显式类型参数)的数量和参数的编译时类型确定将被调用的方法的签名( §15.12.2)。如果要调用的方法是 实例方法,则要调用的实际方法将在运行时使用动态方法查找(第 15.12.4 节)确定。

于 2010-02-14T21:26:59.817 回答
0

这是重载方法的一个示例。即使运行时的实际对象是标签而不是元素,选择调用哪个重载方法(换句话说,方法的签名)并不是在运行时动态决定的。引用类型(不是对象类型)决定调用哪个重载方法!

例子

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

另一方面,被覆盖的方法调用发生在运行时,它取决于对象类型(换句话说,堆上实际实例的类型)

于 2011-01-10T22:08:23.727 回答
0

因为你可能在做:

Element element = new Label();

它由编译器决定。

于 2010-02-14T21:07:41.240 回答