2010-01-10 6 views
1

Рассмотрим следующий код:Java полиморфизм

public abstract class Base { 
     public void getAnswer(); 
} 

public class Derived1 extends Base { 
     public void getAnswer() { 
     } 
} 

public class Derived2 extends Base { 
     public void getAnswer() { 
     } 
} 


public class Main { 

    public final int DERIVED1 = 1; 
    public final int DERIVED2 = 2; 

    public Base b; 

    public static void Main() { 

     int which_obj = which(); 

     switch (which_obj) { 
     case DERIVED1: Derived1 derived1 = new Derived1(); 
        // construct object 
        b = derived1; 
        break; 
     case DERIVED2: Derived1 derived1 = new Derived1(); 
        // construct object 
        b = derived2; 
        break; 
     } 

     b.getAnswer(); 
    } 
} 

здесь мы используем случай переключатель, чтобы решить, какой объект на строительство и, соответственно, мы строим его и присвоить ему б так, чтобы использовать полиморфизм.

Какое преимущество дает нам полиморфизм?

Теперь есть способ, с помощью которого мы можем избежать случая переключения. say: есть отображение из int в String, которое возвращает «Derived1» или «Derived2». , если строка содержит имя класса. теперь я могу построить объект, заданный Строкой, содержащей имя класса. что-то вроде:

Base b = construct_obj(str); 

библиотека вызов construct_obj автоматически находит класс OBJ из байткодов и возвращает ссылку на объект. то я могу избежать случая переключения. обычно я бы имел 100 классов Derived.

+2

вы имели в виду «случай DERIVED2: Derived2 derived2 = новый Derived2() ;» ? В противном случае нет такой вещи, которая была бы присвоена b. – Edmund

ответ

5

Ну, вы можете создать Map<Integer, Class<? extends Base>>, а затем использовать Class.newInstance, чтобы создать экземпляр с отражением. Он также не будет работать, и есть различные ошибки, которые не будут отображаться до времени выполнения, но это сработает.

Вот пример кода.

import java.util.*; 

abstract class Base {} 
class Derived1 extends Base {} 
class Derived2 extends Base {} 

public class Test 
{ 
    public static void main(String[] args) 
    { 
     Map<Integer, Class<? extends Base>> map = 
      new HashMap<Integer, Class<? extends Base>>(); 

     map.put(1, Derived1.class); 
     map.put(2, Derived2.class); 

     int which = 2; // For example 

     Class<? extends Base> clazz = map.get(which); 
     if (clazz == null) 
     { 
      // Invalid choice. Do whatever. 
     } 
     else 
     { 
      try 
      { 
       Base base = clazz.newInstance(); 
       // Use base 
      } 
      catch (InstantiationException e) 
      { 
       // Handle exception or whatever 
      } 
      catch (IllegalAccessException e) 
      { 
       // Handle exception or whatever 
      }    
     } 
    } 
} 

Обратите внимание, что если у вас есть непрерывный диапазон целых чисел, вы можете использовать массив вместо карты.

Другой альтернативой является использование заводских экземпляров, а не использование конструкторов - это было бы «более безопасно» (с точки зрения ошибок при отсрочке), но, вероятно, значительно больше кода. (В C# было бы легко с помощью лямбда-выражения, Java 7 может это предпочтительное решение сделать тоже.)

+0

Это полностью верный ответ и все, но я просто должен сказать, что каждый раз, когда я вижу Java, который не отформатирован правилами JCC, это заставляет меня съеживаться. Вы знаете, одна из этих мелочей ничего важна. – Esko

+1

@ Esko: Включая 8-изначный отступ? Ик. Лично я не думаю, что Sun должна была включать форматирование в соглашениях - именование имеет большой смысл, поскольку это выходит в API, но я думаю, что для разных компаний имеет смысл выбирать свой предпочтительный макет, тем более, что это такой «религиозный» аргумент. На работе мы используем соглашения Sun, и я привык к ним, но по большому счету я по-прежнему предпочитаю стиль «скобки в своей собственной линии». –

+0

Обязательный юмор: некоторые разработчики утверждают [против этого]. Автор этого FAQ не видит явного преимущества для принятия этого подхода и полагает, что упомянутые разработчики также помещают свои фигурные скобки в неправильную линию. :-) http://junit.sourceforge.net/doc/faq/faq.htm#organize_1 – trashgod

1

Вы можете позвонить Class.newInstance

Class cl = Class.forName("com.stackoverflow.Derived1"); 
Base b = cl.newInstance(); 
Смежные вопросы