java:“向下转换”到新对象/切片的对面

时间:2011-03-23 22:57:04

标签: java downcast

抱歉,我真的不知道如何为这个问题制作标题;也许有一个名字,我试图做什么,我不知道,但我可以用一些代码来解释:

猜猜你有一个类,遗憾的是它既没有复制构造函数也没有公共静态复制方法。

class A
{
    private int i;  // <- private, cant access
    String x;       // <- even worse: cant access unless in same pkg!
    /* … other stuff, ctor, etc. … */
    public A clone()
    {
        A a = new A();
        a.i = i;
        a.x = x;
        return x;
    }
}

进一步猜测,有一些函数可以返回该类的对象:

public static A someFn(x,y,z);

现在问题:我想从该类派生来添加一些功能。不幸的是,我既没有java中的sizeof也没有cc或静态复制方法。

所以当我做一个

class B extends A
{
    protected w;
    public B clone()
    {
       /* as usual */
    }
}

然后我可以克隆我的B并获得一个新的,但是我怎样才能将返回的A从someFn()转换为B.反正是否要在java中切片相反?如果我克隆它,它仍然是A,我不能逐字段复制它。这在c ++中很简单,但是如何用Java做到这一点?

4 个答案:

答案 0 :(得分:3)

更改A和B的设计,以便能够将A转换为B(如果它甚至有意义:你如何将狗变成达尔马提亚狗?),或者使用组合而不是继承:

public class B {
    private A a;
    private int w;

    public B(A a, int w) {
        this.a = a;
        this.w = w;
    }

    public int foo() {
        return a.foo();
    }

    // ...
}

答案 1 :(得分:1)

在java中,没有使用运算符clone()实现new。我希望你能控制原始的Java类 - 它不遵循最佳实践。

你调用super.clone()而不是神奇地返回一个正确类型的对象,并将先前克隆方法的结果应用于它。

请参阅How to properly override clone method

答案 2 :(得分:1)

首先,你的克隆方法是错误的。它应该是这样的:

public A clone(){
    A result = (A)super.clone();
    result.i = i;
    result.x = x;
    return result;
}

B的克隆:

public B clone(){
    B result = (B)super.clone():
    result.w = w;
    return result;
}

你可以在B中有一个构造函数,它接受一个A的实例,从它的A实例中提取它所需的数据,并用它创建B对象。

然后,您可以调用someFn(x,y,z),如:

B b = new B(someFn(x, y, z))

另外如果someFn不是静态的,你可以为定义它的类编写一个子类,并覆盖someFn改变它的返回类型(这个特性叫做covariant return type):

B someFn(x, y, z){
   ...
}

答案 3 :(得分:0)

不幸的是,剩下的唯一方法是使用完整的包装器来模仿我需要的功能,并在性能上花费一些开销。

完全愚蠢的是,没有办法为克隆提供一个克隆的类......