子类重新实现父类的方法称重写;重写时可以修改访问权限修饰符和返回值,方法名和参数类型及个数都不可以修改;仅当返回值为类类型时,重写的方法才可以修改返回值类型,且必须是父类方法返回值的子类;要么就不修改,与父类返回值类型相同。那么,该如何理解呢?为什么要是父类返回值类型的子类?

作者: 蝉蝉

请尊重作者劳动成果,转载请在标题注明“转载”字样,并标明原文链接:

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---如何理解“子类重写父类方法时,返回值若为类类型,则必须与父类返回值类型相同或为其子类”的更多相关文章

  1. java学习笔记(13) —— google GSON 实现json转化方法

    1.配置struts.xml <action name="getGsonAction" class="com.test.action.json.GetGsonAct ...

  2. 0013 Java学习笔记-面向对象-static、静态变量、静态方法、静态块、单例类

    static可以修饰哪些成员 成员变量---可以修饰 构造方法---不可以 方法---可以修饰 初始化块---可以修饰 内部类(包括接口.枚举)---可以修饰 总的来说:静态成员不能访问非静态成员 静 ...

  3. 疯狂java学习笔记之面向对象(六) - 构造器重载、方法重载和方法重写

    一.方法重载(Overload): Java允许同一个类中定义多个同名方法,只要形参不一样就可以,如果同一个类中包含了两个或两个以上方法名相同的方法,但形参列表不同,则被成为方法重载(两同一异). 同 ...

  4. 【疯狂Java学习笔记】【理解面向对象】

    [学习笔记]1.Java语言是纯粹的面向对象语言,这体现在Java完全支持面向对象的三大基本特征:封装.继承.多态.抽象也是面向对象的重要组成部分,不过它不是面向对象的特征之一,因为所有的编程语言都需 ...

  5. Java学习笔记之深入理解引用

    引言:Java中数据传递的方式,除了基本数据类型是按照值传递,其它类型全部是按照引用传递,这和C++有很大区别,但是很多网上文章都解释的不清楚,甚至是错误的,在查阅资料之后,下面整理出一个比较容易理解 ...

  6. Java学习笔记13(面向对象六:super)

    在创建子类对象时,父类的构造方法会先执行,因为子类中所有构造方法的第一行有默认的隐式super();语句 注意:父类构造方法第一行也有隐式的super(); 所有类都有一个"祖宗类" ...

  7. Java学习笔记-13.创建窗口和程序片

    1.init()方法:程序片第一次被创建,初次运行初始化程序片时调用. start()方法:每当程序片进入web浏览器中,并且允许程序片启动他的常规操作时调用(特殊的程序片被stop()关闭):同样在 ...

  8. Java学习笔记13(equals()方法;toString()方法)

    equals()方法: equals方法是Object类中的方法:Object是所有类的祖宗,所以所有类都有equals()方法: boolean equals(Object obj); equals ...

  9. Java学习笔记10---访问权限修饰符如何控制成员变量、成员方法及类的访问范围

    1.Java有三种访问权限修饰符,分别为public.protected.private,还有一种为缺省权限修饰符的情况,记为default.其中,可以由public和default来修饰类:这四种修 ...

随机推荐

  1. Android架构: MVC 新浪微博

    由于项目的需要,最近研究了一下需要连接网络项目的MVC架构,参考了一下一个新浪微博的开发架构 http://www.open-open.com/lib/view/open1345524526767.h ...

  2. python之集合

    集合(set),它是一个无序的,不重复的数据组合,它是作用如下: 1.去重,也就是去除重复的内容.有一点值得注意的是:将一个列表(list)变成集合的时候,会自动去重. 2.关系测试.测试数据之间的交 ...

  3. 最美时光第三方UWP源码公开

    自己大概写了一个星期的成果.. 使用了官方最美时光app的UI和图片资源,并没有调用官方接口 https://files.cnblogs.com/files/loyieking/NiceCountDo ...

  4. APP在模拟器崩溃,提示__gcd_queue_item_enqueue_hook_block_invoke

    libBacktraceRecording.dylib`__gcd_queue_item_enqueue_hook_block_invoke: libBacktraceRecording.dylib` ...

  5. url编码&&PHP大法

    URL编码 Url编码通常也被称为百分号编码(Url Encoding,also known as percent-encoding),是因为它的编码方式非常简单,使用%百分号加上两位的字符--012 ...

  6. 【机器学习实战】第 10 章 K-Means(K-均值)聚类算法

    第 10 章 K-Means(K-均值)聚类算法 K-Means 算法 聚类是一种无监督的学习, 它将相似的对象归到一个簇中, 将不相似对象归到不同簇中.相似这一概念取决于所选择的相似度计算方法.K- ...

  7. R学习笔记 第四篇:函数,分支和循环

    变量用于临时存储数据,而函数用于操作数据,实现代码的重复使用.在R中,函数只是另一种数据类型的变量,可以被分配,操作,甚至把函数作为参数传递给其他函数.分支控制和循环控制,和通用编程语言的风格很相似, ...

  8. .5-Vue源码之AST(1)

    讲完了数据劫持原理和一堆初始化 现在是DOM相关的代码了 上一节是从这个函数开始的: // Line-3924 Vue.prototype._init = function(options) { // ...

  9. javascript 之执行环境-08

    概念 执行环境(Execution context,简称EC)或执行上下文对象(后面统一用执行上下文表示),它定义了变量或者函数有权访问的其他数据,决定了他们各自的行为.是不是有点不好理解,那我先简单 ...

  10. 如何在 Apple TV 上使用描述文件

    您可以使用 OS X 上的 Apple Configurator 在 Apple TV 上安装配置描述文件. 开始前,请在 Mac 上安装最新版本的 Apple Configurator(如果尚未安装 ...