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

作者: 蝉蝉

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

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. Codeforces A. Trip For Meal

    A. Trip For Meal time limit per test 1 second memory limit per test 512 megabytes input standard inp ...

  2. migo的增强

    migo的增强 所用BADI:MB_MIGO_BADI   具体见例子:(SE19) CIN_PLUG_IN_TO_MIGO JVA_CRP_MIGO_BADI JV_CRP_MIGO_BADI WB ...

  3. 测试String.Format中的Format参数

    DateTime datetime = DateTime.Now; Console.WriteLine(String.Format("{0:d}", datetime)); // ...

  4. springcloud之服务注册与发现(Eureka)

    springcloud服务注册与发现 使用Eureka实现服务治理 作用:实现服务治理(服务注册与发现) 简介: Spring Cloud Eureka是Spring Cloud Netflix项目下 ...

  5. 深入理解Java中的迭代器

    迭代器模式:就是提供一种方法对一个容器对象中的各个元素进行访问,而又不暴露该对象容器的内部细节. 概述 Java集合框架的集合类,我们有时候称之为容器.容器的种类有很多种,比如ArrayList.Li ...

  6. 基于Hadoop(M/R)的MySQL到Oracle海量数据切割

    # 背景介绍 大数据时代,海量数据的迁移会很普遍地出现在各个应用场景,本文主要讨论利用Sqoop的分布式能力从关系型数据库MySQL到Oracle的海量数据迁移和切割. # 所需环境 1 JDK+Ec ...

  7. 深入理解Java虚拟机--中

    深入理解Java虚拟机--中 第6章 类文件结构 6.2 无关性的基石 无关性的基石:有许多可以运行在各种不同平台上的虚拟机,这些虚拟机都可以载入和执行同一种平台无关的字节码(ByteCode),从而 ...

  8. 28款GitHub最流行的开源机器学习项目

    现在机器学习逐渐成为行业热门,经过二十几年的发展,机器学习目前也有了十分广泛的应用,如:数据挖掘.计算机视觉.自然语言处理.生物特征识别.搜索引擎.医学诊断.DNA序列测序.语音和手写识别.战略游戏和 ...

  9. IT连创业系列:说说苹果商店AppStore上架App应用前后遇到的那些神坑

    前言: IT连创业的这个系列,又隔空了一个多月了. 不知道为什么,最近写文的冲动感下降了很多,如果不是因为特别忙,大概就因为上了年纪的原因了. 群里关注我创业的朋友,一直都在问,啥时候有新的文章讲述创 ...

  10. Lua中使用table实现的其它5种数据结构

    Lua中使用table实现的其它5种数据结构 lua中的table不是一种简单的数据结构,它可以作为其他数据结构的基础,如:数组,记录,链表,队列等都可以用它来表示. 1.数组 在lua中,table ...