Hullo all,

想知道是否有任何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(),但是并不热衷于添加额外的样板代码。

有帮助吗?

解决方案

(无法在评论中添加代码,因此我将在此处添加)

关于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区。]

其他提示

就像试图这样做:

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

然后尝试:

  String s = ( String ) copy();

您的 Parent 类和 ChildN 类与 Object String

具有相同的关系

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

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

即,覆盖“复制”。方法并返回正确的实例。


修改

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

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

这样你就不必覆盖“复制”了。每个子类中的方法。这是Prototype设计模式。

但是,使用此实现,您应该知道两个已检查的异常。这是完整的程序,可以毫无问题地编译和运行。

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 );
    }
}

演员有效地试图这样做:

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

(它正在计算执行时执行的转换,但这就是它将会是什么,因为 orig.getClass()将是 ChildN.class )但是,< code> orig.copy()不返回ChildN的实例,只返回 Parent 的实例,因此无法转换为 ChildN

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

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

  

确定指定的Object是否为   赋值与对象兼容   由本课程代表。这种方法   是Java的动态等价物   语言instanceof运算符...   具体来说,如果这样    Class 对象代表一个   声明类,此方法返回   如果指定 true    Object 参数是一个   代表类的实例(或   任何子类);它返回    false 否则。

由于Parent不是子类的子类,因此isInstance()返回false,因此cast()会抛出异常。这可能违反了最不惊讶的原则,但它按照记录的方式工作 - cast()只能翻转,而不是垂头丧气。

可能只是想要对象的复制/克隆。

在这种情况下,实现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方式做。

(是的,你也可以做一些花哨的内省游戏,但是只要你没有公共默认构造函数,这些方法就会失败或变得丑陋。无论你使用什么构造函数,克隆都可以工作。)

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

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top