当前课程知识点:Java程序设计 > 第三章 类的重用 > 3.1.3-隐藏和覆盖 > 3.1.3-隐藏和覆盖
大家好欢迎回来继续学习
JAVA语言程序设计
这一节我们来学习
隐藏和覆盖
子类对于那些从超类
继承过来的属性和行为
可以进行重新的定义
如果你定义重名的属性
那从超类继承过来的属性
就被隐藏了
如果你定义一个
声明一个跟超类
继承过来的方法原型
完全一模一样的方法
那么从超类继承过来那个方法
就被覆盖了
接下来我们首先来看
什么是属性的隐藏
现在我们通过这个例子看一下
什么是属性的隐藏
先看左边这个类的声明
在这个Parent类体中
声明了一个
Number类型的成员aNumber
右边这个Child类
它就继承了Parent类
但是在它的类体中
它也声明了一个名字
叫做aNumber的属性
当然它的类型不一样
是Float类型
那经过这样的声明
在这个Child类中
就将继承过来的
Number类型的那个aNumber
就隐藏了
隐藏是什么意思呢
就是子类中声明了
与超类中相同的成员变量名
这样从超类继承的变量
就被隐藏了
隐藏以后它还在不在呢
当然它依然存在
这个时候子类就拥有了
两个相同名字的变量
一个是从超类继承的
另一个是由自己的类声明的
那这两个同样名字的变量
怎么使用呢
如果你通过变量名
去访问它指向的对象的话
到底你访问到哪个变量了呢
那么又要分一下
看看是由哪个方法
来访问这个变量
如果子类执行的是
从超类继承的操作
那么它处理的
当然是从超类继承的变量
这个大家也可以想象得到
因为超类自己继承过来的
这个方法
它当然不可能去处理
子类定义的变量
它只能处理超类的变量
而子类如果执行
它自己声明的方法的时候
这个方法里面
访问了隐藏过的这个同名变量
那它访问的就是
子类自己声明的这个同名变量
具有这样的差别
这就是属性的隐藏
我们用这样的属性隐藏的机制
可以隐藏掉超类中的某些属性
然后定义我们自己的
不同类型的新的属性
好 我们知道了
这个属性隐藏的这种特性
继承来的属性
如果在子类中定义了
同名的属性它就被隐藏了
隐藏以后
如果从子类自己声明的方法中
去访问这些属性的话
那么自动访问到的
就是子类自己声明的新的属性
新的同名属性
如果这个时候
尽管是从子类自己声明的
方法中访问
我还硬要就是访问那个
(父类)超类继承过来的
被隐藏的属性
可不可以呢 能不能访问呢
也是能访问的
这个时候就要通过
super这个关键字来访问
super.属性名
就显示的说明了
我一定要访问
从超类继承过来的
这个名字的属性
这是一个比较简单的例子
我们通过这个例子
想让大家体会一下
当我们去访问一个属性的时候
如果说这个属性
在超类中有声明
在子类中又声明了
同名的属性变量
那么在什么时候
我们访问到的是超类的那个属性
什么时候访问的
是子类的这个属性
具体我们现在来看
定义了一个A1类
里面有属性或者叫变量x
定义的时候就给了初始值是2
然后有一个x方法
将这个参数值i附给x
然后有个Printa方法
是把x的值输出一下
那再看这个类B1
class B1 它继承了A1
它自己定义了一个
也是名字叫x的属性
那这个x就会把
从超类继承过来的
这个x变量隐藏了
它的初始值是100
那么printb里面做点什么事呢
你看它非得要直接访问
从超类继承过来那个x
那怎么办呢
你要是光写x的话
那默认就是本类的这个x了
所以它必须写super.x
那么把super.x加10
再附值回自己
然后super.x
和自己定义的这个x
都一起输出一下
现在我们来看这个测试程序
在测试类里面这个主方法中
我们首先构造一个A1的对象
A1
然后调用setx
把x设置为4
再调用printa去输出
这个没有什么悬念
因为本身就是A1的对象
那setx 把x值设成4了
然后printa输出x
所以我们看到
在这个地方输出的是4
接下来再构造一个B1类的对象
B1它调用printb
调用printb的时候看
在这就将super.x加了10
那么它从超类继承过来
那个x的值此刻是几呢
在加10之前
你看它初始化就成了2
所以2加10这时候
从超类继承过来那个x
super.x变成了12
那么本类自己
新定义的这x是什么呢
我们看初始化为100
这个时候把它们在一行输出
我们就看到了
在这super.x输出的是12
本类自己的x是100
好 接下来通过对象B1
调用printa
虽然是通过对象B1调用
但是调用的这个方法
是从超类继承过来的方法
是printa
这个时候我们就要知道
超类的方法是不可能知道
如何去处理未来某个子类
自己定义的变量和属性的
肯定那语法一定是这样规定
就是超类的方法里面
它处理的这个同名的属性
肯定是那个从超类继承来的
所以这个也没有悬念
这个printa
它输出的就是超类里面
继承过来的这个x
也就是super.x它的值
我们看到输出的是12
好 接下来我们再调用setx
通过B1去调用setx
这个setx也是从超类继承过来
从A1继承过来的
所以这个setx
它会去设置谁的值呢
肯定只会设置那个
super.x的值
所以我们把super.x
又给设置6了
然后再次调用printb
在这个printb里面
对super.x加10
然后本类的x还是原来的样子
没有修改
现在我们来看
输出这一行就是super.x
变成16了
本类自己写的这个x还是100
那接下来再调用一次printa
同样的原因
printa它是从A1继承过来的方法
当然它直接访问的
解决a1继承过来的x
也就是super.x
它又输出一次16
好 最后一次有点迷惑
我们调用A1点printa
注意 这是A1点printa
刚才我们通过B1
做了好多好多个操作
但是A1在这一次调用printa之后
就没有再做过任何的状态改变
那么你再调用一次printa
当然A1这个对象里面的
那个x值依然是
所以你看在这输出的是4
这样通过这个例子
大家应该了解了
在进程的情况下
有属性隐藏的情况下
在什么时候访问的是哪个属性
现在我们将上一个例题中的程序
做一点点修改
刚才这个A类中的x
它是属于对象的
现在我们在前面
加一个static
它就变成静态的了
属于整个类的了
那么我们知道静态的成员
它是不被继承的
但是静态成员
可以被所有的子类对象访问
现在我们来看
B类继承A类
然后B类跟刚才那例题
是一样的定义
我们再测试一下还是这样
够作一个A类的对象A1
然后调用setx
注意这个时候
setx设置的是什么
是它本类的这个静态成员的值
是它本类静态成员值
所以把这个x设置为4
所以就要调用printa
这出这个4
接下来依然是构造B类的对象
B1
那么调用printb
在这个printb里面
它是可以访问
超类的静态成员的
所以这这个super.x
指的是超类的这个静态成员x
它没有继承
但是它是访问的
我们知道静态成员
不属于任何目前一个对象
它不会有多个副本
连这个超类带
不管有多少个子类合一块
它总共有这么一个x的存储
它不会有多个静态x
所以这个时候
在B类的printb方法中
访问的这个super.x
跟我们刚才通过对象A1
调用setx所设置的
那个x是不是一个呀
是一个是一个
所以刚才把这个公共的
静态x设置成4了
那么现在在B类中访问的时候
它当然就是4了
加上10变成14
然后跟本类的x一起输出
我们看到在这一行上输出了
super.x是14 x是100
好 接下来再调用printa
通过B1对象调用printa
输出的依然是大家共享的
那个公共的静态x
那么当然它是14
我们看到输出的是14
好 接下来通过B1
调用setx 把它设置成6
设置的还是这个静态的
为大家所共享的这个x
它现在又变成6了
设置成6以后
再次通过B1调用printb
进到这个方法里面
访问的还是同一个静态x
从头到尾就这么一个静态x
然后加上10它变成16了
我们看到输出的super.x是16
本类的x还是100
接下来我们再通过B1
调用printa
输出的还是这个静态x它是16
好 跟刚才一样
现在通过A1再调用一次printa
注意在刚才的例子里面
A1调用的printa
输出的是A1对象自己的x
而B1调用printa
输出的是B1对象自己的x
但是在现在这个例题中
它们访问的都是同一个静态x
所以通过A1去调用printa
输出的也是16
所以通过这个例题
我们就了解了静态的属性
在继承过程中
它是不被继承的
但是它是可以被
所有本类的对象
和它的子类的对象所访问的
如果我们在子类中
声明了与超类中某个方法
它的原型完全一样的一个方法
我重新声明一遍
重新写方法体
那么这个时候
就叫做方法的覆盖
如果子类不需要使用
从超类继承过来的方法的功能
比如说你想对这个功能进行修改
或者你声明一个完全的
全新的功能
不要它原来的功能
但是仍然用这个
对外的接口名字
也就是这个方法名
这个时候我们就可以
进行方法的覆盖
方法的覆盖
那么覆盖的方法
也就是子类中
自己新定义的同名方法
它的方法原型
与超类中继承过来的方法原型
必须是一样的
返回类型 方法名 参数表
都必须是一致的
然后你可以定义自己新的方法体
而且覆盖方法的访问权限
可以比被覆盖的方法更宽松
但是不能更为严格
举个例子
如果在超类中
这个方法它是公有的
那么到了子类中
它就必须是公有的
不能比这个更严格
比如说你把它定义成保护的
那就不行了
但是如果超类中的方法
它原本是保护的私有的
或者是默认的
你在子类中覆盖的时候
把它扩大一点这个访问权限
变成比如说公有的
那这个是可以的
简单的来说
我们在什么时候
会有可能用到
方法覆盖这种机制呢
有可能我们继承了
超类的方法以后
但是对同样的事情
在子类这种更具体的情况下
它可能希望使用不同的算法
那么自己要去重写一下
这个方法体
也可能除了超类方法
完成的功能以外
子类的这个同名方法
它可能希望增加一些功能
那么这个时候也需要覆盖
还有一个情况
可能干脆取消超类中的某些功能
把它的功能更减少
那么这些都可以用方法覆盖
这种机制来达到
我们在进行方法覆盖的时候
要注意这样几点
有一些方法是必须要覆盖的
比附说我们稍候要介绍的
这个抽象方法
具有抽象方法的类就是抽象类
抽象类就不能生成实例
只能当超类用
那么子类如果继承了
一个抽象类
它里面有抽象方法
你就必须把这些抽象方法覆盖掉
你重新写方法体
原来没有方法体你要写方法体
否则的话这个派生类
自己也就成为抽象类
你也不能实例化了
关于抽象类我们稍候会介绍
大家先有个基本的印象
就可以了
有一些方法是不能覆盖的方法
我们稍候要介绍的
这种final 也就是终结方法
是不允许覆盖的
终结方法里面
规定了算法呀这些
往往就是说
认为这就是很关键的了
对于系统安全
或者是说正确性
它太关键了
所以你直接拿来用就好
千万不要改
那么就不让它改了
也可能是认为这个算法
已经最好了
不需要再改了等等
这样的原因
终结方法
final方法是不许修改的
final方法我们稍候还要仔细讲
另外就是静态方法
这个static方法
这个是不能覆盖的
如果我们覆盖了
超类继承过来的方法以后
又要刻意去调用那个
被覆盖的方法
怎么调用呢
也是要用super关键字
super.被覆盖的方法名
这样就可以调用它了
这一节我们学习了
如何隐藏从超类继承过来的变量
或者叫做属性
如何覆盖从超类继承过来的方法
这样我们就可以
在继承的基础上进行修改
这一节的内容就是这些
-1.0-导学
--1.0-导学
-1.1-Java与面向对象程序设计简介
--第一章 Java语言基础知识--1.1-Java与面向对象程序设计简介
-1.2-基本数据类型与表达式
-第一章 Java语言基础知识--1.2-基本数据类型与表达式
-1.3-数组
--1.3.1-数组
-第一章 Java语言基础知识--1.3-数组
-1.4-算法的流程控制
--第一章 Java语言基础知识--1.4-算法的流程控制
-1.5-第一章小结
-第一章编程练习题
-课件
--外部链接
-Java环境配置、Eclipse使用、Helloworld程序详解
--使用eclipse建立Java项目、编写和运行Java程序
-Java数据类型
--Java整数类型
--Java浮点类型
--数据类型实战
--数据类型转换
--Java强制类型转换精度损失示例与表达式中的数据类型转换
-Java数组
-Java变量
--Java的变量
-命令行参数
--命令行参数的介绍
-2.0-导学
--2.0-导学
-2.1-面向对象方法的特性
--第二章 类与对象--2.1-面向对象方法的特性
-2.2-1-类声明与对象创建
--第二章 类与对象--2.2-1-类声明与对象创建
-2.2-2-数据成员
--第二章 类与对象--2.2-2-数据成员
-2.2-3-方法成员
--第二章 类与对象--2.2-3-方法成员
-2.2-4-包
--2.2-4-包
--第二章 类与对象--2.2-4-包
-2.2-5-类的访问权限控制
--第二章 类与对象--2.2-5-类的访问权限控制
-2.3-1-对象初始化
--第二章 类与对象--2.3-1-对象初始化
-2.3-2-内存回收
--第二章 类与对象--2.3-2-内存回收
-2.4-枚举类
--2.4-枚举类
--第二章 类与对象--2.4-枚举类
-2.5-应用举例
--2.5-应用举例
-2.6-第2章小结
-第二章编程练习题
-课件
--第二章课件
-3.0-导学
--3.0-导学
-3.1.1-3.1.2-类继承的概念和语法
--第三章 类的重用--3.1.1-3.1.2-类继承的概念和语法
-3.1.3-隐藏和覆盖
--第三章 类的重用--3.1.3-隐藏和覆盖
-3.2-Object 类
--第三章 类的重用--3.2-Object 类
-3.3-终结类与终结方法
--第三章 类的重用--3.3-终结类与终结方法
-3.4-抽象类
--3.4-抽象类
--第三章 类的重用--3.4-抽象类
-3.5-泛型
--3.5-泛型
--第三章 类的重用--3.5-泛型
-3.6-类的组合
--3.6-类的组合
-3.7-小结
--3.7-小结
-第三章编程练习题
-课件
--课件
-4.0-导学
--导学
-4.1-接口
--接口
--第四章 接口与多态--4.1-接口
-4.2.1-4.2.2-类型转换
--类型转换
--第四章 接口与多态--4.2.1-4.2.2-类型转换
-4.2.3-方法的查找
--方法的查找
--第四章 接口与多态--4.2.3-方法的查找
-4.3-多态的概念
--多态的概念
--第四章 接口与多态--4.3-多态的概念
-4.4-多态的应用举例
--多态的应用举例
--第四章 接口与多态--4.4-多态的应用举例
-4.5-构造方法与多态性
--构造方法和多态性
--第四章 接口与多态--4.5-构造方法与多态性
-4.6-本章小结
--本章小结
-第四章编程作业
-课件
--课件
-5.0-导学
--5.0-导学
-5.1.1-5.1.2-异常处理的概念
--第五章 输入输出--5.1.1-5.1.2-异常处理的概念
-5.1.3-5.1.5-异常的处理
--第五章 输入输出--5.1.3-5.1.5-异常的处理
-5.2-输入输出流的概念
--输入输出流的概念
--第五章 输入输出--5.2-输入输出流的概念
-5.3.1-写文本文件
--写文本文件
--第五章 输入输出--5.3.1-写文本文件
-5.3.2-读文本文件
--读文本文件
--第五章 输入输出--5.3.2-读文本文件
-5.3.3-写二进制文件
--写二进制文件
--第五章 输入输出--5.3.3-写二进制文件
-5.3.4-读二进制文件
--读二进制文件
-5.3.5-File类
--File类
-5.3.6-处理压缩文件
--处理压缩文件
-5.3.7-对象序列化
--对象序列化
-5.3.8-随机文件读写
--随机文件读写
-5.4-本章小结
--本章小结
-课件
--课件
-6.0-导学
--导学
-6.1-Java集合框架介绍
--第六章 对象群体的组织--6.1-Java集合框架介绍
-6.2-主要接口及常用的实现类
--第六章 对象群体的组织--6.2-主要接口及常用的实现类
-6.3-常用算法
--常用算法
-6.4-数组实用方法
-6.5-基于动态数组的类型(Vector, ArrayList)
--基于动态数组的类型(Vector, ArrayList)
-6.6-遍历Collection
-6.7-Map接口及其实现
-6.8-第6章小结
--第6章小结
-课件
--课件
-7.0-导学
--导学
-7.1-绘图
--绘图
-7.2-Swing基础
--Swing基础
-7.3-Swing的层次
--Swing的层次
-7.4-布局管理
--布局管理
-7.5-内部类
--内部类
-7.6-事件处理的基本概念
-7.7-事件派发机制
--事件派发机制
-7.8-顶层容器
--7.8-顶层容器
-7.9-中间层容器(一)
-7.10-中间层容器(二)
-7.11-原子组件(一)
-7.12-原子组件(二)
-7.13-原子组件(三)
-7.14-其它Swing特性
-7.15-第7章小结
-课件
--课件