代码之家  ›  专栏  ›  技术社区  ›  Cam

将基类转换为派生类

  •  17
  • Cam  · 技术社区  · 15 年前

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

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

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

    还是这个?

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

    好吧,让我更具体地谈谈我想做什么。以下是我的资料:

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

    现在,我想创建一组新的类来扩展基本节点和基本节点,如下所示:

    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){
            ...
        }
    }
    

    因此,本质上,我想通过扩展基本节点和基本节点并向它们添加一个函数来向它们添加新功能。此外,基本节点和基本节点应该能够单独使用。

    如果可能的话,我真的很想不使用仿制药。


    好吧,所以我终于弄明白了,部分原因是马吕斯·佩里的回答。

    在我的构造函数中 Base , n 被实例化为 BaseNode . 我要做的就是重新实例化 n 作为一个 DerivedNode 在我的派生类的构造函数中,它工作得很好。

    8 回复  |  直到 6 年前
        1
  •  6
  •   Babar    15 年前

    你需要使用 运算符 关键字检查引用的对象类型 n 然后键入对象并调用 巴尔) 方法。结账 派生.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" );
        }
    }
    
        2
  •  21
  •   Omry Yadan    15 年前

    因为如果b扩展c,它意味着b是c,而不是c是b。

    重新思考你想做什么。

        3
  •  18
  •   Jon Skeet    15 年前

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

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

    在哪里执行 read 方法来自?它是抽象的 InputStream . 它从哪里获取数据?它很简单 不合适 治疗光秃秃的 java.lang.Object 作为一个 输入流 . 演员们最好还是提出一个例外。

    根据我的经验,要得到“并行类层次结构”是很难的,就像你描述的那样。你 可以 发现仿制药有帮助,但它会很快变得毛茸茸的。

        4
  •  3
  •   Community CDub    8 年前

    您可以为B创建一个以C为参数的构造函数。 见 this post 去做你想做的事情。

        5
  •  2
  •   brabster    15 年前

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

    所以,假设c有一个方法 foo() . 然后你知道你可以打电话 英尺() 在a b上,当b扩展c时,因此可以相应地将a视为c (C)(new B()) .

    但是-如果B有方法 bar() 子类关系中没有任何内容表示可以调用 巴尔) 也在C上。因此,不能将C视为B,也不能将其铸造。

        6
  •  2
  •   Maurice Perry    15 年前

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

    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){
            ...
        }
    }
    
        7
  •  2
  •   rich s    12 年前

    基类不应该知道从它们派生的类的任何信息,否则将出现上面强调的问题。downcast是一种“代码气味”,而基类中对派生类的downcast则是一种“臭味”。这样的设计也会导致难以解决循环依赖性。

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

        8
  •  0
  •   glebm    15 年前

    因为如果 B extends C ,那么B可能有一些不在C中的东西(例如,您在构造函数中初始化的实例变量不在新的C()中)