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
Java; casting base class to derived class
提问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
回答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.
如果您希望基类使用派生类实现,请使用模板方法模式,即在基类中添加虚拟或抽象方法并在派生类中覆盖和实现它。然后您可以安全地从基类调用它。

