如何使用泛型调用最具体的方法?

时间:2015-04-22 11:07:53

标签: java type-erasure generics

有以下例子:

public class Test {

    public static class A {}

    public static void main(String[] args) {
        A a = new A();
        m1(a);
    }

    public static <T> void m1(T t) {
        // t.getClass().getSimpleName() is A
        // t instanceof A is true
        m2(t);
    }

    /* Not called */
    public static void m2(A a) {
        System.out.println("A");
    }

    public static void m2(Object o) {
        // o.getClass().getSimpleName() is A
        // o instanceof A is true
        System.out.println("O");
    }

}

我不明白为什么选择m2(Object o)代替m2(A a)。如您所见,在调用m2(t)时,t&#34;是A&#34;。

输出

  • 实际

    O
    
  • 预期

    A
    

如何在上述情况下使用泛型,以便选择m2(A a)

修改

即使我添加了B类型(类似于A),我也希望有一个通用的解决方案。

...
public static void main(String[] args) {
    A a = new A();
    m1(a);
    B b = new B();
    m1(b);
}
...
public static void m2(B b) {
    System.out.println("B");
}
...

输出

  • 实际

    O
    O
    
  • 预期

    A
    B
    

1 个答案:

答案 0 :(得分:3)

您正在寻找Java不支持的double dispatch。我不认为泛型可以在这里提供帮助,但是visitor design pattern可以用来模仿它:

public class Test {
    public static interface Visitable {
        void accept(Visitor visitor);
    }

    public static class A implements Visitable {
        @Override
        public void accept(Visitor visitor) {
            visitor.visit(this);
        }
    }

    public static class B implements Visitable {
        @Override
        public void accept(Visitor visitor) {
            visitor.visit(this);
        }
    }

    public static interface Visitor {
        void visit(A a);

        void visit(B b);
    }

    public static class PrintingVisitor implements Visitor {
        @Override
        public void visit(A a) {
            System.out.println("A");
        }

        @Override
        public void visit(B b) {
            System.out.println("B");
        }
    }

    public static void main(String[] args) {
        Visitable visitable = new A();
        m(visitable);
        visitable = new B();
        m(visitable);
    }

    public static void m(Visitable visitable) {
        visitable.accept(new PrintingVisitor());
    }
}