重写与隐藏,有些书上或介绍上可能名称不一样,但都大差不差。以前只了解重写,隐藏也听说过,但没有详细了解过,趁现在,整理一下这两方面的内容吧。

  首先,先说一下概念方面的东西。

重写

  重写:子类继承了父类,在子类中声明了与父类具有相同的方法名称与参数列表,并且具有相同的返回类型(或者子类的返回类型是父类的子类型)的实例方法,那么就说子类重写了父类中的同名方法(但父类的方法必须在子类中可见),而重写则是实现多态的前提;子类可以向上转型为父类类型,这样,当通过父类的引用来调用重写的方法时,就可以表现出子类的行为。

1. 如果子类重写了父类的方法,则有如下要求:

(1)子类与父类的方法必须都是实例方法,即都不是静态方法;

(2)子类与父类的方法需要具有相同的方法名称,参数列表,并且子类的返回类型与父类相同,或者是父类的子类型;

public class JavaTest extends Super {
@Override
public Integer print() {
return null;
}
} class Super {
public Object print() {
return null;
}
}

由于Integer是Object的子类,因此满足重写的条件。

(3)子类方法的访问权限不能小于父类的访问权限(可以有相同的访问权限);

public class JavaTest extends Super {
@Override
protected Integer print() {
return null;
}
} class Super {
public Object print() {
return null;
}
}

  访问权限由高到低依次为public,protected,包的访问权限,private。如果子类方法的访问权限低于父类的访问权限,那么编译器将给出错误信息。如上面的代码,编译器就会报错。

(4)子类方法不能比父类方法抛出更多的已检测异常(也称编译时异常),即子类方法抛出的异常必须是父类的子集或和父类是相同的异常;

public class JavaTest extends Super {
@Override
public Integer print() throws IOException {
return null;
}
} class Super {
public Object print() throws FileNotFoundException{
return null;
}
}

如上面代码,由于父类抛出的FileNotFoundException异常是子类抛出的IOException异常的子类,这是不允许的。

注意:如果是未检测异常(运行时异常),则不受此限制,子类也不用显示的使用throws抛出。

(5)父类的方法在子类中必须可见(子类可以使用super来访问父类中被重写的方法);

public class JavaTest extends Super {

    public Integer print() {
return null;
}
} class Super {
private Object print() {
return null;
}
}

如上面代码,父类中的方法是private类型的,在子类是无法访问的,但这不属于重写;

2.重写方法的调用

  当子类向上转型为父类类型A,通过父类的引用来调用某个方法时,Java编译器会先检查当前类有没有实现同名方法,如果有,执行当前类的方法;若没有,则去执行父类的同名方法;若父类没有,则再检查父类的父类有没有实现这个方法,以此类推,直到父类A为止。

public class JavaTest {
public static void main(String[] args) {
SuperClass test = new ThatClass();
test.print1();
test.print2();
test.print3();
}
} class ThatClass extends ThisClass {
public void print1() {
System.out.println("ThatClass print1()");
}
} class ThisClass extends SuperClass {
public void print1() {
System.out.println("ThisClass print1()");
} public void print2() {
System.out.println("ThisClass print2()");
}
} class SuperClass {
public void print1() {
System.out.println("SuperClass print1()");
} public void print2() {
System.out.println("SuperClass print2()");
} public void print3() {
System.out.println("SuperClass print3()");
}
}

执行结果如下:

ThatClass print1()
ThisClass print2()
SuperClass print3()

  还有一种情况,当使用父类的引用调用某个方法(如A方法)时,如果A方法中又调用了另一个父类中的方法(假设为B方法),那么依然按照上述的原则来查找B方法(由子类到父类的查找顺序);

public class JavaTest {
public static void main(String[] args) {
SuperClass test = new ThatClass();
test.print3();
}
} class ThatClass extends ThisClass {
public void print1() {
System.out.println("ThatClass print1()");
}
} class ThisClass extends SuperClass {
public void print1() {
System.out.println("ThisClass print1()");
} public void print2() {
System.out.println("ThisClass print2()");
}
} class SuperClass {
public void print1() {
System.out.println("SuperClass print1()");
} public void print2() {
System.out.println("SuperClass print2()");
} public void print3() {
System.out.println("SuperClass print3()");
print2();
print1();
}
}

打印结果如下:

SuperClass print3()
ThisClass print2()
ThatClass print1()

  简单分析下,父类引用调用print3方法,由于子类都没有重写,所以调用父类的方法,而父类print3方法又调用了父类的其他两个方法,并且这两个方法在子类中均可见,因此按照由子类到父类的查找顺序进行。由于print1方法在子类中被重写,所以调用子类的print1方法,而print2在子类中没有被重写,而是在子类的直接父类中被重写,所以调用子类的直接父类的print2方法。

  注意:JDK5.0之后可以使用@Override注解来标明要重写的方法。如果没有重写,编译器就会报错,如下,编译器就会报错。

class ThatClass extends ThisClass {
@Override
public void print1() {
System.out.println("ThatClass print1()");
}
} class ThisClass {
private void print1() {
System.out.println("ThisClass print1()");
}
}

隐藏

1. 什么是隐藏呢?

  隐藏其实和重写差不多,除了隐藏要求所有的方法都是静态方法,而重写是实例方法,其他的要求都是一样的。

  其实隐藏与重写最本质的区别是,重写是多态的前提,利用重写可以实现多态,而隐藏则无法实现多态。

下面通过一个简单的例子来了解一下:

public class JavaTest {
public static void main(String[] args) {
SuperClass superTest = new ThisClass();
superTest.hiding();
superTest.override();
System.out.println("===================");
ThisClass thisTest = (ThisClass)superTest;
thisTest.hiding();
thisTest.override();
}
} class ThisClass extends SuperClass {
public void override() {
System.out.println("ThisClass void override()");
} public static void hiding() {
System.out.println("ThisClass static void hiding()");
}
} class SuperClass {
public void override() {
System.out.println("SuperClass void override()");
} public static void hiding() {
System.out.println("SuperClass static void hiding()");
}
}

结果如下:

SuperClass static void hiding()
ThisClass void override()
===================
ThisClass static void hiding()
ThisClass void override()

通过以上例子,我们发现了重写与隐藏的根本区别:

(1)如果子类重写了父类的方法,则通过父类的引用调用的是子类的方法;

(2)如果子类隐藏了父类的方法,则通过父类的引用调用的仍然是父类的方法;

(3)这表明了实例方法的调用是动态绑定的,是在运行的时候根据对象真正的类型来决定调用哪个方法,而静态方法的调用是静态绑定的,是根据引用的类型来决定调用哪个方法。

2. 成员变量的隐藏

  当子类继承了父类,在子类中声明了与父类具有相同名称的成员变量时,那么就说子类隐藏了父类中的成员变量。子类不能重写父类中的成员变量,只能隐藏。

  所以,不管是静态变量还是实例变量,打印的是父类还是子类的成员变量取决于引用的类型,而不是对象的类型,因为子类隐藏了父类的成员变量。

public class JavaTest {
public static void main(String[] args) {
SuperClass superTest = new ThisClass();
System.out.println(superTest.min);
System.out.println(superTest.max);
System.out.println("===================");
ThisClass thisTest = (ThisClass)superTest;
System.out.println(thisTest.min);
System.out.println(thisTest.max);
}
} class ThisClass extends SuperClass {
public static int max = 8;
public int min = 7;
} class SuperClass {
public static int max = 4;
public int min = 5;
}

结果如下:

5
4
===================
7
8

3. 成员变量的继承

如果子类继承了父类的实例变量,子类将与父类共享该实例变量,在子类中修改将影响到父类,反之亦然。

public class JavaTest {
public static void main(String[] args) {
ThisClass superTest = new ThisClass();
System.out.println("修改之前:");
superTest.printMin();
System.out.println("修改子类之后:");
superTest.setMin(4);
superTest.printMin();
System.out.println("修改父类之后:");
superTest.setSuperMin(7);
superTest.printMin();
}
} class ThisClass extends SuperClass { public void setMin(int value) {
min = value;
} public void setSuperMin(int value) {
super.min = value;
} public void printMin() {
System.out.println("父类的min: " + super.min);
System.out.println("子类的min: " + min);
}
} class SuperClass {
public int min = 5;
}

结果如下:

修改之前:
父类的min: 5
子类的min: 5
修改子类之后:
父类的min: 4
子类的min: 4
修改父类之后:
父类的min: 7
子类的min: 7

至于静态成员变量就不举例了,静态成员变量和实例变量类似,但实例变量是基于对象的,即每一个对象中子类与父类都共享同一份实例对象的拷贝,而不同的对象互不干扰。而静态成员变量是基于类的,这将会导致所有子类与父类都共享同一个静态变量,无论创建多少对象,都是同一份拷贝。

总结:Java的重写与隐藏其实差不多,最根本的区别就是重写可以实现多态,而隐藏则无法实现多态。

参考自:《细说Java》

【细说Java】Java的重写与隐藏的更多相关文章

  1. 类与接口(五)java多态、方法重写、隐藏

    一.Java多态性 面向对象的三大特性:封装.继承.多态. 多态的类型,分为以下两种: 编译时多态: 指的是 方法重载.编译时多态是在编译时确定调用处选择那个重载方法,所以也叫 静态多态,算不上真正的 ...

  2. Java学习笔记二十二:Java的方法重写

    Java的方法重写 一:什么是方法的重写: 如果子类对继承父类的方法不满意,是可以重写父类继承的方法的,当调用方法时会优先调用子类的方法. 语法规则 返回值类型.方法名.参数类型及个数都要与父类继承的 ...

  3. java构造方法和重写equals

    Cell的构造函数 package Test; import java.util.Objects; public class Cell { int a; int b; public int getA( ...

  4. Java 15 新特性:隐藏类

    什么是隐藏类 隐藏类,是一种不能被其他类直接使用的类.引入隐藏类的主要目的是给框架来使用,使得框架可以在运行时生成类,并通过反射间接使用它们.可能有点抽象,不要紧,下面我们通过一个例子来直观的认识它! ...

  5. Java/Java Web中乱码解决汇总

    在开发Java/Java Web Application过程中,往往会出现乱码问题,而且有的时候真会弄得人很烦,浪费太多的时间. 记得之前看过一篇帖子,详细解释了Encoding/Decoding过程 ...

  6. 关于C#重写,隐藏的一些事

    第一次开始写技术博客,不知该从何处下手,本人算是菜鸟一枚,每每看到博客园里面的大牛们分享的技术文章,只能望其项背,高不可攀.但细细想来,若不尝试着从小处从低处慢慢去积累分享,想要成为技术大牛也只能沦为 ...

  7. 重载(overload),覆盖/重写(override),隐藏(hide)

    写正题之前,先给出几个关键字的中英文对照,重载(overload),覆盖/重写(override),隐藏(hide).在早期的C++书籍中,常常把重载(overload)和覆盖(override)搞错 ...

  8. C#之重写与隐藏

    一 重写与隐藏区别 (1)方法重写:就是在基类中的方法用virtual关键字来标识,然后在继承类中对该类进行重写(override),这样基类中的方法已经被重写了,已经失去了功能了.当让基类的对象的引 ...

  9. 新手如何学习Java——Java学习路线图

    推荐初学者阅读:新手如何学习Java——Java学习路线图

随机推荐

  1. Hbase设计实战

    Hbase设计实战 本文通过一个游戏公司客户实际案例的讲解,分析了 Hbase 表设计及开发在实际案例中的运用,对比了不同的 Hbase 设计考量对客户端访问模式及检索性能的差异.读者通过案例中 Hb ...

  2. SKPhysicsContactDelegate协议

    符合 NSObject 框架 /System/Library/Frameworks/SpriteKit.framework 可用性 可用于iOS .0或者更晚的版本 声明于 SKPhysicsWorl ...

  3. [转] Linux Shell 文本处理工具集锦

    内容目录: find 文件查找 grep 文本搜索 xargs 命令行参数转换 sort 排序 uniq 消除重复行 用tr进行转换 cut 按列切分文本 paste 按列拼接文本 wc 统计行和字符 ...

  4. div中实现居中

    今天纠结了大半天的居中,把学到的先记录下来,还没完全弄清楚,发现网上原创的技术贴并不算多,大多都是相互转载.(ps.先安利一个大神的帖集,昨天才发现的,内容丰富,语言,呃...很幽默,一般都是图文并茂 ...

  5. poj 1595

    #include <iostream> #define N 10010 using namespace std; int a[N],b[N]; int prime(int a) { int ...

  6. FileUpload 简单上传+小预览

    页面代码 : <form id="form1" runat="server"> <div> <asp:FileUpload ID= ...

  7. FAL[client]: Failed to request gap sequence GAP - thread 1 sequence 29-29

    一:问题描述 主备库所在机器都重启后,rac(主库)开机自动启动,但备库(单实例)不是开机启动,现已手工启动到mount,并已在备库上alter database recover  standby d ...

  8. 汇编笔记之 ret 、retf和call

    作用: ret  将 栈顶数据出栈到IP retf 将 栈顶数据出栈到IP ,然后再次将栈顶数据出栈到CS 这样一来,可以使程序跳转到已经定义好了的代码段去执行. call 语法 call s0 (如 ...

  9. NetBeans使用技巧记录

    1.窗体字体大小设置: 在etc文件夹下的netbeans.conf中添加,12表示字体大小,12正合适. netbeans_default_options="--fontsize 12 - ...

  10. RBAC角色权限设计思路

    1 设计思路 为了设计一套具有较强可扩展性的用户认证管理,需要建立用户.角色和权限等数据库表,并且建立之间的关系,具体实现如下. 1.1 用户 用户仅仅是纯粹的用户,用来记录用户相关信息,如用户名.密 ...