`
talentluke
  • 浏览: 595021 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

Java覆盖与隐藏的区别

 
阅读更多

1 隐藏

隐藏现象发生在子类和父类之间,隐藏是针对父类中成员变量和静态方法而言。当子类声明与父类中成员变量具有相同的变量名的变量时,则实现了对父类中成员变量的隐藏;当子类声明了与父类中的静态成员方法具有相同的方法名,参数列表和相同的返回值时,则实现了对父类中静态方法的隐藏。成员变量和静态方法由栈中对象类型决定,不是由实例类型决定,是与类相关的,不是与实例相关的,编译时检查的。

2覆盖

发生在子类与父类的之间,指在在子类中声明一个和父类具有相同的方法名,参数列表,返回值,访问权限等的非静态方法,即在子类中重新编写方法实现的功能。方法由实例类型决定,是与实例相关的,是与类相关的,运行时检查。

覆盖不同于静态方法的隐藏,父类中被隐藏的方法在子类中完全不可用,而父类中被覆盖的方法在子类中可以通过其他方式被引用。

 

 

关于隐藏和覆盖的区别,要提到RTTI(run-time type identification)(运行期类型检查),也就是运行期的多态,当一个父类引用指向子类对象的时候,请看下面我编写的一段代码:

复制代码代码如下:

public class RunTime {

public static void main(String[] args) {
Animal a = new Cat();
System.out.println(a.A);
System.out.println(a.b);
a.voice();
a.method();

}

 

}

class Dog extends Animal {
public int b = 3;
public static int A = 3;
public static void method(){
System.out.println("狗");
}
public void voice() {
System.out.println("狗叫");
}
}

class Cat extends Animal {
public int b = 4;
public static int A = 4;
public static void method(){
System.out.println("猫");
}
public void voice() {
System.out.println("猫叫");
}
}

class Animal {
public int b = 0;
public static int A = 0;
public static void method(){
System.out.println("动物");
}
public void voice() {
System.out.println("动物叫");
}
}


输出结果是:
0
0
猫叫
动物

 

您可以看到,当父类Animal的引用a指向子类Dog时,RTTI在运行期会自动确定该引用的真是类型,当子类 覆盖 了父类的方法时,则直接调用子类的方法,打印出“猫叫”;然而非静态的方法在子类中重写的话就是被覆盖,而静态的方法被子类重写的话就是隐藏,另外,静态变量和成员变量也是被隐藏,而RTTI是只针对覆盖不针对影藏,所以,静态变量 A 和 非静态变量 b 以及静态方法method() 均不通过RTTI,是哪个类的引用就调用谁的静态方法,成员变量,而这里是父类Animal的引用,所以直接调用父类Animal中的方法以及成员变量。所以静态方法 method(), 静态变量 A 和成员变量 b 打印结果全是父类中的。只用被覆盖的非静态方法voice()才打印子类的。

    ——试图用子类的静态方法隐藏父类中同样标识的实例方法是不合法的,编译器将会报错

  ——试图用子类的实例方法覆盖父类中同样标识的静态方法也是不合法的,编译器会报错

  ——静态方法和最终方法(带关键字final的方法)不能被覆盖

  ——实例方法能够被覆盖

  ——抽象方法必须在具体类中被覆盖

 

1)如果返回类型是引用类型,则覆盖方法的返回类型可以声明为超类方法声明的返回类型的子类型;如果返回类型是基本类型,则覆盖方法的返回类型必须和超类方法的返回类型相同
  2)覆盖方法有自己的访问修饰符,但只限于提供更多的访问权限。覆盖方法还可以改变其他方法修饰符,可以随意的改变synchronized、native和strictfp修饰符。不管覆盖方法中的参数是否是final的,子类都可以修改这个参数(参数的final修饰符不属于方法的签名,只是实现的细节),访问权限、返回类型、抛出的异常、final和返回值不属于方法的签名

  3)覆盖方法的throws子句可以和超类方法有所不同,它列出的每一个异常类型都应该和超类中的异常类型相同,或者是超类异常类型的子类型。   

4)子类方法不能缩小父类方法的访问权限。

  继承 变量的覆盖 属性 

作者:臧圩人(zangweiren) 

网址:http://zangweiren.javaeye.com 

 

>>>转载请注明出处!<<< 

 

我们来看看这么一道题: 

Java代码  

1.class ParentClass {   

2.    public int i = 10;   

3.}   

4.  

5.public class SubClass extends ParentClass {   

6.    public int i = 30;   

7.  

8.    public static void main(String[] args) {   

9.        ParentClass parentClass = new SubClass();   

10.        SubClass subClass = new SubClass();   

11.        System.out.println(parentClass.i + subClass.i);   

12.    }   

13.}  

 

 

控制台的输出结果是多少呢?20?40?还是60? 

 

变量,或者叫做类的属性,在继承的情况下,如果父类和子类存在同名的变量会出现什么情况呢?这就是这道题要考查的知识点——变量(属性)的覆盖。 

 

这个问题虽然简单,但是情况却比较复杂。因为我们不仅要考虑变量、静态变量和常量三种情况,还要考虑private、friendly(即不加访问修饰符)、protected和public四种访问权限下对属性的不同影响。 

 

我们先从普通变量说起。依照我们的惯例,先来看一段代码: 

Java代码  

1.class ParentClass {   

2.    private String privateField = "父类变量--private";   

3.  

4.    /* friendly */String friendlyField = "父类变量--friendly";   

5.  

6.    protected String protectedField = "父类变量--protected";   

7.  

8.    public String publicField = "父类变量--public";   

9.  

10.    // private的变量无法直接访问,因此我们给他增加了一个访问方法   

11.    public String getPrivateFieldValue() {   

12.        return privateField;   

13.    }   

14.}   

15.  

16.public class SubClass extends ParentClass {   

17.    private String privateField = "子类变量--private";   

18.  

19.    /* friendly */String friendlyField = "子类变量--friendly";   

20.  

21.    protected String protectedField = "子类变量--protected";   

22.  

23.    public String publicField = "子类变量--public";   

24.  

25.    // private的变量无法直接访问,因此我们给他增加了一个访问方法   

26.    public String getPrivateFieldValue() {   

27.        return privateField;   

28.    }   

29.  

30.    public static void main(String[] args) {   

31.        // 为了便于查阅,我们统一按照private、friendly、protected、public的顺序   

32.        // 输出下列三种情况中变量的值   

33.  

34.        // ParentClass类型,ParentClass对象   

35.        ParentClass parentClass = new ParentClass();   

36.        System.out.println("ParentClass parentClass = new ParentClass();");   

37.        System.out.println(parentClass.getPrivateFieldValue());   

38.        System.out.println(parentClass.friendlyField);   

39.        System.out.println(parentClass.protectedField);   

40.        System.out.println(parentClass.publicField);   

41.  

42.        System.out.println();   

43.  

44.        // ParentClass类型,SubClass对象   

45.        ParentClass subClass = new SubClass();   

46.        System.out.println("ParentClass subClass = new SubClass();");   

47.        System.out.println(subClass.getPrivateFieldValue());   

48.        System.out.println(subClass.friendlyField);   

49.        System.out.println(subClass.protectedField);   

50.        System.out.println(subClass.publicField);   

51.  

52.        System.out.println();   

53.  

54.        // SubClass类型,SubClass对象   

55.        SubClass subClazz = new SubClass();   

56.        System.out.println("SubClass subClazz = new SubClass();");   

57.        System.out.println(subClazz.getPrivateFieldValue());   

58.        System.out.println(subClazz.friendlyField);   

59.        System.out.println(subClazz.protectedField);   

60.        System.out.println(subClazz.publicField);   

61.    }   

62.}  

 

这段代码的运行结果如下: 

1.ParentClass parentClass = new ParentClass(); 

2.父类变量--private 

3.父类变量--friendly 

4.父类变量--protected 

5.父类变量--public 

6.

7.ParentClass subClass = new SubClass(); 

8.子类变量--private 

9.父类变量--friendly 

10.父类变量--protected 

11.父类变量--public 

12.

13.SubClass subClazz = new SubClass(); 

14.子类变量--private 

15.子类变量--friendly 

16.子类变量--protected 

17.子类变量--public 

 

从上面的结果中可以看出,private的变量与其它三种访问权限变量的不同,这是由于方法的重写(override)而引起的。关于重写知识的回顾留给以后的章节,这里我们来看一下其它三种访问权限下变量的覆盖情况。 

 

分析上面的输出结果就会发现,变量的值取决于我们定义的变量的类型,而不是创建的对象的类型。 

 

在上面的例子中,同名的变量访问权限也是相同的,那么对于名称相同但是访问权限不同的变量,情况又会怎样呢?事实胜于雄辩,我们继续来做测试。由于private变量的特殊性,在接下来的实验中我们都把它排除在外,不予考虑。 

 

由于上面的例子已经说明了,当变量类型是父类(ParentClass)时,不管我们创建的对象是父类(ParentClass)的还是子类(SubClass)的,都不存在属性覆盖的问题,因此接下来我们也只考虑变量类型和创建对象都是子类(SubClass)的情况。 

Java代码  

1.class ParentClass {   

2.    /* friendly */String field = "父类变量";   

3.}   

4.  

5.public class SubClass extends ParentClass {   

6.    protected String field = "子类变量";   

7.  

8.    public static void main(String[] args) {   

9.        SubClass subClass = new SubClass();   

10.        System.out.println(subClass.field);   

11.    }   

12.}  

 

运行结果: 

•子类变量 

 

Java代码  

1.class ParentClass {   

2.    public String field = "父类变量";   

3.}   

4.  

5.public class SubClass extends ParentClass {   

6.    protected String field = "子类变量";   

7.  

8.    public static void main(String[] args) {   

9.        SubClass subClass = new SubClass();   

10.        System.out.println(subClass.field);   

11.    }   

12.}  

 

运行结果: 

•子类变量 

 

上面两段不同的代码,输出结果确是相同的。事实上,我们可以将父类和子类属性前的访问修饰符在friendly、protected和public之间任意切换,得到的结果都是相同的。也就是说访问修饰符并不影响属性的覆盖,关于这一点大家可以自行编写测试代码验证。 

 

对于静态变量和常量又会怎样呢?我们继续来看: 

Java代码  

1.class ParentClass {   

2.    public static String staticField = "父类静态变量";   

3.  

4.    public final String finalField = "父类常量";   

5.  

6.    public static final String staticFinalField = "父类静态常量";   

7.}   

8.  

9.public class SubClass extends ParentClass {   

10.    public static String staticField = "子类静态变量";   

11.  

12.    public final String finalField = "子类常量";   

13.  

14.    public static final String staticFinalField = "子类静态常量";   

15.  

16.    public static void main(String[] args) {   

17.        SubClass subClass = new SubClass();   

18.        System.out.println(SubClass.staticField);   

19.        System.out.println(subClass.finalField);   

20.        System.out.println(SubClass.staticFinalField);   

21.    }   

22.}  

 

运行结果如下: 

1.子类静态变量 

2.子类常量 

3.子类静态常量 

 

虽然上面的结果中包含“子类静态变量”和“子类静态常量”,但这并不表示父类的“静态变量”和“静态常量”可以被子类覆盖,因为它们都是属于类,而不属于对象。 

 

上面的例子中,我们一直用对象来对变量(属性)的覆盖做测试,如果是基本类型的变量,结果是否会相同呢?答案是肯定的,这里我们就不再一一举例说明了。 

 

最后,我们来做个总结。通过以上测试,可以得出一下结论: 

1.由于private变量受访问权限的限制,它不能被覆盖。 

2.属性的值取父类还是子类并不取决于我们创建对象的类型,而是取决于我们定义的变量的类型。 

3.friendly、protected和public修饰符并不影响属性的覆盖。 

4.静态变量和静态常量属于类,不属于对象,因此它们不能被覆盖。 

5.常量可以被覆盖。 

6.对于基本类型和对象,它们适用同样的覆盖规律。 

 

 

 

分享到:
评论

相关推荐

    Java方法的覆盖与隐藏的区别分析

    本篇文章介绍了,关于Java方法的覆盖与隐藏的区别分析。需要的朋友参考下

    java中重载、覆盖和隐藏三者的区别分析

    本篇文章介绍了,在java中重载、覆盖和隐藏它们三者的区别分析。需要的朋友参考下

    Java中的方法和变量在继承时的覆盖问题

    变量和方法覆盖和隐藏的不同:一个类的实例无法通过使用全局名或者强制自己转换为父类型,以访问父类中被隐藏的方法,然而强制转换子类为父类型之后,可以访问父类中被隐藏的变量。另外静态方法不能覆盖父类的实例...

    Java开发技术大全(500个源代码).

    showDiff.java 演示隐藏与覆盖之间的区别 showSomething.java 测试运行时多态 stupid.java 试图覆盖最终方法的类,它有错误 Sub.java 一个简单的子类 Super.java 一个基类 testOverload.java 测试方法的重载...

    方法和变量在继承时的覆盖和隐藏问题

    最近有个同学问了我一个小问题,觉得很有意思,之前一直没有想到过。他说“java中存在方法覆盖,是否存在变量的覆盖呢?”。

    10个java主题

    10个JAVA主题,Item 1: 什么时候被覆盖的方法并非真的被覆盖了 Item 2: String.equals()方法与== 运算符的用法比较 Item 3: Java 是强类型语言本 Item 4: 那是构造函数吗 Item 5: ...

    Java100个面试题.doc

    与此相对,方法覆盖是说子类重新定义了父类的方法。方法覆盖必须有相同的方法名,参数列表和返回类型。覆盖者可能不会限制它所覆盖的方法的访问。 7. Java中的构造函数是什么?什么是构造函数重载?什么是复制构造...

    Java中方法的重写与成员变量的隐藏

    讨论了Java面向对象概念中一个基本的概念–Field Hiding(隐藏成员变量),文中给大家介绍了java中的重写知识,非常不错,具有参考借鉴价值,需要的朋友参考下吧

    java初学者必看

    最近正在学习Java,也买了很多的有关Java方面的书籍,其中发现《跟我学Java》这本书,都的很不错啊,所以顺便拿电脑把这本书的目录敲了下来,与大家分享。尤其是那些和我一样初学Java的朋友们,看看哪一节对你有用,...

    java jdk实列宝典 光盘源代码

    方法和变量在继承时的覆盖和隐藏;排序类; 3数字 数字类;格式化数字;转换数字进制;生成随机数; 4数组和集合 使用Arrays类;动态调整数组长度;java为数据结构中的列表定义了一个接口类java.util.list同时提供了...

    java基础教学ppt

    java基础教学ppt,共15章.第一章 Java语言基础知识 ...* 重载、覆盖和重载的区别 * Object类 * 终结类、终结方法 * 抽象类、抽象方法 * 接口 其它不在这里一一说明.如果有感趣的可以自己下载看.

    java 编程入门思考

    15.6 Java与CGI的沟通 15.6.1 CGI数据的编码 15.6.2 程序片 15.6.3 用C++写的CGI程序 15.6.4 POST的概念 15.7 用JDBC连接数据库 15.7.1 获得学习示例 15.7.2 查找程序的GUI版本 15.7.3 JDBC API为何如何复杂 15.8 ...

    java继承与多态教学及练习

    1继承的概念 2继承的实现 3变量隐藏与方法覆盖 4super关键字 5 子类的构造顺序 6Object类 7 final关键字

    最新java面试题目.docx

    Java 面试题目总结 面向对象的软件开发有哪些优点?面向对象设计是一种把面向对象的思想...方法的覆盖与属性的隐藏不同,方法的覆盖是子类重新定义父类中已经存在的方法,而属性的隐藏是子类重新定义父类中的属性。

    Java面向对象编程思想.pdf

    多态是 Java 面向对象编程的第三大特征,通过重载、重写与覆盖,实现不同类的不同形态特征。多态使得类可以根据不同的情况表现出不同的形态,从而提高代码的灵活性和可维护性。 四、类和对象 类是 Java 面向对象...

    Java初学者入门教学

    15.6 Java与CGI的沟通 15.6.1 CGI数据的编码 15.6.2 程序片 15.6.3 用C++写的CGI程序 15.6.4 POST的概念 15.7 用JDBC连接数据库 15.7.1 获得学习示例 15.7.2 查找程序的GUI版本 15.7.3 JDBC API为何如何复杂 15.8 ...

    java学习重点

    多态性 (重载overload,方法名相同、参数的个数不同、参数的类型不同、返回的类型不同和覆盖override) ;多态性就是“一种接口,多种方法”,可以为一组相关的动作设计一个通用的接口,其实类的函数的重载就是一种...

    java联想(中文)

    15.6 Java与CGI的沟通 15.6.1 CGI数据的编码 15.6.2 程序片 15.6.3 用C++写的CGI程序 15.6.4 POST的概念 15.7 用JDBC连接数据库 15.7.1 获得学习示例 15.7.2 查找程序的GUI版本 15.7.3 JDBC API为何如何复杂 15.8 ...

    信息隐藏隐写与分析

    1、隐写:分别完成位图格式图像头文件冗余、图片尾部追加和数据区覆盖三种隐写。...2、分析:分别完成位图格式图像头文件冗余、图片尾部追加和数据区覆盖三种隐写图像与正常图像的分析及隐写数据的提取。

Global site tag (gtag.js) - Google Analytics