本文介绍了java - 在java中使用多态性从父类打印时,为什么子私有字段为空?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

据了解,子类BBgetS方法覆盖了父类AA的相同方法.然而,尽管两个类都初始化了 getS 返回的字段 s,但它被打印为 null.为什么会发生这种情况?

As far as In understand he getS method from child class BB overrides the same method from the parent class AA. Yet although both classes have initialized the field s which is returned by getS it's printed as null. Why is this happening?

这是代码:

public class AA {
    public String getS() {
        return s;
    }
    private String s = "hello1";
    public AA() {
        System.out.println(service() + getS());
    }
    public static String service() {
        return "A service ";
    }
}

public class BB extends AA {
    private String s = "hello2";
    @Override
    public String getS() {
        return s;
    }
    public static String service() {
        return "B service ";
    }
}

public class CC {
    public static void main(String[] args) {
        BB b =new BB(); //prints "A service null"
    }
}

推荐答案

当我们调用 new SomeClass()

  1. new 运算符首先创建 SomeClass 的对象,但该对象的所有字段都设置为默认值 (0, '\0', false, null).

  1. new operator first creates object of SomeClass but that object has all its fields set to default values (0, '\0', false, null).

在创建对象后,执行构造函数的代码以正确初始化对象(将其字段设置为正确的值,并可能做一些其他事情).

After object is created code of constructor is executed to initialize object properly (set its fields to proper values, and possibly do few other things).

但是如果类有父类,构造函数首先(隐式或显式)调用它的 super() 构造函数以确保所有继承的字段都正确初始化,然后我们开始使用可能依赖的继承方法这些字段状态.

But if class has parent class, constructor first (implicitly or explicitly) calls its super() constructor to ensure that all inherited fields are properly initialized, before we start using inherited methods which may depend on those fields state.

但是方法是多态的(只要它们不是 privatestaticfinal).这意味着当我们在超类中调用被覆盖的方法时,将执行最新版本"的代码(因为多态使用 this 实例的实际类型 - 由 new 关键字返回- 定位应该开始搜索应该执行的代码的类 - 这称为后期或 动态绑定).

But methods are polymorphic (as long as they are not private, static or final). This means that when in superclass we call method which was overridden, "newest version" of code will be executed (because polymorphism uses actual type of this instance - returned by new keyword - to locate class from which it should start searching for code which should be executed - this is called late or dynamic binding).

因此,由于您在 AA 超类中调用了 getS() 方法,但是在 BB 实例上(因为这就是 new BB 创建),来自 BB 类的覆盖代码被执行.问题是这段代码使用了 BB 类中声明的 s,但 s 尚未初始化.让我们看看由 new BB() 调用的 BB 的默认构造函数是什么样子的:

So since you called getS() method in AA superclass but on BB instance (because that is what new BB created), overridden code from BB class was executed. Problem is that this code uses s declared in BB class, but that s wasn't initialized yet. Lets see how default constructor of BB which was invoked by new BB() looks like:

BB(){
    super(); //calls AA()
    s = "hello2"; // by default `s` holds `null` value 
                  // all initialization is moved to constructors 
                  // after superconstructor call
}

所以

  • before s = "hello2"; s (of BB class) hold null
  • 但在 s 被初始化为 "hello2" 之前 super() 被调用(内部调用 getS()代码>)
  • 因为 getS() 是来自 BB 类的多态代码,该方法将被执行
  • 但是那个代码(来自BB)使用了尚未初始化的BB的s,所以它持有null,这就是你在控制台中看到.
  • before s = "hello2"; is executed s (of BB class) holds null
  • but before s is initialized to "hello2" super() is called (which internally calls getS())
  • since getS() is polymorphic code from BB class for that method will be executed
  • but that code (from BB) uses s of BB which wasn't yet initialized, so it holds null and that is what you see in console.

因此,放入可以被覆盖的构造函数方法被认为是不好的做法(在大多数情况下).我们应该限制自己调用非多态的方法,这意味着private staticfinal.

Because of that it is considered bad practice (in most cases) to put in constructor methods which can be overridden. We should limit ourselves to calling methods which are not polymorphic, which means either private static or final.

这篇关于java - 在java中使用多态性从父类打印时,为什么子私有字段为空?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-27 15:27