Java中的“动态”转换

时间:2008-12-30 20:31:40

标签: java inheritance casting

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(),但并不热衷于添加额外的样板代码。

7 个答案:

答案 0 :(得分:9)

就像试图这样做:

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

这样您就不必覆盖每个子类中的“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 );
    }
}

答案 1 :(得分:6)

演员有效地试图这样做:

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

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

答案 2 :(得分:4)

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

答案 3 :(得分:2)

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

  

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

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

答案 4 :(得分: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方式执行的操作。

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

答案 5 :(得分: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区。]

答案 6 :(得分:0)

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