Java基础

【重点】变量/方法:java继承里的 隐藏 vs方法

隐藏:父类和子类拥有相同名字的属性或者方法时,父类的同名的属性或者方法形式上不见了,实际是还是存在的。

  • 变量隐藏:子类实例变量/静态变量可以隐藏父类的静态/实例变量,总结为变量”可以交叉隐藏
  • 方法隐藏:只有一种形式,就是父类和子类存在相同的静态方法。

覆盖:子类重写父类的方法,要求方法名和参数类型完全一样(参数不能是子类),返回值和异常比父类小或者相同(即为父类的子类),访问修饰符比父类大或者相同。

  • 变量覆盖:不存在
  • 方法覆盖:子类实例方法-->[覆盖]-->父类实例方法;子类静态方法-->[覆盖]-->父类静态方法。总结为方法”不能交叉覆盖

【重点】定义:隐藏 vs 覆盖

  • 被隐藏的属性,在子类被强制转换成父类后,访问的是父类中的属性
  • 被覆盖的方法,在子类被强制转换成父类后,调用的还是子类自身的方法
  • 因为覆盖是动态绑定,是受RTTI(run time type identification,运行时类型检查)约束的,隐藏不受RTTI约束,总结为RTTI只针对覆盖,不针对隐藏

例子(必看!)

class Parent{
 
	   int x=10;
	   public Parent(){
		   add(2);
	  }
	   void add(int y){
			x+=y;
	   }
 }
 
class Child extends Parent{
	  int x=9;
	  void add(int y){
		   x+=y;
	  }
	  public static void main(String[] args){
		   Parent p=new Child();
		   System.out.println(p.x);
	  } 
 }

 答案

答案应该是10

在上面的试题中,子类Child的实例方法add(int y)覆盖了父类Parent的实例方法add(int y),而子类的实例变量x则是隐藏了父类的实例变量x。
     Child对象的初始化过程是:
     首先为父类的实例变量x分配内存空间,因为在定义变量x时为它赋了值(int x=10),所以会同时将这个值赋给x。
     其次调用父类的无参构造函数,Parent的构造函数中做的唯一的事情就是调用了add(2);
     第三、由于子类的add(int y)方法覆盖了父类的方法,所以add(2)实际调用的是子类的方法,在子类的add方法中做了如下操作x+=j;在这里由于子类的实例变量x隐藏了父类 的实例变量x,所以这条语句是针对子类本身的,但是这时还没有为子类的实力变量x分配空间,它的默认值是0,加2之后是2。
     第四、父类初始化完毕后接着初始化子类,为子类的x分配内存空间并将它赋值为9,之前的add(2)操作白瞎了。
     再次注意Parent p=new Child();这条语句,它是用父类的引用指向子类的对象,而前面已经说过变量只会被隐藏不会被覆盖,所以这时的p.x值应该是父类的10,而不是子类的9;
     如果将输出语句换成下面的语句结果就是9了:
     System.out..println(((Child)p).x); //首先将p转换成Child类型

原文地址:https://www.cnblogs.com/frankcui/p/13584180.html