Java 爪哇; 将基类转换为派生类

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2572348/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 09:22:04  来源:igfitidea点击:

Java; casting base class to derived class

javacastingclass

提问by Cam

Why can't I cast a base class instance to a derived class?

为什么我不能将基类实例转换为派生类?

For example, if I have a class B which extends a class C, why can't I do this?

例如,如果我有一个 B 类扩展了一个 C 类,为什么我不能这样做?

B b=(B)(new C());

or this?

或这个?

C c=new C();
B b=(B)c;


Alright let me be more specific as to what I'm trying to do. Here's what I have:

好吧,让我更具体地说明我要做什么。这是我所拥有的:

public class Base(){
    protected BaseNode n;
    public void foo(BaseNode x){
        n.foo(x);
    }
}


public class BaseNode(){
    public void foo(BaseNode x){...}
}

Now I want to create a new set of classes which extend Base and Basenode, like this:

现在我想创建一组扩展 Base 和 Basenode 的新类,如下所示:

public class Derived extends Base(){
    public void bar(DerivedNode x){
        n.bar(x);//problem is here - n doesn't have bar
    }
}

public class DerivedNode extends BaseNode(){
    public void bar(BaseNode){
        ...
    }
}

So essentially I want to add new functionality to Base and BaseNode by extending them both, and adding a function to both of them. Furthermore, Base and BaseNode should be able to be used on their own.

所以本质上,我想通过扩展 Base 和 BaseNode 来为它们添加新功能,并为它们添加一个函数。此外,Base 和 BaseNode 应该能够单独使用。

I'd really like to do this without generics if possible.

如果可能的话,我真的很想在没有泛型的情况下做到这一点。



Alright so I ended up figuring it out, partly thanks to Maruice Perry's answer.

好吧,所以我最终弄清楚了,部分归功于 Maruice Perry 的回答。

In my constructor for Base, nis instantiated as a BaseNode. All I had to do was re-instantiate nas a DerivedNodein my derived class in the constructor, and it works perfectly.

在我的构造函数中,Base,n被实例化为BaseNode. 我所要做的就是在构造函数的派生类中重新实例n化为 a DerivedNode,并且它完美地工作。

采纳答案by Babar

You need to use the instanceofkeyword to check the type of object referenced by nand typecast the object and call the bar()method. Checkout Derived.bar()method bellow

您需要使用instanceof关键字来检查n引用的对象类型并对该对象进行类型转换并调用bar()方法。Checkout Derived.bar()方法如下

public class Test{
    public static void main(String[] args){
        DerivedNode dn = new DerivedNode();
        Derived d = new Derived(dn);
        d.bar( dn );
    }
}

class Base{
    protected BaseNode n;
    public Base(BaseNode _n){
        this.n = _n;
    }

    public void foo(BaseNode x){
        n.foo(x);
    }
}


class BaseNode{
    public void foo(BaseNode x){
        System.out.println( "BaseNode foo" );
    }
}

class Derived extends Base{
    public Derived(BaseNode n){
        super(n);
    }

    public void bar(DerivedNode x){
        if( n instanceof DerivedNode ){
            // Type cast to DerivedNode to access bar
            ((DerivedNode)n).bar(x);
        }
        else {
            // Throw exception or what ever
            throw new RuntimeException("Invalid Object Type");
        }
    }
}

class DerivedNode extends BaseNode{
    public void bar(BaseNode b){
        System.out.println( "DerivedNode bar" );
    }
}

回答by Omry Yadan

because if B extends C, it means B is a C and not C is a B.

因为如果 B 扩展了 C,则意味着 B 是 C 而不是 C 是 B。

rethink what you are trying to do.

重新考虑你正在尝试做什么。

回答by brabster

You can't do that because C does not necessarily implement the behaviours you created when you extended it in B.

你不能这样做,因为 C 不一定实现你在 B 中扩展它时创建的行为。

So, say C has a method foo(). Then you know that you can call foo()on a B, as B extends C, so you can cast accordingly a treat a B as if it was a C with (C)(new B()).

所以,说 C 有一个方法foo()。然后您知道您可以调用foo()B,因为 B 扩展了 C,因此您可以相应地将 B 视为 C 与(C)(new B()).

However - if B has a method bar(), nothing in the subclass relationship says that you can call bar()on C too. Thus you cannot treat a C as if it were a B, and so you cannot cast.

但是 - 如果 B 有一个 method bar(),则子类关系中没有任何内容表明您也可以调用bar()C 。因此,您不能将 C 视为 B,因此您不能强制转换。

回答by glebm

Because if B extends C, then B might have stuff that isn't in C (like instance variables you initialize in the constructor that are not in new C())

因为 if B extends C,那么 B 可能有 C 中没有的东西(比如你在构造函数中初始化的实例变量不在 new C() 中)

回答by Joel

You can create a constructor for B that takes C as a parameter. See this postfor ideas to do what you're trying to do.

您可以为 B 创建一个将 C 作为参数的构造函数。请参阅这篇文章,了解做您想做的事情的想法。

回答by Jon Skeet

The existing answers are fine in terms of an abstract argument, but I'd like to make a more concrete one. Suppose you coulddo that. Then this code would have to compile and run:

就抽象论点而言,现有答案很好,但我想提出一个更具体的答案。假设你可以这样做。然后这段代码必须编译并运行:

// Hypothetical code
Object object = new Object();
InputStream stream = (InputStream) object; // No exception allowed?
int firstByte = stream.read();

Where exactly would the implementation of the readmethod come from? It's abstract in InputStream. Where would it get the data from? It simply isn't appropriateto treat a bare java.lang.Objectas an InputStream. It's much better for the cast to throw an exception.

read方法的实现究竟来自哪里?它是抽象的InputStream。它会从哪里获取数据?它仅仅是不恰当的治疗裸java.lang.Object作为InputStream。演员抛出异常要好得多。

In my experience it's tricky to get "parallel class hierarchies" like the one you're describing to work. You mayfind that generics help, but it can get hairy very quickly.

根据我的经验,像您描述的那样使“并行类层次结构”起作用是很棘手的。您可能会发现泛型有所帮助,但它很快就会变得毛茸茸的。

回答by Maurice Perry

In your exemple, you can cast n into a DerivedNode if you are certain that n is an instance of DerivedNode, or you can use generics:

在您的示例中,如果您确定 n 是 DerivedNode 的实例,则可以将 n 转换为 DerivedNode,或者您可以使用泛型:

public class Base<N extends BaseNode> {
    protected N n;
    public void foo(BaseNode x){
        n.foo(x);
    }
}


public class BaseNode {
    public void foo(BaseNode x){...}
}

public class Derived extends Base<DerivedNode> {
    public void bar(DerivedNode x){
        n.bar(x); // no problem here - n DOES have bar
    }
}

public class DerivedNode extends BaseNode {
    public void bar(BaseNode){
        ...
    }
}

回答by rich s

Base classes shouldn't know anything about classes derived from them, otherwise the problems highlighted above will arise. Downcasting is a 'code smell', and downcasting in the base class to a derived class is particularly 'smelly'. Such designs can lead to difficult to resolve circular dependencies too.

基类不应该知道从它们派生的类的任何信息,否则会出现上面强调的问题。向下转换是一种“代码异味”,将基类中的向下转换为派生类特别“臭”。这种设计也会导致难以解决循环依赖。

If you want a base class to make use of derived class implementations use the Template method pattern i.e add a virtual or abstract method in your base class and override and implement it in the derived class. You can then safely call this from the base class.

如果您希望基类使用派生类实现,请使用模板方法模式,即在基类中添加虚拟或抽象方法并在派生类中覆盖和实现它。然后您可以安全地从基类调用它。