Java中的隐藏和覆盖

1编译时类型和运行时类型

 

Java的引用变量有两个类型,一个是编译时类型,一个是运行时类型

编译时类型由声明该变量时使用的类型决定

运行时类型由该变量指向的对象类型决定

如果编译时类型和运行时类型不一致,会出现所谓的多态。因为子类其实是一种特殊的父类,因此java允许把一个子类对象直接赋值给一个父类引用变量,无须任何类型转换,或者被称为向上转型,由系统自动完成。

 Father  f  =  new  Son();  SonFather的子类

引用变量f就会出现编译时类型和运行时类型不一致的情况 编译时是Father类型的 运行时是Son类型的

当变量的编译时类型和运行时类型不一致时,通过变量访问它所引用的对象的实例时,该实例变量的值由声明该变量的类型决定。

 

通过变量访问它所引用的对象的方法时,该方法的行为由所引用的对象实际类型所决定。

2、隐藏和覆盖

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

覆盖是对于实例方法而言的

方法不能交叉覆盖:子类实例方法不能覆盖父类的静态方法;

                  子类的静态方法也不能覆盖父类的实例方法(编译时报错)

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

隐藏是对于静态方法和成员变量(静态变量和实例变量)而言的

(1)当发生隐藏的时候,声明类型是什么类,就调用对应类的属性或者方法,而不会发生动态绑定

  (2) 属性只能被隐藏,不能被覆盖

 (3)变量可以交叉隐藏:子类实例变量/静态变量可以隐藏父类的实例/静态变量

3、隐藏和覆盖的区别

1被隐藏的属性,在子类被强制转换成父类后,访问的是父类中的属性

  在无强制转换时子类要访问父类的属性使用super关键字

(2)被覆盖的方法,在子类被强制转换成父类后,调用的还是子类自身的方法

     子类要是想访问父类的方法,可以使用super关键字

RTTI(run time type identification,运行时类型检查)

RTTI只针对覆盖,不针对隐藏:因为覆盖是动态绑定,是受RTTI约束的,隐藏不受RTTI约束

运行时类型为引用变量所指向的对象的类型,编译时类型是引用变量自身的类型

4、常见的笔试面试题

[java]  view plain  copy
  1. public class Test {  
  2.     public static void main(String[] args)  {  
  3.         Circle circle = new Circle();//本类引用指向本类对象  
  4.         Shape shape = new Circle();//父类引用指向子类对象(会有隐藏和覆盖)  
  5.           
  6.        System.out.println(circle.name);  
  7.        circle.printType();  
  8.        circle.printName();  
  9.        //以上都是调用Circle类的方法和引用  
  10.          
  11.         System.out.println(shape.name);//调用父类被隐藏的name属性  
  12.         shape.printType();//调用子类printType的方法  
  13.         shape.printName();//调用父类隐藏的printName方法   
  14.     }  
  15. }  
  16.    
  17. class Shape {  
  18.     public String name = "shape";  
  19.        
  20.     public Shape(){  
  21.         System.out.println("shape constructor");  
  22.     }  
  23.        
  24.     public void printType() {  
  25.         System.out.println("this is shape");  
  26.     }  
  27.        
  28.     public static void printName() {  
  29.         System.out.println("shape");  
  30.     }  
  31. }  
  32.    
  33. class Circle extends Shape {  
  34.     public String name = "circle"//父类属性被隐藏  
  35.        
  36.     public Circle() {  
  37.         System.out.println("circle constructor");  
  38.     }  
  39.      
  40.     //对父类实例方法的覆盖  
  41.     public void printType() {  
  42.         System.out.println("this is circle");  
  43.     }  
  44.       
  45.    //对父类静态方法的隐藏    
  46.     public static void printName() {  
  47.         System.out.println("circle");  
  48.     }  
  49. }  
[java]  view plain  copy
  1. 运行结果:  
[java]  view plain  copy
  1. shape constructor  
  2. circle constructor  
[java]  view plain  copy
  1. circle  
  2. this is circle  
  3. circle  
[java]  view plain  copy
  1. shape  
  2. this is circle  
  3. shape  

静态(static)方法重写(override)


父类的普通方法可以被继承和重写,不多作解释,如果子类继承父类,而且子类没有重写父类的方法,但是子类会有从父类继承过来的方法。

静态的方法可以被继承,但是不能重写。如果父类中有一个静态的方法,子类也有一个与其方法名,参数类型,参数个数都一样的方法,并且也有static关键字修饰,那么该子类的方法会把原来继承过来的父类的方法隐藏,而不是重写。通俗的讲就是父类的方法和子类的方法是两个没有关系的方法,具体调用哪一个方法是看是哪个对象的引用;这种父子类方法也不在存在多态的性质。《Java编程思想》中这样提到“只有普通的方法调用可以是多态的”。下面代码为例:

[html]  view plain  copy
  1. public class StaticTest  
  2. {  
  3.     public static void main(String[] args)  
  4.     {  
  5.         M m = new N();  
  6.         m.output();  
  7.     }  
  8. }  
  9.   
  10. class M  
  11. {  
  12.     public static void output()  
  13.     {  
  14.         System.out.println("M");  
  15.     }  
  16. }  
  17.   
  18. class N extends M  
  19. {  
  20.     public static void output()  
  21.     {  
  22.         System.out.println("N");  
  23.     }  
  24. }  

上面执行的结果是“M”,也就是是M类型的引用调用的,如果修改main方法中的代码:

N n = new N();

n.output();

那么执行的结果是“N”,也就是N类型的引用调用的。

静态的方法不能覆写,也不能被重写。总之,静态的没有重写!!!


  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值