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
, n
is instantiated as a BaseNode
. All I had to do was re-instantiate n
as a DerivedNode
in 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 read
method come from? It's abstract in InputStream
. Where would it get the data from? It simply isn't appropriateto treat a bare java.lang.Object
as 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.
如果您希望基类使用派生类实现,请使用模板方法模式,即在基类中添加虚拟或抽象方法并在派生类中覆盖和实现它。然后您可以安全地从基类调用它。