【问题标题】:Override ArrayList and cast one to that class覆盖 ArrayList 并将一个强制转换为该类
【发布时间】:2011-10-30 10:32:12
【问题描述】:

我有一个 ArrayList 作为对象(来自反射),并创建了我自己的类,该类从它扩展而来(ArrayListMonitor),每次数组列表删除/添加项目时都会调用一个函数。但后来我明白了:java.util.ArrayList cannot be cast to ArrayListMonitor 我需要监控 arraylist,因为我正在加载一个 jar 并从中创建一个服务器,它有一个我需要监控的 clients 字段。

【问题讨论】:

    标签: java arraylist extends


    【解决方案1】:

    没错,您不能只将任何 ArrayList 转换为您的 ArrayList 子类。

    打个比方:

    每只大象都是哺乳动物,但并非每只哺乳动物都是大象。
    每个 ArrayListMonitor 都是一个 ArrayList,但不是每个 ArrayList 都是一个 ArrayListMonitor。

    有关详细信息,请参阅 Java 教程的 Inheritance 部分。


    关于你的评论,看看这个场景:

    OutputStream os1 = new FileOutputStream("foo.txt");
    OutputStream os2 = new DataOutputStream(os1);
    DataOutputStream dos2 = (DataOutputStream) os2; // works
    DataOutputStream dos1 = (DataOutputStream) os1; // will throw ClassCastException
    

    【讨论】:

    • 我知道,但是这样看。 DataOutputStream 扩展了 OutputStream,并且可以将输出流转换为 DOS (afaik)
    • @Someguynamedpie 这正是我要说的。不,除非它实际上是作为 DataOutputStream 创建的,否则它不能。我将为此添加一个示例
    • @Someguynamedpie 不,您不能将任意OutputStream 转换为DataOutputStream。这正是 Sean 所解释的......铸造不会进行任何魔法转换。它只是告诉编译器“我知道这个对象确实是DataOutputStream,所以让我这样对待它”。它不会神奇地将任意操作系统转换为 DOS。
    【解决方案2】:

    您尝试转换的对象,它的实际类型是什么?

     ArrayList anArrayList = new ArrayList();
    

     ArrayList aMonitorList = new ArrayListMonitor();
    

    您将无法将任何类似于 anArrayList 的内容投射到您的监视器列表中。您不能像这样向其他人的对象添加功能。您需要它们来使用您的特殊数组类。除非您尝试检测的代码有某种机制可以让您说“使用我的类”,否则这种方法将不起作用。

    为了能够监控预先存在的编译对象,在技术上可以操作编译的字节码,但这是一项相当复杂的技术。

    【讨论】:

    • public class ArrayListMonitor<E> extends ArrayList<E> { 是我想说的
    【解决方案3】:

    如果ArrayList 不是实例ArrayListMonitor,这将无法工作:

    ArrayList<String> a = new ArrayList<String>();
    ArrayListMonitor<String> am = (ArrayListMonitor<String>) a; // must throw ClassCastException
    

    如果您想监控阵列列表,您有多种选择:

    1. 编写像new ArrayListMonitor(a); 这样的委托,并为ArrayList 中的所有相关方法创建委托
    2. 使用 dynamic proxy 监控 ArrayList 的行为
    3. 使用 AOP 等其他技术

    【讨论】:

    • @Someguynamedpie:对不起,你说的“绕道”是什么意思?
    • Detouring a function的意义——将一个函数的调用重定向到另一个函数。
    • 好的,知道了。是的,代理intercepts 调用某些方法,您可以决定是否要传递到您的“真实”列表。您可以执行日志记录、升级等操作。拦截器相当动态且复杂,因此委托是更好的选择。
    • 我对 Java 的喜爱多了 2000%。非常感谢你告诉我关于代理的事情,我要暂停这个项目,现在用代理玩得开心。它还解决了我在使用沙盒代码时遇到的问题。
    • 如果 ArrayList 对象源自某些库代码并在那里传递,是否可以使用动态代理?我们是否必须控制对象生命周期的创建才能使用 DynamicProxies?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-11-04
    • 2014-01-25
    • 1970-01-01
    • 2016-02-02
    • 1970-01-01
    • 2020-03-02
    相关资源
    最近更新 更多