Java学习笔记13---如何理解“子类重写父类方法时,返回值若为类类型,则必须与父类返回值类型相同或为其子类”
子类重新实现父类的方法称重写;重写时可以修改访问权限修饰符和返回值,方法名和参数类型及个数都不可以修改;仅当返回值为类类型时,重写的方法才可以修改返回值类型,且必须是父类方法返回值的子类;要么就不修改,与父类返回值类型相同。那么,该如何理解呢?为什么要是父类返回值类型的子类?
作者: 蝉蝉
请尊重作者劳动成果,转载请在标题注明“转载”字样,并标明原文链接:
http://www.cnblogs.com/chanchan/p/7796472.html
还是先看示例,详见下文。
包human中定义了三个类,Person类、Student类和TestMain类,其中Student类是Person类的子类。代码分别如下:
Person类的代码如下:
package human; public class Person {
String name;
int age; //test:重写
public Person overRide() {
Person per = new Person();
per.name = "liu"; return per;
}
}
Student类重写了父类的overRide()方法,代码如下:
package human; public class Student extends Person {
String stuNumber;
int score; //test:重写
public Student overRide() {
Student stu = new Student();
stu.name = "li"; return stu;
}
}
TestMain类的代码如下:
package human; public class TestMain { public static void main(String[] args) {
Student stu = new Student();
Person per = new Person(); per = stu.overRide();
System.out.println(per.name);
per = per.overRide();
System.out.println(per.name);
}
输出结果为:
li
li
有没有人跟我一样,第一反应输出应该为“li liu”呢,怎么两个都是“li”?
仔细分析一下,看下面的几张内存图就明白了。
第1、第2条语句分别创建一个子类对象和一个父类对象,其中,stu指向子类对象,per指向父类对象。如下面图1所示:
图1
接着执行第3条语句:per = stu.overRide();;
stu先调用overRide(),方法体里创建了一个子类对象,并让临时变量stu指向该对象,其存储位置就是以C为首地址的内存块;
然后把该对象的变量name赋值为“li”;最后返回stu的值并赋给per,也就是说,虽然per是父类对象引用,但最后指向了overRide()里创建的子类对象,这里以蓝色箭头表示; 原先指向的以B为首地址的父类对象这时没有引用指向它,这里把红色箭头变为虚线表示。此时访问per的name,显然是“li”。内存结构见图2:
图2
再接着要执行per = per.overRide();,调用overRide()方法;
由于子类重写了父类的overRide()方法,虽然per为父类对象引用,此时父类的该方法被覆盖,所以此时要调用子类的方法;执行过程同上,per不再指向以C为首地址的子类对象,改为指向新创建的子类对象,以D为首地址,如图3所示。
同上面一样的道理,此时访问per的name仍然为“li”,因为父类的overRide()两次压根都没有被调用到。
图3
修改一下TestMain,如下所示:
package human; public class TestMain { public static void main(String[] args) {
Student stu = new Student();
Person per = new Person();
Person per2 = per;//
per = stu.overRide();
System.out.println(per.name);
per = per.overRide();
System.out.println(per.name);
per2 = per2.overRide();//
System.out.println(per2.name);//
}
此时定义了一个父类对象引用per2,并让它与per指向同一个对象;最后两行,由per2调用overRide()方法,很显然要调用父类的方法,所以方法体中创建的也是父类的对象,再把结果返回给per2,此时per2指向新创建的父类对象,该父类对象的name就为“liu”了。
说了这么多,貌似还没解决开头的问题,为什么是父类返回值类型的子类?为方便说明,记父类的返回值类型为A。
我的理解是,这是为了向上转型;既然子类重写了父类的方法,有时候就需要用父类对象引用来调用子类重写的方法,在上面例子的情况下,也就是说要把A的子类对象引用赋给A的对象引用,如果此时返回值类型不是A类或A的子类,其他类的对象引用是不能赋给A的对象引用的,这样就会出错;所以说,子类重写的方法,如果返回值为类类型,其返回值类型必须与父类返回值类型相同或为父类返回值类型的子类。
不知道有没有说清楚。
PS:例子选得不是特别好,如果返回值类型是与Person和Student不相干的类,可能更好理解,不然容易把返回值的类与方法所属的类混淆。
Java学习笔记13---如何理解“子类重写父类方法时,返回值若为类类型,则必须与父类返回值类型相同或为其子类”的更多相关文章
- java学习笔记(13) —— google GSON 实现json转化方法
1.配置struts.xml <action name="getGsonAction" class="com.test.action.json.GetGsonAct ...
- 0013 Java学习笔记-面向对象-static、静态变量、静态方法、静态块、单例类
static可以修饰哪些成员 成员变量---可以修饰 构造方法---不可以 方法---可以修饰 初始化块---可以修饰 内部类(包括接口.枚举)---可以修饰 总的来说:静态成员不能访问非静态成员 静 ...
- 疯狂java学习笔记之面向对象(六) - 构造器重载、方法重载和方法重写
一.方法重载(Overload): Java允许同一个类中定义多个同名方法,只要形参不一样就可以,如果同一个类中包含了两个或两个以上方法名相同的方法,但形参列表不同,则被成为方法重载(两同一异). 同 ...
- 【疯狂Java学习笔记】【理解面向对象】
[学习笔记]1.Java语言是纯粹的面向对象语言,这体现在Java完全支持面向对象的三大基本特征:封装.继承.多态.抽象也是面向对象的重要组成部分,不过它不是面向对象的特征之一,因为所有的编程语言都需 ...
- Java学习笔记之深入理解引用
引言:Java中数据传递的方式,除了基本数据类型是按照值传递,其它类型全部是按照引用传递,这和C++有很大区别,但是很多网上文章都解释的不清楚,甚至是错误的,在查阅资料之后,下面整理出一个比较容易理解 ...
- Java学习笔记13(面向对象六:super)
在创建子类对象时,父类的构造方法会先执行,因为子类中所有构造方法的第一行有默认的隐式super();语句 注意:父类构造方法第一行也有隐式的super(); 所有类都有一个"祖宗类" ...
- Java学习笔记-13.创建窗口和程序片
1.init()方法:程序片第一次被创建,初次运行初始化程序片时调用. start()方法:每当程序片进入web浏览器中,并且允许程序片启动他的常规操作时调用(特殊的程序片被stop()关闭):同样在 ...
- Java学习笔记13(equals()方法;toString()方法)
equals()方法: equals方法是Object类中的方法:Object是所有类的祖宗,所以所有类都有equals()方法: boolean equals(Object obj); equals ...
- Java学习笔记10---访问权限修饰符如何控制成员变量、成员方法及类的访问范围
1.Java有三种访问权限修饰符,分别为public.protected.private,还有一种为缺省权限修饰符的情况,记为default.其中,可以由public和default来修饰类:这四种修 ...
随机推荐
- ios自定义数字键盘
因为项目又一个提现的功能,textfiled文本框输入需要弹出数字键盘,首先想到的就是设置textfiled的keyboardType为numberPad,此时你会看到如下的效果: 但是很遗憾这样 ...
- win10 uwp 后台获取资源
本文告诉大家,从后台代码获取界面定义的资源. 如果一个资源是写在 App 的资源,那么如何使用代码去获得他? 简单的方法是使用下面的代码 Application.Current.Resources[& ...
- JavaScript注释之HTML注释(<!-- & //-->)
JavaScript中支持HTML注释 //用法 <script language="javascript"> <!-- alert("我是注释内的JS ...
- 转:stringstream的用法
[本文来自]http://www.builder.com.cn/2003/0304/83250.shtmlhttp://www.cppblog.com/alantop/archive/2007/07/ ...
- js 中 new fn与new fn()的区别
在有些代码中,看见了let fn = new Fn()和let fn = new Fn,刚开始有些人或许和我一样感到些许疑惑,但潜意识的也会想到,这两者说不定就是一样的.没错!!在没有参数的情况下这两 ...
- C++内联函数(03)
在C++中我们通常定义以下函数来求两个整数的最大值: 代码如下: int max(int a, int b){ return a > b ? a : b;} 为这么一个小的操作定义一个函数的好处 ...
- JavaScript OOP 之 this指向
今天给大家分享一个JavaScript OOP中关于分辨this指向对象的小技巧,很实用呦! 我们先来看一段代码: 大家能判断出func();和obj.func();这两句的this指向吗? 首先,我 ...
- Jenkins集成taffy进行自动化测试并输出测试报告
本文主要介绍Jenkins集成taffy/nose框架进行自动化测试并输出测试报告方法. 0. 测试环境 Jenkis主节点部署在CentOS系统上,子节点为Win10 64位系统(即我们本机运行自动 ...
- 笔记-64位dump转32位dump
下图是从测试拷64位windbg抓的dump文件拖到32位windbg查看线程堆栈信息的效果. 那么我们加载一下wow64exts模块,因为需要这个模块帮助把64位的dump,转换成32位的dump. ...
- Android Studio 中修改Apk名称
修改生成的apk名称,并且使调试时也可以使用. 在app->build.gradle 中增加以下内容: android.applicationVariants.all { variant-> ...