2010-09-24 3 views
0

Рассмотрим следующую программу:Java Generic/Тип отправки Вопрос

import java.util.List; 
import java.util.ArrayList; 

public class TypeTest { 

    public static class TypeTestA extends TypeTest { 

    } 

    public static class TypeTestB extends TypeTest { 

    } 

    public static final class Printer { 
     public void print(TypeTest t) { 
      System.out.println("T"); 
     } 

     public void print(TypeTestA t) { 
      System.out.println("A"); 
     } 

     public void print(TypeTestB t) { 
      System.out.println("B"); 
     } 

     public <T extends TypeTest> void print(List<T> t) { 
      for (T tt : t) { 
       print(normalize(tt.getClass(), tt)); 
      } 
     } 

     private static <T> T normalize(Class<T> clz, Object o) { 
      return clz.cast(o); 
     } 

    } 
    public static void main(String[] args) { 
     Printer printer = new Printer(); 
     TypeTest t1 = new TypeTest(); 
     printer.print(t1); 
     TypeTestA t2 = new TypeTestA(); 
     printer.print(t2); 
     TypeTestB t3 = new TypeTestB(); 
     printer.print(t3); 
     System.out.println("...................."); 
     List<TypeTestB> tb1 = new ArrayList<TypeTestB>(); 
     tb1.add(t3); 
     printer.print(tb1); 
    } 
} 

Основной метод печатает:

T 
A 
B 
.................... 
T 

Что я должен сделать, чтобы напечатать следующее?

T 
A 
B 
.................... 
B 

Я хотел бы избежать написания цикла, такие как следующие для каждого типа, которые могут быть распечатаны:

public void printTypeTestB(List<TypeTestB> t) { 
     for (TypeTestB tt : t) { 
      print(tt); 
     } 
    } 

ответ

4

корень вашей проблемы в том, что перегружает метод Java разрешаются в время компиляции, основанное на объявленном типе выражений аргумента метода. Кажется, что ваша программа пытается использовать диспетчеризацию во время перегрузки методов. Это просто не работает на Java.

Тот факт, что вы используете дженерики в своем примере, - это немного красная селедка. У вас будет такая же проблема, если вы замените параметр типа <T> на TypeTest.

0

Кандидат на свернутый «шаблон посетителя».

или просто переместить печать() метод из Printer в TypeTest

2

рассмотривать создания интерфейса посетителя, который знает обо всех соответствующих подтипов.

public class TypeTestFoo { 

interface TypeTestVisitor { 
    void visit(TypeTestA t); 
    void visit(TypeTestB t); 
    void visit(TypeTest t); 
} 

interface TypeTest { 
    void accept(TypeTestVisitor visitor); 
} 

public static class TypeTestA implements TypeTest { 
    public void accept(TypeTestVisitor visitor) { 
     visitor.visit(this); 
    } 
} 

public static class TypeTestB implements TypeTest { 
    public void accept(TypeTestVisitor visitor) { 
     visitor.visit(this); 
    } 
} 

public static final class Printer implements TypeTestVisitor { 
    public void visit(TypeTestA t) { 
     System.out.println("A"); 
    } 

    public void visit(TypeTestB t) { 
     System.out.println("B"); 
    } 

    public void visit(TypeTest t) { 
     System.out.println("T"); 
    } 

} 
public static void main(String[] args) { 
    Printer printer = new Printer(); 
    TypeTest t1 = new TypeTest() { 
     public void accept(TypeTestVisitor visitor) { 
      visitor.visit(this); 
    }}; 
    t1.accept(printer);  
    TypeTestA t2 = new TypeTestA(); 
    t2.accept(printer); 
    TypeTestB t3 = new TypeTestB(); 
    t3.accept(printer); 
    System.out.println("...................."); 
    List<TypeTestB> tb1 = new ArrayList<TypeTestB>(); 
    tb1.add(t3); 
    for (TypeTestB each : tb1) { 
     each.accept(printer); 
    } 
} 

}

Это должно напечатать то, что вы хотели:

T 
A 
B 
.................... 
B 

Типы перечислены в интерфейсе, который позволяет перегружать во время компиляции. С другой стороны, это единственная точка, в которой вы поставили подтипы, для которых вы не хотите параметризовать поведение. Java не очень динамичный язык ... :)

Смежные вопросы