为什么可以在Java中将超类初始化为子类?

时间:2015-03-11 16:23:22

标签: java oop inheritance

简而言之,这是如何以及为何可能:

Object obj=new MyClass();

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


我理解它是如何反过来的,因为子类具有父类的所有变量/方法,所以当你初始化它们时,你只是初始化在父构造函数中指定的变量,它们按照定义存在孩子问题是,当你走另一条路时,它不一定是真的。 子项可以包含父项的变量,那么如果父项甚至没有变量,那么如何将子构造函数与父项一起使用呢?


此功能在开发中有什么用途?我认为如果你想要一个B类实例,你会把它声明为B thing = new B(),而不是A thing =新B()。这可能是我缺乏经验的谈话,所以我会很感激为什么以及如何将父类初始化为其子女之一的启示。

8 个答案:

答案 0 :(得分:7)

  

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

这不正确。当你这样做

Object obj = new MyClass();

Object obj;声明Object类型的引用 并且new MyClass();返回对其创建的对象的引用。

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

正如你所说,

  

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

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

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

现在您创建两个AnimalDogCat的子类,它们会覆盖makeSound()的{​​{1}}方法(Animal咆哮和Dog喵喵叫。

想象一下,您使用Cat代表一个充满Animal s(Dog s和Cat s)的房间,并且您想要制作所有这些房间{{ 1}}。您的列表将被声明为List,因为您不知道将要存储的makeSound()种类。

然后,您遍历List<Animal>为每个Animal致电ListmakeSound()Animal还是Animal并不重要,它会发出声音。

然后想象你想将Dog添加到Cat。容易,不是吗?

答案 1 :(得分:2)

您正在考虑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更改为新的子实例。

答案 2 :(得分:2)

首先,你必须清楚地了解事物。你的示例表达式: Object obj = new MyClass();实际上是两个基本操作的复合。

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

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

你为什么需要这个?

这是实际使用多态基本功能。将任何子类作为其超类引用的能力使得多态性如此强大。你基本上会在两个类共有一个方面的地方使用它,但也存在差异。

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

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。无论创建什么组件(例如Button,CheckBox,RadioButton等),由于Container只依赖于所有组件,它可以处理它们。

答案 3 :(得分:1)

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

Animal a = new Cat();

但是,使用a这样做,您无法对Cat执行任何特定操作,例如meow()purr(),但您可以调用哪些方法适用于所有Animal,例如breathe()

HTH

答案 4 :(得分:1)

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
           }
  }

答案 5 :(得分:0)

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

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

答案 6 :(得分:0)

enter image description here

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

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

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

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

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

答案 7 :(得分:0)

这里有两个不同的东西:

  • 构建新实例
  • 将该实例分配给 变量

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

考虑以下一般情况:

class A extends B implements C,D {
}

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

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

字段或方法上的视图受变量类型的限制(i.E.作为C类型的变量,您只能看到C声明的方法)。 尽管如此,无论变量类型如何,您的实例始终都是使用构造函数实例化的类型