繁体   English   中英

为什么程序打印高度值0而不是我设置的高度值?

[英]Why does the program print the height value 0 instead of the one I set?

我很困惑在运行时如何调用方法和构造函数,因为派生的构造函数被打印3次并且打印高度为0

我已经尝试在方法和构造函数中打印一些消息,以了解究竟发生了什么

public class Derived extends Base{
    public static void main(String args[]){
        System.out.println("Hello World");
        Derived d = new Derived();
    }

    protected Derived(){
        System.out.println("Inside Derived Const");
        showAll();
    }

    protected void showAll(){
        System.out.println("Inside Derived showAll");
        System.out.println(getClass().getName()+" : "+height);
    }

    double height = 106.0;
}

class Base{

    protected Base(){
        System.out.println("Inside Base Const");
        showAll();
    }

    protected void showAll(){
        System.out.println("Inside Base showAll");
        System.out.println(getClass().getName()+" : "+height);
    }

    double height = 196.0;
}

我期待输出

Hello world
Derived : 106
Base : 196

相反,我得到了

Hello World
Inside Base Const
Inside Derived showAll
Derived : 0.0
Inside Derived Const
Inside Derived showAll
Derived : 106.0

这是因为您从BaseDerived类并隐藏变量并覆盖方法。

每当您使用以下方法实例化Derived类时,您都在调用Base类的构造函数:

Derived d = new Derived();

这里当你调用上面的代码时会发生什么:

  • 调用基类Base()构造函数,
  • 然后打印"Inside Base Const"
  • 方法showAll()未被调用,因为它正在被覆盖。 替代地调用Derived类中的方法showAll()
  • 打印出"Inside Base showAll"
  • 打印"Derived : 106.0" ,因为double height = 196.0; inside Base类被double height = 106.0;阴影double height = 106.0; Derived类中。

需要注意的一点是,在创建子类对象时,不会创建超类对象的单独对象。

仅创建具有超类变量的子类对象。

所以我们无法盲目地说每当执行一个类构造函数时,就会创建该类的对象。 请参考以下更改并查看。

public class Derived extends Base {
    public static void main(String args[]) {
        System.out.println("Hello World");
        Derived d = new Derived();
        d.getClass();
    }

    protected Derived() {
        System.out.println("Inside Derived Const");
        System.out.println("Sub class object hashcode :" + this.hashCode());
        System.out.println(this.getClass().getName());
        showAll();
    }

    protected void showAll() {
        System.out.println("Inside Derived showAll");
        System.out.println("Sub class object hashcode :" + this.hashCode());
        System.out.println(getClass().getName() + " : " + height);
    }

    double height = 106.0;
}

class Base {

    protected Base() {
        System.out.println("Inside Base Const");
        System.out.println("Super class object hashcode :" + this.hashCode());
        System.out.println(this.getClass().getName());
        showAll();
    }

    protected void showAll() {
        System.out.println("Inside Base showAll");
        System.out.println("Sub class object hashcode :" + this.hashCode());
        System.out.println(getClass().getName() + " : " + height);
    }

    double height = 196.0;
}

产量

Hello World
Inside Base Const
Super class object hashcode :1917513796
Derived
Inside Derived showAll
Sub class object hashcode :1917513796
Derived : 0.0
Inside Derived Const
Sub class object hashcode :1917513796
Derived
Inside Derived showAll
Sub class object hashcode :1917513796
Derived : 106.0
  • 我们可以看到,超类(Base)对象哈希码和子类(Derived)对象哈希码都是相同的,因此只创建了一个对象。

  • 这个对象属于Derived类,当我们尝试打印创建对象的类的名称时,它是打印子类的“Derived”。

  • 当您第一次在超类中调用showAll()时,由于showAll已被覆盖的方法,它没有高度变量的值。但是在它调用的那一行没有赋值。

  • 当showAll()方法在子类内部调用时,它具有指定的值196.0。 这是由于隐藏变量*。

变量隐藏:当子类和父类都具有相同名称的变量时,子类'变量隐藏父类'变量。)

你偶然发现java(以及其他面向对象语言)的工作存在严重缺陷。编译器允许这种缺陷,但任何体面的IDE都会检测到它并向你显示警告,所以你发布这个问题告诉我你正在编译而没有启用一些非常重要的警告。 在IDE上启用尽可能多的警告,IDE将向您指出问题。 但我现在还要解释一下。

在基类的构造函数中,您正在调用showAll() 这是一个非final方法,因此任何派生类都可以覆盖它。

从构造函数中调用可覆盖的方法是一个严重的错误

您可以看到,在调用基类构造函数时,尚未调用派生类构造函数,并且该对象尚未完全初始化。 所以,简单发生的是,在你的基类构造函数运行的那一刻,你的语句double height = 106.0; 您的派生类尚未执行。 这就是派生类的height成员似乎包含零的原因。 零只是默认值, 106.0尚未存储在其中。

如果在IDE中启用了正确的警告,那么IDE将在构造函数中警告您有关非最终方法的任何调用。 (在我看来,这不应该是一个警告,它应该是一个错误。)

那么,让我简要介绍一下您的期望与结果:

您期望以下内容:

Hello world
Derived : 106
Base : 196

那是错的。 如果您没有其他错误,您应该预期以下内容:

Hello world
Base : 196
Derived : 106

这是因为您的Derived构造函数以对Base构造函数的隐式(隐藏)调用开始,因此将始终首先调用基础构造函数。 您的System.out.println("Inside X Const")语句就是明证。

但相反,你得到以下内容:

Hello World
Derived : 0.0
Derived : 106.0

这两行看起来都来自'Derived'类,因为getClass()将返回当前对象的类,并且您只创建了一个对象,它是Derived一个实例。 因此,当从Derived类中调用时, getClass()将返回Derived ,并且当从Base类中调用时,它也将返回Derived

然后我已经解释过的0.0来自Derived实例的未初始化的成员变量,因为你从基类的构造函数中调用showAll()showAll() ,所以派生类没有机会初始化自己在调用该方法的那一刻。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM