5

大家好,

想知道是否有任何 Java 黑客可以告诉我为什么以下方法不起作用:

public class Parent {
    public Parent copy() {
       Parent aCopy = new Parent();
       ...
       return aCopy;
    }
}

public class ChildN extends Parent {
    ...
}

public class Driver {
     public static void main(String[] args) {
         ChildN orig = new ChildN();
         ...
         ChildN copy = orig.getClass().cast(orig.copy());
     }
}

代码很高兴编译,但决定在运行时抛出 ClassCastException D=

编辑:哇,真的很快回复。多谢你们!所以看来我不能使用这种方法进行向下转换......还有其他方法可以在 Java 中进行向下转换吗?我确实考虑过让每个ChildN类都覆盖copy(),但并不热衷于添加额外的样板代码。

4

7 回答 7

9

就像尝试这样做:

  public Object copy(){
       return new Object();
  }

然后尝试:

  String s = ( String ) copy();

您的Parent类和ChildN类与ObjectString具有相同的关系

要使其工作,您需要执行以下操作:

public class ChildN extends Parent {
    public Parent copy() {
        return new ChildN();
    }
}

也就是说,重写“复制”方法并返回正确的实例。


编辑

根据您的编辑。这实际上是可能的。这可能是一种可能的方式:

public class Parent {
    public Parent copy() {
        Parent copy = this.getClass().newInstance();
        //...
        return copy;
    }
}

这样您就不必在每个子类中重写“复制”方法。这就是原型设计模式。

然而,使用这个实现你应该知道两个检查异常。这是编译和运行没有问题的完整程序。

public class Parent {
    public Parent copy()  throws InstantiationException, IllegalAccessException  {
       Parent copy = this.getClass().newInstance();
       //...
       return copy;
    }
}
class ChildN  extends Parent {}

class Driver {
     public static void main(String[] args) throws  InstantiationException ,  IllegalAccessException  {
         ChildN orig = new ChildN();
         ChildN copy = orig.getClass().cast(orig.copy());
         System.out.println( "Greetings from : " + copy );
    }
}
于 2008-12-30T20:39:06.663 回答
6

演员们正在有效地尝试这样做:

ChildN copy = (ChildN) orig.copy();

(它正在计算要在执行时执行的强制转换,但这就是它将是因为orig.getClass()will be ChildN.class)但是,orig.copy()它不返回 ChildN 的实例,它返回 just 的实例Parent,因此不能强制转换为ChildN.

于 2008-12-30T20:34:22.600 回答
4

如果 ChildN 没有覆盖 copy() 以返回 ChildN 的实例,那么您正在尝试将 parent 类型的对象向下转换为 ChildN 类型

于 2008-12-30T20:35:04.657 回答
2

如果 Class#isInstance() 返回 false,java.lang.Class#cast(Object) 会抛出 ClassCastException。从该方法的javadoc:

确定指定的 Object 是否与该 Class 表示的对象赋值兼容。这个方法是 Java 语言 instanceof 操作符的动态等价物... 具体来说,如果这个 对象表示一个声明的类,那么如果指定的 参数是表示的类(或其任何子类)的实例,则Class该方法返回 ;否则它会返回 。trueObjectfalse

由于 Parent 不是 child 的子类,因此 isInstance() 返回 false 所以 cast() 抛出异常。这可能违反了最小惊讶的原则,但它的工作方式与记录的方式相同 - cast() 只能向上转换,不能向下转换。

于 2008-12-30T20:42:50.710 回答
2

难道你只是想要你的对象的副本/克隆。

在这种情况下,实现 Cloneable 接口并根据需要覆盖 clone()。

public class Parent implement Cloneable {
   public Object clone() throws CloneNotSupportedException {
     Parent aCopy = (Parent) super.clone();
   ...
   return aCopy;
   }
}

public class ChildN extends Parent {
    ...
}

public class Driver {
     public static void main(String[] args) {
         ChildN orig = new ChildN();
         ...
         ChildN copy = orig.getClass().cast(orig.clone());
     }
}

这正是您的“copy()”方法试图以 Java 方式执行的操作。

(是的,你也可以做花哨的内省游戏,但是一旦你没有公共的默认构造函数,这些方法就会失败或变得丑陋。无论你有什么构造函数,克隆在任何情况下都有效。)

于 2008-12-31T01:15:38.053 回答
1

(无法在评论中添加代码,所以我会在这里添加)

关于 Cloneable:如果您正在实施 Cloneable,请按如下方式实施;打电话更干净...

public class Foo implements Cloneable {
    public Foo clone() {
        try {
            return (Foo) super.clone();
        } catch (CloneNotSupportedException e) {
            return null; // can never happen!
    }
}

[编辑:我也看到其他人使用

throw new AssertionError("This should never happen! I'm Cloneable!");

在 catch 块中。]

于 2008-12-31T21:08:18.520 回答
0

向下转换不起作用的原因是,当您将父对象转换为子类型时,您无法在父对象上调用子类型的方法。但它以另一种方式工作......

于 2009-01-04T17:41:16.243 回答