日期:2025/04/06 15:51来源:未知 人气:54
平常我们在Java开发的过程中使用子类继承父类,但是父子之间都使用了相同的实例变量,这个时候创建一个父类的引用,引用到对应的子类,这个时候通过父类的引用来调用相应的实例变量,这个时候会发生什么呢?为了理解这个,我们通过创建以下例子来更好的进行讲解
class Parent {
// Declaring instance variable by name x
String x = "Parent`s Instance Variable";
public void print() {
System.out.println(x);
}
}
class Child extends Parent {
// Hiding Parent class's variable x
by defining a variable in child class with same name.
String x = "Child`s Instance Variable";
@Override
public void print() {
System.out.print(x);
// If we still want to access variable from super class, we do that by using super.x
System.out.print(", " + super.x + "\n");
}
}
接着通过以下方式进行验证
Parent parent = new Child();
System.out.println(parent.x) // Output -- Parent`s Instance Variable
如果我们使用以上方式来进行访问实例变量x,最后打印的是父类的x值,正常情况下我们会理解为和方法多态一样,能够访问到子类的方法,然而却不是,这是为啥呢?
这是因为变量不允许多态和重写,这俩只适用于方法,并且当父类和子类有相同的实例变量时,这时实例变量只能对应的引用类型调用!在Java中,如果父类和子类有相同的变量,这时子类就含有俩相同变量,子类会隐藏父类的实例变量!
1,变量隐藏与方法重写不是相同的
变量隐藏与方法重写不是相同的,当变量隐藏看起来像方法重写,其实是不相似的,重写只适用于方法,然而隐藏只适用变量,在方法重写的案例中,重写方法完全替换了继承的方法,因此当我们试着通过父类的引用指向子类来调用对应的方法,这时您能看到返回的是子类的方法调用!
然而变量隐藏,那个子类隐藏了父类变量被替代了,意味着那个子类中包含了俩变量,但是那个子类变量隐藏了父类变量,因此当我们试着访问访问那个变量从那个子类,他将被访问从那个子类.
当我们声明一个变量在子类,例如x实例变量在父类中,
1,子类的对象包含两个变量,一个在父类,一个在子类,但是那个子类变量隐藏那个父类变量.
2,因为那个x变量在子类隐藏了父类的声明,和那个子类的声明,那这样的话子类访问x变量肯定是访问子类的x变量,那要如何让子类变量访问父类的x变量呢?这时使用super.x来访问父类的x变量.
3,如果我们试着访问x实例变量从子类或者父类的外部来进行访问的话,访问方式是通过引用类型的方式来进行访问。就和上面的父类引用类型指向子类,这个时候使用的是父类的变量,然而(Child) parent2).x这种情况使用的是子类的实例变量!
2,为啥变量隐藏设计成这种方式
因此,当我们知道那个实例变量是选择从那个引用类型而不是对应的实例类型,并且多态是不适合那个变量的,但是真正的原因是为啥呢?为啥变量隐藏来代替重写呢?这是因为变量重写将打破方法继承从那个父类如果我们改变它的类型在那个子类,我们知道每个子类继承变量和方法从它的父类,假设Java允许变量重写并且我们改变那个变量的类型从int到object在那个子类.它将导致任何方法都不能使用那个变量,并且这些方法子类继承父类,那个编译器将给错误
class Parent {
int x;
public int increment() {
return ++x;
}
public int getX() {
return x;
}
}
class Child extends Parent {
Object x;
// Child类继承 increment(), getX() 方法从父类并且方法返回类型为int类型!
// 但是在child类的x 变量是Object, 因此increment(), getX() 将编译失败
}
如果子类变量x重写父类变量x,increment方法和getX方法如何工作,在那个子类这些方法将返回一个错误的类型,如果允许变量重写,那时那个子类变量将不能替换父类的变量.
3,为啥实例变量是选择从声明类型而不是对应的指向类型
在编译时,重写方法调用对待从那个引用类,然而重写方法被替换在运行时,这个过程叫运行时多态!相似的,在编译时,变量访问也是引用类型,但是变量不能被重写在运行时,因此不能被替换为子类变量在运行时.并且一直参考引用类型.