java - 为什么使用java中的多态性从父类打印子私有字段时为空?
据了解,子类 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、''、false、null).
new
operator first creates object ofSomeClass
but that object has all its fields set to default values (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
}
所以
- 在执行
s = "hello2";
之前s
(属于 BB 类) 持有null
- 但在
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
.
相关文章