变量多态的初始化

SER*_*ich 13 java variables polymorphism constructor initialization

假设您有以下代码

class A {
    int i = 4;

    A() { 
        print();
    }

    void print () {
        System.out.println("A");
    }
}

class B extends A {
    int i = 2;              //"this line"

    public static void main(String[] args){
        A a = new B();
        a.print();
    }

    void print () {
        System.out.println(i);
    }
}
Run Code Online (Sandbox Code Playgroud)

这将打印0 2

现在,如果删除标有"此行​​"的行,代码将打印4 4

  • 我明白如果没有int i = 2; 线,

A a = new B();将调用类A,将i初始化为4,调用构造函数,
将控制权交给print()方法class B,最后打印4.

a.print()将调用print()类B中的方法,因为这些方法将在运行时绑定,这也将使用在类A,4中定义的值.

(当然,如果我的推理有任何错误,请告诉我)

  • 但是,我不明白的是,如果有int i = 2.

为什么如果你插入代码,第一部分(创建对象)将突然打印0而不是4?为什么不将变量初始化为i = 4,而是指定默认值?

Adr*_*hum 8

它是Java中几种行为的组合.

  1. 方法覆盖
  2. 实例变量阴影
  3. 建设者的顺序

我将简单介绍一下代码中发生的事情,看看你是否理解.

您的代码在概念上看起来像这样(跳过main()):

class A {
    int i = 0; // default value

    A() { 
        A::i = 4;  // originally in initialization statement
        print();
    }

    void print () {
        System.out.println("A");
    }
}

class B extends A {
    int i = 0;              // Remember this shadows A::i

    public B() {
        super();
        B::i = 2;
    }

    void print () {
        System.out.println(i);
    }
}
Run Code Online (Sandbox Code Playgroud)

所以,当你原来的时候main(),你打电话A a = new B();,它正在构建一个B,为此发生这种情况:

  • A::i并且B::i都是默认值0
  • super(),表示调用A的构造函数
    • A::i 设置为4
    • print()叫做.由于后期绑定,它必然会B::print()
    • B::print()正在尝试打印出来B::i,这仍然是0
  • B::i 设置为2

然后当你打电话给a.print()你的时候main(),B::print()打印出来的是有限的B::i(此刻是2).

因此你看到的结果


Nie*_*ier 7

新对象中的所有实例变量(包括在超类中声明的变量)都初始化为其默认值 - JLS 12.5

因此,您的变量B::i将初始化为0. B中的构造函数将如下所示:

B() {
    super();
    i = 2;
}
Run Code Online (Sandbox Code Playgroud)

所以当你打电话

A a = new B();
Run Code Online (Sandbox Code Playgroud)

A中的构造函数将调用printB中的方法,该方法将打印i类B中的方法,即0.


mha*_*san 5

在你的情况下,B类,"i"的声明在A中隐藏了"i"的声明,而在子类中对"i"的所有引用都指的是Bi而不是Ai

所以你在Ai中看到的是java中任何int属性的默认值,它是零.

无法在子类中重写Java实例变量.

您想尝试这个以获得更多说明.

class B extends A {
    int i = 2;              //"this line"

    public static void main(String[] args){
        B b = new B();
        A a = b;
        System.out.println("a.i is " + a.i);
    System.out.println("b.i is " + b.i);
    }

    void print () {
        System.out.println(i);
    }
}
Run Code Online (Sandbox Code Playgroud)

输出继电器:

a.i is 4
b.i is 2
Run Code Online (Sandbox Code Playgroud)