问题描述
据了解,子类BB
的getS
方法覆盖了父类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()
new
运算符首先创建SomeClass
的对象,但该对象的所有字段都设置为默认值 (0, '\0', false, null).
new
operator first creates object ofSomeClass
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.
但是方法是多态的(只要它们不是 private
、static
或 final
).这意味着当我们在超类中调用被覆盖的方法时,将执行最新版本"的代码(因为多态使用 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) holdnull
- 但在
s
被初始化为"hello2"
之前super()
被调用(内部调用getS()
代码>) - 因为
getS()
是来自BB
类的多态代码,该方法将被执行 - 但是那个代码(来自
BB
)使用了尚未初始化的BB的s
,所以它持有null
,这就是你在控制台中看到.
- before
s = "hello2";
is executeds
(of BB class) holdsnull
- but before
s
is initialized to"hello2"
super()
is called (which internally callsgetS()
) - since
getS()
is polymorphic code fromBB
class for that method will be executed - but that code (from
BB
) usess
of BB which wasn't yet initialized, so it holdsnull
and that is what you see in console.
因此,放入可以被覆盖的构造函数方法被认为是不好的做法(在大多数情况下).我们应该限制自己调用非多态的方法,这意味着private
static
或final
.
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中使用多态性从父类打印时,为什么子私有字段为空?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!