Java Generic / Тип Отправка Вопрос - PullRequest
0 голосов
/ 24 сентября 2010

Рассмотрим следующую программу:

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);
        }
    }

Ответы [ 3 ]

5 голосов
/ 24 сентября 2010

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

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

2 голосов
/ 29 сентября 2010

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

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

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

0 голосов
/ 24 сентября 2010

кандидат на извилистый "шаблон посетителя".

или просто переместите метод print () с Printer на TypeTest

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...