面向对象编程中,某一个实例方法使用实例变量和调用其它实例方法的状况是常见的。当存在继承关系时,这种状况就变得复杂起来。如下就对继承关系中,父类的某实例方法使用实例变量和其它实例方法的状况进行探究。由于我也是初学者,有理解不到位的地方,还请路过的朋友多多指教。java
(1)父类实例方法使用实例变量编程
public或protected修饰的实例变量。测试
由于在继承关系中,public和protected修饰的实例变量对于子类的效果是相同的,因此在此合并讨论。spa
public class Test { public static void main(String[] args) { System.out.println(new Parent().getName()); System.out.println(new Child().getName()); } } class Parent { public String name = "base"; public String getName() { return name; } } class Child extends Parent { public String name = "child"; }
输出结果:code
base base
因而可知,父类的方法若是使用了父类的实例变量,即便在子类中从新定义了一个和该变量名称相同的实例变量,父类的方法在经过子类调用的时候,依然使用的是父类的变量。对象
了解这一点后,咱们能够作一个有趣的实验。下面这段代码会输出什么内容?继承
public class Test { public static void main(String[] args) { Child c = new Child(); c.name = "Child"; System.out.println(c.name); //(1)这里输出的是子类的name System.out.println(c.getName()); //(2)这里输出的时父类的name } } class Parent { public String name = "base"; public String getName() { return name; } } class Child extends Parent { }
(1)处的代码输出的name,是经过子类引用找到的name,而(2)出代码调用的是继承自父类的getName()方法,根据以前测试的结果,该方法访问的确定是父类的name。这里问题的关键在于,子类引用找到的name和父类的name是否是同一个name呢?运行的结果显示:是同一个!内存
输出结果get
Child Child
有这里能够看出,子类继承父类后,子类自身并未多出一个name来,其使用的name仍然是父类的name。也就是说,在内存结构中,子类继承自父类的实例变量,仍然是父类的实例变量,只是对于子类而言是可见的而且表现为子类自身实例变量。面向对象编程
从上述例子还能够看到,子类在声明一个同名成员变量后,子类使用的即是自身的成员变量了。其实此时父类的同名成员变量对子类仍然可见,而且子类能够经过super.变量名来使用该父类的成员变量。
private修饰的成员变量。
其实这时已经不用进一步讨论了,根据上边的结论,父类方法不会访问子类的public/protected员变量,那么确定不会也不会访问到private修饰的成员变量。
综上所述,子类继承自父类的实例方法能够访问的实例变量是父类的实例变量,对于子类自身的实例变量是不能访问的!若是在继承的时候,子类定义了一个和继承自父类的实例变量名称相同的实例变量,则会致使子类不能直接访问父类,进而致使子类方法和父类方法对同名实例变量的操做不一致。因此,不建议子类定义和继承自父类实例变量名称相同的实例变量!
(2)父类实例方法调用实例方法
一样地,分public/protected和private两种状况进行讨论。
public/protected修饰的实例方法。
测试的方法很简单,只须要在对上面的例子稍微改动一下便可。
public class Test { public static void main(String[] args) { new Parent().print(); new Child().print(); } } class Parent { private String name = "base"; public String getName() { return name; } public void print() { System.out.println(getName()); } } class Child extends Parent { private String name = "child"; public String getName() { return name; } }
输出结果:
base child
很明显,子类的getName()覆写了父类的getName(),最终致使两个getName()访问的变量不一致。这里值得注意的是,父类实例方法调用另外一个(子类可见的)实例方法,而且后者被子类重写时,是存在多态的。并且可进一步验证,即便print()方法的修饰符改成private,多态依然存在。
private修饰的实例方法
当方法有private修饰时,多态就不存在了。代码以下
public class Test { public static void main(String[] args) { new Parent().print(); new Child().print(); } } class Parent { private String name = "base"; private String getName() { return name; } public void print() { System.out.println(getName()); } } class Child extends Parent { private String name = "child"; private String getName() { return name; } }
输出结果
base base
这也是能够理解的,由于此时不存在方法的重写,因此也不存在多态。
总结一下:
父类方法访问实例变量只能是父类的实例变量,子类继承父类时。从内存结构上考虑,能够认为子类实例所占据的内存结构中内部有一份完整的父类实例内存结构。父类实例中public/protected修饰的实例变量对于子类实例而言是可见的,而且能够如同访问自身实例变量同样去访问,固然前提是子类自身实例变量中没有父类可见实例变量重名的。另外一方面,父类实例中private修饰的实例变量对于子类而言不可见 。
而当父类方法调用实例方法时,是可能存在多态的。具体说来,若是父类实例方法调用的实例方法被子类重写,当经过子类引用调用前者时,前者所调用的实例方法将采用被子类重写后的那个。然而,若是子类方法和父类方法并没有重写关系(private修饰),那么这种多态效应将不存在,经过子类调用前者时,前者依然使用父类的方法。