Java开发笔记(四十九)关键字super的用法
2019-01-21 02:39:05来源:博客园 阅读 ()
前面介绍了如何从Bird类继承而来Swallow类,按道理子类应当继承父类的所有要素,但是对于构造方法来说,Swallow类仅仅继承了Bird类的默认构造方法,并未自动继承带参数的构造方法。如果子类想继续使用父类的其它构造方法,就得自己重写心仪的构造方法。例如老鹰属于鸟类,那么可以编写继承自Bird类的Eagle类,同时要在Eagle类内部重新定义拥有多个输入参数的构造方法,由此得到如下所示的Eagle类代码:
//定义了一个继承自鸟类的老鹰类 public class Eagle extends Bird { // 老鹰类重写了带三个参数的构造方法,则不使用没有输入参数的构造方法 public Eagle(String name, int sexType, String voice) { // 利用super指代父类的构造方法名称 super(name, sexType, voice); } }
注意到如上代码用到了关键字super,它的字面意思是“超级的”,但并非说它是超人,而是用super指代父类的名称,所以这里“super(name, sexType, voice)”实际表达的是“Bird(name, sexType, voice)”,也就是依然利用了Bird类的同名且同参数的构造方法。外部若想创建Eagle类的实例,就要调用新定义的带三个参数的构造方法,此时创建实例的代码如下所示:
// 通过构造方法设置属性值 private static void setConstruct() { // 调用Bird类带三个参数的构造方法 Bird cuckoo = new Bird("杜鹃", 1, "布谷"); System.out.println(cuckoo.toString()); // Eagle类重写了带三个参数的构造方法 Eagle eagle = new Eagle("鹰" , 0, "啁啁"); System.out.println(eagle.toString()); }
在类继承的场合,关键字super表示父类,对应的this表示本类。如同this的用法一般,super不但可用于构造方法,还可作为成员属性和成员方法的前缀,例如“super.属性名称”代表父类的属性,“super.方法名称”代表父类的方法。
在中文世界里,性别名称的“雄”和“雌”专用于野生动物,而家畜、家禽的性别应当采用“公”和“母”,比如公鸡、公牛、母鸭、母猪等等。前述的Bird类,默认的性别名称为“雄”和“雌”,显然并不适用于家禽。为此几种家禽从Bird类派生而来时,需要重新定义它们的性别名称属性,也就是重写setSexType方法,在该方法内部另行对sexName字段赋值。以鸭子类为例,重写方法后的类定义代码如下:
//定义了一个继承自鸟类的鸭子类 public class Duck extends Bird { // 定义一个家禽类的性别名称 private String sexName; public Duck(String name, int sex) { // 利用super指代父类的构造方法名称 super(name, sex, "嘎嘎"); } public void setSexType(int sexType) { // 方法内部再调用自身方法,会变成递归调用,如果没有退出机制就变成死循环了 //setSexType(sexType); // 在方法前面添加前缀“super.”,表示这里调用的是父类的方法 super.setSexType(sexType); // 修改家禽类的性别名称,此时父类和子类都有同名属性sexName,不加前缀的话默认为子类的属性 sexName = (sexType==0) ? "公" : "母"; //this.sexName = (sexType==0) ? "公" : "母"; } // 父类的getSexName方法需要重写,否则父类的方法会使用父类的属性 public String getSexName() { return this.sexName; } // 父类的toString方法需要重写,否则父类的方法会使用父类的属性 public String toString() { String desc = String.format("这是一只%s%s,它会%3$s、%3$s地叫。", this.sexName, getName(), getVoice()); return desc; } }
以上的Duck类代码,看起来颇有些奇特之处,且待下面细细道来:
1、由于Bird类的sexName属性为private类型,表示其为私有属性,不可被子类访问,因此Duck类另外定义自己的sexName属性,好让狸猫换太子。
2、重写后的setSexType方法,只有sexName属性才需额外设置,而sexType属性仍遵循父类的处理方式,故此时要调用父类的setSexType方法,即给该方法添加前缀“super.”。
3、因为Duck类重新定义了sexName属性,所以与sexName有关的方法都要重写,改为读写当前类的属性,否则父类的方法依旧操作父类的属性。
再来看一个以super修饰成员属性的例子,倘若Bird类的sexName属性为public类型,就意味着子类也可访问它,那么Duck类便能通过“super.sexName”操作该属性了。此时新定义的DuckPublic类代码就变成下面这样:
//演示同名的父类属性、子类属性、输入参数三者的优先级顺序 public class DuckPublic extends Bird { public DuckPublic(String name, int sex) { super(name, sex, "嘎嘎"); } public void setSexType(int sexType) { super.setSexType(sexType); // 若想对父类的属性直接赋值,则考虑把父类的属性从private改为public super.sexName = (sexType==0) ? "公" : "母"; // 父类和子类拥有同名属性,则不带前缀的属性字段默认为子类属性 //sexName = (sexType==0) ? "公" : "母"; //this.sexName = (sexType==0) ? "公" : "母"; } private String sexName; public void setSexName(String sexName) { // 输入参数与类的属性同名,则不带前缀的参数字段默认为输入参数 this.sexName = sexName; } }
假设DuckPublic类也定义了同名属性,并且另外实现了setSexName方法,于是该类里面将会出现三个sexName,分别是:super.sexName表示父类的属性,this.sexName表示本类的属性,而setSexName内部的sexName表示输入参数。要是三者同时出现两个,必定有一个需要添加“super”或者“this”的前缀,不然编译器哪知同名字段是啥含义?或者说,假如有一个sexName未加任何前缀,那么编译器应该优先认定它是父类属性,还是优先认定它是本类属性,还是优先认定它是输入参数?对于这些可能产生字段名称混淆的场合,Java制定了下列的优先级判断规则:
1、方法内部存在同名的输入参数,则该字段名称默认代表输入参数;
2、方法内部不存在同名的输入参数,则该字段名称默认代表本类的成员属性;
3、方法内部不存在同名的输入参数,且本类也未重新定义同名的成员属性,则该字段名称只能代表父类的成员属性;
概括地说,对于同名的字段名称而言,其所表达含义的优先级顺序为:输入参数>本类属性>父类属性。
更多Java技术文章参见《Java开发笔记(序)章节目录》
原文链接:https://www.cnblogs.com/pinlantu/p/10279686.html
如有疑问请与原作者联系
标签:
版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有
上一篇:Spring Boot 学习目录
下一篇:Java 插入附件到PDF文档
- 国外程序员整理的Java资源大全(全部是干货) 2020-06-12
- 2020年深圳中国平安各部门Java中级面试真题合集(附答案) 2020-06-11
- 2020年java就业前景 2020-06-11
- 04.Java基础语法 2020-06-11
- Java--反射(框架设计的灵魂)案例 2020-06-11
IDC资讯: 主机资讯 注册资讯 托管资讯 vps资讯 网站建设
网站运营: 建站经验 策划盈利 搜索优化 网站推广 免费资源
网络编程: Asp.Net编程 Asp编程 Php编程 Xml编程 Access Mssql Mysql 其它
服务器技术: Web服务器 Ftp服务器 Mail服务器 Dns服务器 安全防护
软件技巧: 其它软件 Word Excel Powerpoint Ghost Vista QQ空间 QQ FlashGet 迅雷
网页制作: FrontPages Dreamweaver Javascript css photoshop fireworks Flash