【问题标题】:Create a base class object from a derived class从派生类创建基类对象
【发布时间】:2015-08-10 15:31:57
【问题描述】:

我有以下课程:

public class Base{

    //fields
    public String getStr(){
        String str = null;
        //Getting str from the fields
        return str;
    }
}

public class Derived extends Base{

    //fields
    //some other fileds
    public String getStr(){
        String str = null;
        //Getting str from the fields + some other fields
        return str;
    }
}

现在,我有一个方法,它的参数类型为Derived

public void makeStr(Derived d){
    Base b = null;
    //Getting the Base class subobject from d and printing the str
}

但我不能像b = d; 那样做赋值然后调用b.getStr(),因为方法d.getStr() 将被调用。

如何从Derived 类型的对象的Base 子对象创建Base 类型的对象?事实上,我只想创建 Derived 类型的 Base 子对象的副本。

【问题讨论】:

  • str 不是字段,而是方法变量
  • @amit 还有?我们从字段中创建 str 。我认为创建该字符串的细节(例如在字段上调用 ​​toString() 方法)在这里并不重要。
  • 我误解了您的意图,虽然您将 str 称为字段本身
  • 这是Derived extends Base 还是您的代码原样?
  • @dubey-theHarcourtians 当然,是的。已更新。

标签: java class inheritance


【解决方案1】:

在子类中重写方法的全部意义在于子类的方法将在运行时执行,即使编译时类型是超类的。

如果出于某种原因你需要超类的实例,你应该为你的超类添加一个复制构造函数并使用它来创建这样一个实例:

public class Base {
    ...
    Base (Base source) {
        // copy the properties from source
    }

}

然后:

public void makeStr(Derived d)
{ 
    Base b = new Base(d);
    ... b.getStr() will call the Base class implementation
}

【讨论】:

  • 是否有一种通用的方法来创建作为基础子对象副本的此类对象?我的意思是避免手动处理字段。
  • @St.Antario 你可以通过反射来做到这一点。
  • 我的意思是我们已经在派生对象中拥有了基础子对象。为什么我们必须在构造函数中显式地编写复制属性?没有反思就没有办法做到这一点?
  • @St.Antario 它可以有更多字段。
  • @St.Antario 如果要调用基本实现,为什么要重写该方法?如果将方法声明为 final,则可以防止覆盖该方法,在这种情况下,将始终调用基本实现。
【解决方案2】:

您可以使用"Has-a" relation 代替"is-a" relation

在这种情况下,您可以使其具有Base 类型的字段,而不是让Derived 扩展Base
Derived 将是一个单独的类,具有自己的功能,并将通过其Base 字段支持Base 的功能。

设计是否正确取决于实现,根据所提供的信息很难判断是否正确。

【讨论】:

  • 正是这个!在很多情况下,人们应该使用组合而不是继承!!! - 有时人们只是使用继承,因为在学校学过它并认为要正确的 OO 你必须有许多扩展和实现,因为它看起来很花哨。
【解决方案3】:

当您在 Java 中从另一个类继承一个类时,子类的对象不存在父“子对象”之类的东西。您似乎希望使用基于原型的继承,就像在 JavaScript 中一样。

如果您希望访问“子对象”,您可能希望以另一种方式实现您的“继承”。 Derived 对象不应继承自 Base 对象,而应将其包装起来。

class Derived {

    private Base base;

    public Derived(Base base) {
        this.base = base;
    }

    public Base getBase() {
        return this.base;
    }
}

public void makeStr(Derived d){
    Base b = d.getBase();
    // ...
}

【讨论】:

  • 实际上,OP 所说的“复制子对象”概念似乎直接取自 C++ - 几乎与任何其他语言都没有多大意义。
【解决方案4】:

基本思想是,当创建子类对象时,子类对象中没有定义基类对象的重写方法,所以你永远不会从子类对象中获得这样的超级方法。

你可以通过类型转换来获得 rest 成员。

Base castedInBase = derivedObj;
//child class specific member as well as hided fields are also availble here.

你只能通过构造函数获取父类的对象-

Base base= new Base(derivedObj);
//orrided method of base class lost,will refer to super class overrided method.

假设以下是您的方法-

public void makeStr(Derived derivedObj){
        Base castedInBase = derivedObj;
    }

注意:这是不可能从父类中获取重写方法的 子类对象。

【讨论】:

    【解决方案5】:

    如果你真的想让基类的实现可用,你可以这样做:

    public class Derived extends Base{
        …
        public String getStr(){
            String str = null;
            // produce the specialized string
            return str;
        }
        public String getBaseStr(){
             return super.getStr(); // delegate to base class
        }
    }
    

    关于它的全部要点是,如果一个类决定重写一个继承的方法,它还会为它自己的实例控制原始方法是否可用于其他类。

    Derived 类总是可以通过super.getStr()this 实例调用Base 的原始实现,但是为了在任意实例(例如作为参数传入的实例)上调用它或公开它其他类的可能性,您需要像上面示例中的另一种方法。然后您可以在Derived 的任意实例上调用getBaseStr()

    【讨论】:

      【解决方案6】:

      你不能这样做。

      派生对象实例将永远附加到它自己的类。您不能只是将其“还原”回基类,也不能只是“跳过”其覆盖的方法以返回基类的实现。

      【讨论】:

        【解决方案7】:

        如果你想假设 BaseDerived 对象共享一个共同的特性,你可以实现一个接口

        public interface IStr {
            String getStr();
        }
        public class Base implements IStr {
            //...
        }
        public class Derived implements IStr {
            //...
        }
        public void makeStr(IStr o) {
            // ...
        }
        

        如果你想复制对象,我会选择 @Eran 的答案 - 创建一个复制构造函数。

        【讨论】:

          【解决方案8】:

          事实上,我只是想创建 Derived 类型的 Base 子对象的副本。

          就去做吧。在你的 Base 中实现复制构造

          public Base(Base b) {
              // assign all required fields from the old object
              ...
          }
          

          当你想从 Derived 获取 Base 时调用它:

          Base b = new Base(d);
          

          【讨论】:

            猜你喜欢
            • 2020-08-06
            • 1970-01-01
            • 2020-03-17
            • 1970-01-01
            • 1970-01-01
            • 2011-07-20
            • 1970-01-01
            • 1970-01-01
            • 2023-01-26
            相关资源
            最近更新 更多