Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/variables/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 变量多态性中的初始化_Java_Variables_Constructor_Initialization_Polymorphism - Fatal编程技术网

Java 变量多态性中的初始化

Java 变量多态性中的初始化,java,variables,constructor,initialization,polymorphism,Java,Variables,Constructor,Initialization,Polymorphism,假设您有以下代码 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

假设您有以下代码

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);
    }
}
这将打印0 2

现在,如果删除标记为“this line”的行 代码将打印4

  • 我理解如果没有int I=2;行,
A A=新B()将调用类A,将i初始化为4,调用构造函数,
它控制
类B中的
print()
方法,最后打印4

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

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

  • 然而,我不明白的是,是否有int i=2
为什么如果插入代码,第一部分(创建对象)会突然打印0而不是4?为什么它不将变量初始化为i=4,而是指定默认值

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

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

B() {
    super();
    i = 2;
}
所以当你打电话的时候

A a = new B();

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

在类B中,“i”的声明隐藏了A中的“i”声明,子类中对“i”的所有引用都指向B.i而不是A.i

因此,您在A.i中看到的是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);
    }
}
输出:

a.i is 4
b.i is 2

它是Java中几种行为的组合

  • 方法重写
  • 实例变量阴影
  • 构造器顺序
  • 我将简单地检查一下代码中发生了什么,看看您是否理解

    您的代码在概念上如下所示(跳过main()):

    因此,当您在原始的
    main()
    中调用
    A A=new B(),它正在构造一个
    B
    ,为此:

    • A::i
      B::i
      都是默认值
      0
    • super(),这意味着调用了
      • A::i
        设置为4
      • 调用
        print()
        。由于后期绑定,它被绑定到
        B::print()
      • B::print()
        正在尝试打印出仍为0的
        B::i
    • B::i
      设置为2
    然后,当您在
    main()
    中调用
    a.print()
    时,它被绑定到
    B::print()
    ,它正在打印出
    B::i
    (此时为2)


    因此,当你调用某个类的构造函数时,你看到的结果是,它的超类的构造函数将在它的构造函数之前被调用,我想你是知道的。你知道吗,在调用构造函数之前,超类的字段也会被初始化?这是一个很好的例子,说明了为什么从构造函数中调用可重写的方法是一个坏主意-结果充其量是令人困惑的,更经常是危险的(有可能泄漏对部分初始化对象的引用)。感谢@Hulk指出了这个打字错误。。用更正更新了我的答案
    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);
        }
    }