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中的方法覆盖(Override)和隐藏(Hiding)是面向对象编程中的两个重要概念,它们涉及到多态性和运行时类型识别(RTTI)。在Java中,这两种情况在处理继承关系时会产生不同的行为。 1. **方法覆盖(Override)*...
- 实现窗体能贴边隐藏的核心是检测用户拖动窗口时与屏幕边缘的距离。这需要在`MouseMotionListener`的`mouseDragged()`方法中计算窗口的位置,并对比屏幕边界。 3. **事件处理**: - 使用`MouseListener`监听鼠标...
在Java编程语言中,继承是面向...总结来说,理解Java中方法和变量的覆盖与隐藏规则对于编写正确、高效且可维护的代码至关重要。在编程中应当根据实际需求合理运用继承规则,并注意避免因为覆盖和隐藏带来的潜在问题。
### Java中的方法重载(Overloading)与方法覆盖(Overriding) #### 方法的重载(Overloading) 在Java中,方法重载允许我们定义多个同名的方法,但这些方法之间必须具备不同的特征来区分它们。这有助于提高代码的...
**隐藏与覆盖的区别** 当子类对象被强制转换为父类类型时,对于隐藏的属性,会访问父类中的属性,而对于覆盖的方法,会根据对象的实际类型调用子类的方法,这是由于RTTI的作用。隐藏不受RTTI约束,因此,隐藏是静态...
在Java编程语言中,测试是确保代码质量与正确性的重要环节。其中,语句覆盖、分支覆盖和路径覆盖是衡量测试充分性的重要指标,它们属于代码覆盖率测试的一部分。本文将详细探讨这些概念以及如何在实际开发中应用它们...
7. **覆盖与隐藏的区别**: 当子类中定义了一个与父类同名但参数列表不同的方法时,这实际上是一种“隐藏”,而非覆盖。 #### 四、super关键字 **super关键字**在Java中用于指代当前对象的直接父类对象。它主要用于...
本文中提到的ElcEmma是一款Java代码覆盖率分析工具,它能够有效地从不同层面定位代码的覆盖及未覆盖情况,帮助开发人员设计出高质量的测试用例,有助于保障软件测试工作的充分性。通过在Java游戏实例中应用ElcEmma,...
变量和方法覆盖和隐藏的不同:一个类的实例无法通过使用全局名或者强制自己转换为父类型,以访问父类中被隐藏的方法,然而强制转换子类为父类型之后,可以访问父类中被隐藏的变量。另外静态方法不能覆盖父类的实例...
同样,静态方法(`static`)也不能被覆盖,而是被隐藏,因为静态方法与类关联,而不是与类的实例关联。 5. **abstract方法**:如果父类方法是抽象的(`abstract`),子类必须覆盖它,除非子类也是抽象的。如果子类不是...
showDiff.java 演示隐藏与覆盖之间的区别 showSomething.java 测试运行时多态 stupid.java 试图覆盖最终方法的类,它有错误 Sub.java 一个简单的子类 Super.java 一个基类 testOverload.java 测试方法的重载...
例如,Frame类代表一个窗口,它具有标题和尺寸,并可以设置为可见或隐藏。Panel类则是一个可以容纳其他组件的容器,通常用于布局和定位,其默认的布局管理器为FlowLayout。 事件处理是GUI编程的一个重要方面,Java...
10个JAVA主题,Item 1: 什么时候被覆盖的方法并非真的被覆盖了 Item 2: String.equals()方法与== 运算符的用法比较 Item 3: Java 是强类型语言本 Item 4: 那是构造函数吗 Item 5: ...
《Java语言程序设计(Java7)入门与提高篇》是一本专为初学者和有一定基础的程序员设计的书籍,旨在帮助读者深入理解Java编程语言,并通过实际操作提升编程技能。这本书涵盖的内容广泛,从基础语法到高级特性,全...
- **方法覆盖与static**:Java中无法覆盖static方法,因为方法覆盖依赖于运行时动态绑定,而static方法是静态绑定的。 4. **在static环境中访问非static变量**: - **不可行**:非static变量属于对象实例,而...
### Java问题与解答知识点详解 #### 一、抽象(Abstraction) **定义:** 抽象是面向对象编程中的一个重要概念,指的是在设计系统时只关注事物的本质特征,而忽略那些不重要的细节。它允许开发者创建一个简化版本...
"Java中方法的重写与成员变量的隐藏" Java 中方法的重写和成员变量的隐藏是面向对象编程中两个重要的概念。方法的重写是指在子类中重新定义父类中的方法,以便实现多态性,而成员变量的隐藏则是指在子类中定义与...
在Java编程语言中,方法覆盖(Method Overriding)和变量覆盖(Variable Overriding)是面向对象编程中的两个重要概念,尤其对于初学者来说,正确理解它们的区别至关重要。 **方法覆盖**指的是子类重写父类中具有...
每个类都有自己的构造器,子类可以有与父类同名的构造器,但这不是覆盖,而是隐藏。 4. **静态方法与方法覆盖**: 静态方法也不能被覆盖,因为它们是与类绑定的,而不是与对象绑定。静态方法的调用是基于类的,而...
《Java全能速查宝典》作为一本全面介绍Java编程语言的参考书,不仅覆盖了Java基础知识,还深入探讨了面向对象编程、常用开发工具和技术、进阶技巧与最佳实践等内容。对于初学者来说,这本书可以作为学习Java的入门...