“动态”铸造

问题描述:

喂所有,“动态”铸造

想知道是否有任何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 =

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

+0

你可以做到这一点。看看我的编辑。我虽然在第一时间理解“铸造”有困难。 – OscarRyz 2008-12-30 22:06:31

(无法在评论中添加代码,所以我要在此添加)

关于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块

]

演员被有效试图做到这一点:

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

(它的工作了剧组在执行时进行,但是这将是什么,因为orig.getClass()ChildN.class)但是,orig.copy()不返回一个ChildN的实例,它返回的只是Parent的一个实例,所以它不能被转换为ChildN

如果ChildN没有覆盖副本()返回ChildN的实例,那么你想垂头丧气型亲本的目的是键入ChildN

就像是试图做到这一点:

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

然后尝试:

String s = (String) copy(); 

家长类和ChildN级有作为对象字符串的关系一样

为了使它工作,你需要做到以下几点:

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

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


编辑

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

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

这样你就不必在每个子类中重写“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); 
    } 
} 
+0

以身作则!这个答案对我来说很清楚。现在可以声明Child.copy来返回一个ChildN iso一个Parent吗? (我知道它可以在C++中) – xtofl 2008-12-30 21:00:25

+0

不在Java中。至少不在Java源代码中。若要将问题稍微混淆,可以在Java字节码中允许* – 2008-12-30 21:18:21

+1

Java 5+中的源代码允许使用它。 – 2008-12-30 21:35:30

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

确定指定对象是与该Class表示的对象 赋值兼容。此方法 是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方式执行的操作。

(是的,你可以做花哨的反省游戏太多,但这些方法失败或很快变得丑陋,你没有一个公共默认构造函数。克隆可以在任何情况下,无论是什么构造你。)

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