【问题标题】:Why can a super class be initialized as a child class in Java?为什么超类可以在Java中初始化为子类?
【发布时间】:2015-03-11 16:23:22
【问题描述】:

简而言之,如何以及为什么会这样:

Object obj=new MyClass();

Object 是所有对象的超类,因此 MyClass 是 Object 的子类。一般来说,在Java中,为什么可以在父类中使用子类的构造函数?


我理解它是如何反过来的,因为子类拥有父类的所有变量/方法,所以当你初始化它们时,你只是初始化父构造函数中指定的变量,这些变量按定义存在于孩子。问题是,当你反其道而行之时,它不一定是正确的。 子级可以有父级没有的变量,那么当父级甚至没有变量时,如何将子级构造函数与父级一起使用?


这个特性在开发中有什么用处?我认为如果你想要一个 B 类的实例,你应该将它声明为 B thing=new B(),而不是 A thing=新的 B()。这可能是我的经验不足,所以我希望能得到关于为什么以及如何将父类初始化为其子类的启发。

【问题讨论】:

  • 要获得准确的答案,您必须深入了解 Java 是如何实现的......为了让您直观了解 Object obj = new MyClass(); 为何有效,那是因为 MyClass 一个Object,因为它实现了那个类并且拥有它的所有方法/属性/等等。但是,Object 没有实现方法/等。 MyClass
  • 您没有在“父类”中使用子类的构造函数:您正在使用子类的构造函数,但随后将“MyClass”对象分配给更通用的类变量,一个“对象”。
  • What uses does this feature have in development? 如果类型无关紧要并且我们正在处理许多可能的类型。为每种可能的类型编写一个方法可能是不可能的。但是如果我们只需要具体的信息,比如Object#toString()方法,那么我们可以只使用Object而不是MyClassStringInteger等等。例如,System.out.println(Object);

标签: java oop inheritance


【解决方案1】:

为什么可以使用子类的构造函数 父类?

这是不正确的。当你这样做时

Object obj = new MyClass();

Object obj; 声明Object 类型的引用 new MyClass(); 返回一个对它创建的对象的引用。

因此,您正在实例化MyClass 并将对创建的对象的引用分配给Object 类型的引用,这是可能的,因为MyClassObject

如你所说,

孩子可以拥有父母没有的变量

这称为扩展父功能 (inheritance)。

对于您的第二个问题,请考虑经典的 Animal 示例:假设您创建了一个 Animal 类并在其上创建了一个方法 makeSound()

现在您创建Animal 的两个子类DogCat,它们将覆盖AnimalmakeSound() 方法(一个Dog 吠和一个Cat 喵)。

假设您使用List 表示一个充满Animals(Dogs 和Cats)的房间,并且您想将它们全部设为makeSound()。您的列表将被声明为 List<Animal>,因为您不知道要存储的 Animals 类型。

然后您遍历List 为每个Animal 调用makeSound()AnimalDog 还是 Cat 无关紧要,它会让它听起来不错。

然后假设您想将Birds 添加到List。容易,不是吗?

【讨论】:

    【解决方案2】:

    首先,你必须对事物有一个清晰的认识。您的示例表达式: Object obj = new MyClass(); 实际上是两个基本运算的复合体。

    第一个是创建 MyClass 的实例:new MyClass()new 关键字基本上是实际获取类实例的唯一方法(让我们忽略运行时反射以保持简单),并且您实际上是通过其构造函数在此处命名要创建的内容(MyClass)。除了你用 new 关键字真正命名的东西之外,没有其他方法可以创建任何东西。 new 的结果(隐式)是 MyClass 的一个实例,但 new X 的显式结果是 X 类型的 reference(引用新创建的实例)。

    现在第二个操作是将您的(新)MyObject 的引用分配给另一个 Object 类型的引用。这是有效的,因为 MyObject is 是一个 Object(由于继承)。

    你为什么需要这个?

    这是真正利用多态性基本特性。将任何子类称为其超类的能力使多态性如此强大。你基本上会在两个类有共同点的地方使用它,但也有区别。

    一个真实的例子是图形用户界面。窗口中有按钮、列表、表格和面板,它们都是用户界面元素,但每个元素的作用不同。为了将它们整齐地组织在一个窗口中,这些元素通常嵌套在面板中,更抽象地表示为 容器。现在容器不关心里面有什么样的元素,只要它们是组件。但要正确处理它们,容器确实需要一些关于这些组件的基本信息,主要是它们占用了多少空间以及如何实际绘制它们。所以这被建模为:

    public abstract class Component {
        public int getWidth() { ... }
    
        public int getHeight() { ... }
    
        public void paint(Graphics g) { ... }
    }
    
    public class Container extends Component {
        public void add(Component child) { ... }
    
        public void paint(Graphics g) {
            for (Component child : children) {
                child.paint(g);
            }
        }
    }
    

    这几乎是直接从 JDK 中提取出来的,关键是,如果您需要将每个 Component 称为其具体类型,那么构建一个 Container 是不切实际的,您决定制作的每个 Component 都需要额外的代码(例如,会有一个 addButton、addTable 等)。因此,Container 只是参考 Component 来工作。无论创建什么 Component(例如 Button、CheckBox、RadioButton 等),由于 Container 只是依赖它们来处理所有 be Component,因此它可以处理它们。

    【讨论】:

      【解决方案3】:
      class myMobile{
        public void call{
           System.out.println("Mobile");
            }
        }
          public class mainClass{
              public static void main(){
                  Object o=new myMobile();
                      //here we can call methods which are common to all 
                                           // objects not specific to 
                                                         // myMobile object
                 }
        }
      

      【讨论】:

        【解决方案4】:

        Java 中的每个类都源自Object。所以MyClassObject,顾名思义,但它是一个更专业的版本。可以这样想:每个生物都是AnimalCat 是一种特殊的动物;特定类型。由于CatAnimal,您仍然可以将其称为Animal

        Animal a = new Cat();
        

        但是这样做,使用a,你不能做任何特定于Cat的事情,比如meow()purr(),但是你可以调用对所有Animals都有效的方法,比如作为breathe()

        HTH

        【讨论】:

          【解决方案5】:

          您正在考虑 C++ 语义,但这是 Java。在 Java 中,所有非原始类型变量都是引用,而不是实例。

          在 C++ 中,当你说

          Object obj;
          

          您在堆栈或静态内存中分配了一个新的 Object 实例。

          当你说

          Object obj = new MyObject;
          

          您调用 Object 类的构造函数,该构造函数接受 MyObject 指针(或者可能是 MyObject 可以转换为的其他东西)。

          在 Java 中,

          Object obj;
          

          不创建Object 的任何实例。它只是创建一个可以引用Object 实例的变量,但目前不引用任何实例。初始化为null

          Object obj = new MyObject();
          

          分配MyObject 的一个实例。它不分配Object 的新实例。它只是将变量设置为引用新实例。在 C++ 术语中,这更类似于

          Object *obj = new MyObject();
          

          所以我们不是从子实例构造父实例。我们正在将变量设置为的值从 null 更改为新的子实例。

          【讨论】:

            【解决方案6】:

            因为MyClass Object。请注意,java 是特殊的,因为Object 是所有其他类类型的超类(C++ 中没有等价物)。

            一个更有趣的例子是,如果你有一个类或接口以及一个或多个子类。这在OOD中一直出现。例如,考虑 java 的 jdbc API:一组通用接口,用于连接和查询可由不同具体类实现的数据库。您只需编写 API 代码,然后在运行时使用您选择的数据库的实现。

            【讨论】:

            • 但在 C# 中有。 ;)
            • @Frecklefoot 是的,这只是说这不一定是规范,但你是对的,更现代或纯粹的 OO 语言确实有同样的概念。
            【解决方案7】:

            http://docs.oracle.com/javase/7/docs/api/java/lang/Object.html
            

            类对象是类层次结构的根。每个类都有 Object 作为超类。所有对象,包括数组,都实现了这个类的方法。

            每个 Java 类都是一个Object。这就是原因。

            http://docs.oracle.com/javase/tutorial/java/IandI/subclasses.html

            在 java.lang 包中定义的 Object 类定义并实现了所有类(包括您编写的类)共有的行为。在 Java 平台中,许多类直接派生自 Object,其他类派生自其中一些类,依此类推,形成类的层次结构。

            【讨论】:

            • 你的答案实际上不是他的问题的答案,你在他的问题中陈述的答案中的内容
            【解决方案8】:

            这里有两个不同的东西:

            • 新实例的构造
            • 将该实例分配给 一个变量

            由于您的 MyClass 实例也是 Object 的实例,因此效果很好。

            考虑以下一般情况:

            class A extends B implements C,D {
            }
            

            由于您的 AB 以及 CDObject,因此一旦创建了实例,您就可以(直接或间接)将其分配给所有这些变量类型:

            A a = new A();
            B b = a;
            C c = a;
            D d = a;
            Object o = a;
            

            您对字段或方法的视图受变量类型的限制(即作为 C 类型的变量,您只能看到 C 声明的方法)。 尽管如此,您的实例始终是您使用构造函数实例化的类型,而与变量类型无关。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2017-01-09
              • 1970-01-01
              • 2022-06-10
              • 2019-05-09
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多