简体   繁体   English

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

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

I am confused about how are the methods and constructors called at runtime, since the derived constructor is printed 3 times and the height is printed 0 我很困惑在运行时如何调用方法和构造函数,因为派生的构造函数被打印3次并且打印高度为0

I have tried printing some messages inside methods and constructors as to know what exactly is happening 我已经尝试在方法和构造函数中打印一些消息,以了解究竟发生了什么

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

I expected the output to be 我期待输出

Hello world
Derived : 106
Base : 196

instead I am getting 相反,我得到了

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

It's because you derived the Derived class from Base class and shadowing the variable and also overriding the methods. 这是因为您从BaseDerived类并隐藏变量并覆盖方法。

You're calling the constructor of the Base class whenever you're instantiating the Derived class with: 每当您使用以下方法实例化Derived类时,您都在调用Base类的构造函数:

Derived d = new Derived();

Here what happens when you're calling the above code: 这里当你调用上面的代码时会发生什么:

  • Constructor of Base class Base() is called, 调用基类Base()构造函数,
  • then "Inside Base Const" is printed, 然后打印"Inside Base Const"
  • method showAll() is not called because it's being override. 方法showAll()未被调用,因为它正在被覆盖。 Method showAll() inside the Derived class is called instead, 替代地调用Derived类中的方法showAll()
  • "Inside Base showAll" is printed, 打印出"Inside Base showAll"
  • "Derived : 106.0" is printed because double height = 196.0; 打印"Derived : 106.0" ,因为double height = 196.0; inside Base class is being shadowed by double height = 106.0; inside Base类被double height = 106.0;阴影double height = 106.0; inside the Derived class. Derived类中。

An important point to note is, when subclass object is created, a separate object of super class object will not be created. 需要注意的一点是,在创建子类对象时,不会创建超类对象的单独对象。

Only a subclass object is created that has super class variables. 仅创建具有超类变量的子类对象。

so we unable to blindly say that whenever a class constructor is executed, object of that class is created or not. 所以我们无法盲目地说每当执行一个类构造函数时,就会创建该类的对象。 Please refer to below changes and see. 请参考以下更改并查看。

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

Output 产量

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
  • As we can observe that both super class(Base) object hashcode and subclass(Derived) object hashcode are same, so only one object is created. 我们可以看到,超类(Base)对象哈希码和子类(Derived)对象哈希码都是相同的,因此只创建了一个对象。

  • This object is of class Derived as when we try to print name of class which object is created, it is printing "Derived" which is subclass. 这个对象属于Derived类,当我们尝试打印创建对象的类的名称时,它是打印子类的“Derived”。

  • When you have called showAll() in super class for first time it doesn't have a value for height variable because of the method showAll has overridden.But the value has not assigned at that line it calls. 当您第一次在超类中调用showAll()时,由于showAll已被覆盖的方法,它没有高度变量的值。但是在它调用的那一行没有赋值。

  • When the method showAll() has called inside the subclass it has the value assigned which is 196.0. 当showAll()方法在子类内部调用时,它具有指定的值196.0。 This is due to variable hiding*. 这是由于隐藏变量*。

( Variable hiding: When the child and parent classes both have a variable with the same name, the child class' variable hides the parent class' variable.) 变量隐藏:当子类和父类都具有相同名称的变量时,子类'变量隐藏父类'变量。)

You have stumbled upon a major deficiency in the workings of java (and other object-oriented languages.) This deficiency is allowed by the compiler, but any decent IDE will detect it and show you a warning, so the fact that you are posting this question tells me that you are compiling without some very important warnings enabled. 你偶然发现java(以及其他面向对象语言)的工作存在严重缺陷。编译器允许这种缺陷,但任何体面的IDE都会检测到它并向你显示警告,所以你发布这个问题告诉我你正在编译而没有启用一些非常重要的警告。 Go enable as many warnings as you can on your IDE, and your IDE will point the problem out to you. 在IDE上启用尽可能多的警告,IDE将向您指出问题。 But I will now explain it anyway. 但我现在还要解释一下。

In the constructor of your base class, you are invoking showAll() . 在基类的构造函数中,您正在调用showAll() This is a non-final method, so any derived class may override it. 这是一个非final方法,因此任何派生类都可以覆盖它。

It is a grave mistake to invoke an overridable method from within a constructor . 从构造函数中调用可覆盖的方法是一个严重的错误

You see, at the moment that the base class constructor is being invoked, the derived class constructor has not been invoked yet, and the object has not been fully initialized. 您可以看到,在调用基类构造函数时,尚未调用派生类构造函数,并且该对象尚未完全初始化。 So, what is simply happening is that at the moment that your base class constructor is running, your statement double height = 106.0; 所以,简单发生的是,在你的基类构造函数运行的那一刻,你的语句double height = 106.0; of your derived class has not been executed yet. 您的派生类尚未执行。 That's why the height member of your derived class appears to contain zero. 这就是派生类的height成员似乎包含零的原因。 Zero is simply the default, and 106.0 has not been stored in it yet. 零只是默认值, 106.0尚未存储在其中。

If you enable the right warnings in your IDE, then your IDE will warn you about any invocations of non-final methods from within a constructor. 如果在IDE中启用了正确的警告,那么IDE将在构造函数中警告您有关非最终方法的任何调用。 (In my opinion, this should not be a warning, it should be an error.) (在我看来,这不应该是一个警告,它应该是一个错误。)

So, let me briefly address each of your expectations vs. results: 那么,让我简要介绍一下您的期望与结果:

You expected the following: 您期望以下内容:

Hello world
Derived : 106
Base : 196

That's wrong. 那是错的。 If you had no other mistakes, you should have expected the following: 如果您没有其他错误,您应该预期以下内容:

Hello world
Base : 196
Derived : 106

That's because your Derived constructor starts with an implicit (hidden) call to the Base constructor, so the base constructor will always be invoked first. 这是因为您的Derived构造函数以对Base构造函数的隐式(隐藏)调用开始,因此将始终首先调用基础构造函数。 This is evident by your System.out.println("Inside X Const") statements. 您的System.out.println("Inside X Const")语句就是明证。

But instead you got the following: 但相反,你得到以下内容:

Hello World
Derived : 0.0
Derived : 106.0

Both lines appear to come from the 'Derived' class, because getClass() will return the class of the current object, and you have only created one object, which is an instance of Derived . 这两行看起来都来自'Derived'类,因为getClass()将返回当前对象的类,并且您只创建了一个对象,它是Derived一个实例。 So, getClass() will return Derived when invoked from within the Derived class, and it will also return Derived when invoked from within the Base class. 因此,当从Derived类中调用时, getClass()将返回Derived ,并且当从Base类中调用时,它也将返回Derived

And then the 0.0 as I have already explained comes from the uninitialized member variable of the Derived instance, since you are invoking the showAll() overridable from within the constructor of the base class, so the derived class has not had a chance to initialize itself at the moment that the method is invoked. 然后我已经解释过的0.0来自Derived实例的未初始化的成员变量,因为你从基类的构造函数中调用showAll()showAll() ,所以派生类没有机会初始化自己在调用该方法的那一刻。

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

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