从通用列表中进行Java动态下转换

时间:2014-02-23 14:38:56

标签: java generics rtti instanceof downcast

如何使用instanceof语句动态转发对象? 我在阅读Bruce Eckel的Thinking in Java,并且使用了Class,并且有这样一个主题,但我没有接近 附:抱歉我的英文。

public class GenericTest {


    static private interface Base {
    }


    static private class A implements Base {
    }

    static private class B implements Base {
    }

    static private class C extends B {
    }

    private List<Class<? extends Base>> types;
    private List<Base> objects;

    public GenericTest() {
        types = new ArrayList<Class<? extends Base>>();
        types.add(A.class);
        types.add(B.class);
        types.add(C.class);

        objects = new ArrayList<Base>(Arrays.asList(new A(), new B(), new C()));

        for (Base base : objects) {
            if (base instanceof A)
                test((A) base);
            else if (base instanceof C)
                test((C) base);
            else if (base instanceof B)
                test((B) base);

            for (Class<? extends Base> c : types)
                if (base.getClass().equals(c))
                    test(c.cast(base));
        }
    }

    private void test(A a) {
        System.out.println("A");
    }

    private void test(B b) {
        System.out.println("B");
    }

    private void test(C c) {
        System.out.println("C");
    }

    private void test(Base base) {
        System.out.println("Base");
    }

    public static void main(String[] args) {
        new GenericTest();
    }
}

2 个答案:

答案 0 :(得分:3)

有时,使用instanceof表示您的设计存在缺陷,可能违反了面向对象编程的一些基本原则。

在你的情况下,我可以监督两个解决方案,具体取决于你的最终目标。第一个是将test()的特定行为封装在类ABC中。可以通过在接口test()中声明方法Base,使其成为抽象类并在子类中实现它来完成。

static private abstract class Base {
    public void test() {
        System.out.println("Base");
    } 
}

static private class A extends Base {
    private void test() {
        System.out.println("A");
    }
}

static private class B implements Base {
    private void test() {
        System.out.println("B");
    }
}

static private class C extends B {
    private void test() {
        System.out.println("C");
    }
}

请注意,层次结构级别大于3的类不是一个好习惯。继承是两个对象之间可以获得的最高耦合度。这就是为什么我们倾向于prefer composition over inheritance

正如@SLaks所提到的,改进设计的第二种方法是使用访客模式。可以找到有关此模式的更多信息here。有关该主题的推荐阅读材料为GOFRefactoring to Patterns

答案 1 :(得分:2)

目前还不清楚你想做什么,但这里是你如何在没有施放和instanceof的情况下获得相同的结果。

test方法放在接口Base上:

static private interface Base {
    public void test();
}

然后实施它:

static private class A implements Base {
    public void test() {
        System.out.println("A");

}

,同样适用于BC。 然后你的循环应该是这样的:

for (Base base : objects) {
    base.test();
}

如果A::testbase的实例,则会A调用B::test,如果baseB的实例,则会调用{{1}}。 (根据引用对象的运行时类型选择方法。)