【问题标题】:Java dynamic downcasting from generic list通用列表中的 Java 动态向下转换
【发布时间】:2014-02-23 14:38:55
【问题描述】:

如何使用 out 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();
    }
}

【问题讨论】:

  • 考虑使用访问者模式。
  • 更详细地描述您真正想要实现的目标。在大多数情况下,使用instanceof 至少是可疑的。
  • 发布的回复是否回答了您的问题?

标签: java generics rtti instanceof downcast


【解决方案1】:

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

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

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

【讨论】:

  • 我只想将实现与类分开。现在,我正在阅读 Head first design patterns。
  • Head First Design Patterns 是一个很好的起点。祝你好运。
【解决方案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();
}

如果baseA 的实例,这将导致调用A::test,如果baseB 的实例,则调用B::test 等等。(方法是根据运行时类型选择的引用的对象)。

【讨论】:

    猜你喜欢
    • 2017-08-14
    • 2013-12-31
    • 1970-01-01
    • 1970-01-01
    • 2010-10-18
    • 1970-01-01
    • 2017-03-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多