Приоритет перегруженных методов - PullRequest
5 голосов
/ 15 февраля 2010

У меня есть базовый класс, который называется Элемент. Некоторые другие классы (например, 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 для того, чтобы «перехватить» все те классы, которые а) реализуют Element, но не имеют своего собственного конкретного метода в этом классе диспетчеризации.

Я использую Java 6, как это исправить?

Редактировать: Хорошо, я должен признать, что это вовсе не дженерики. Но вот где я столкнулся с этим в первый раз.

спасибо и всего наилучшего

Ответы [ 5 ]

6 голосов
/ 15 февраля 2010

Почему бы вам не:

  • make Element абстрактный класс, обеспечивающий реализацию по умолчанию createEditor()
  • сделать Label переопределить createEditor().

Таким образом, вам не понадобятся статические утилиты, и вы достигнете своей цели.

Если вам нужен Element, чтобы быть интерфейсом, то:

  • определить createEditor() как методы Element
  • определить EditorFactory интерфейс
  • укажите DefaultEditorFactory и ListEditorFactory
  • используйте соответствующие фабрики в реализациях Element:

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

, где конкретный EditorFactory создается либо во время инициализации, либо посредством какого-либо внедрения зависимости.


По вашему конкретному вопросу - это зависит от того, какой тип вы там скомпилировали. Если вы позвоните createEditor(obj), это будет зависеть от того, Element obj = .. или Label obj = ..

2 голосов
/ 15 февраля 2010

Это действительно не имеет ничего общего с обобщениями, и все, что связано с перегрузкой методов. В 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) проверял тип и вызывал с приведением правильный перегруженный метод для подтипов. Однако у вас будет проблема с вашими возвращаемыми параметрами, если вы сделаете это с методами, как объявлено.

1 голос
/ 15 февраля 2010

Из спецификации языка Java :

Когда метод вызывается (§15.12), количество фактических аргументов (и любой явные аргументы типа) и типы времени компиляции аргументов во время компиляции , для определить сигнатуру метода это будет вызвано (§15.12.2). Если метод, который должен быть вызван, является экземпляр метод, фактический метод для будет вызван будет при запуске время , с использованием динамического поиска метода (§15.12.4).

0 голосов
/ 11 января 2011

Это пример перегруженных методов. Несмотря на то, что фактический объект во время выполнения является меткой, а не элементом, выбор, какой перегруженный метод вызывать (другими словами, подпись метод) НЕ определяется динамически во время выполнения. Тип ссылки (не тип объекта) определяет, какой перегруженный метод вызывается!

Пример

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

С другой стороны, переопределенный вызов метода происходит во время выполнения и зависит от типа объекта (другими словами, типа фактического экземпляра в куче)

0 голосов
/ 15 февраля 2010

Так как вы, вероятно, делаете:

Element element = new Label();

Определяется компилятором.

...