Java学习笔记14---this作为返回值时返回的是什么
有时会遇到this作为返回值的情况,那么此时返回的到底是什么呢?
返回的是调用this所处方法的那个对象的引用,读起来有点绕口哈,有没有想起小学语文分析句子成份的试题,哈哈。
一点点分析的话,主干是“返回的是引用”;
什么引用呢?“那个对象的引用”;
哪个对象呢?“调用方法的那个对象”;
调用的哪个方法呢?“调用的是this所位于的方法”;这样就清楚了。
再总结一下就是,this作为返回值时,返回的是调用某方法的对象的引用,这个方法正是包含“return this;”这行命令的那个方法;更简单点说,就是谁调用返回的就是谁。由于返回的是对象引用,所以this不能用在静态成员方法中,只能在非静态成员方法中出现。
为了更清楚、直观的理解问题,下面以简单的例子说明。
作者: 蝉蝉
请尊重作者劳动成果,转载请在标题注明“转载”字样,并标明原文链接:
http://www.cnblogs.com/chanchan/p/7812166.html
追加(11.26):
添加了下面5项测试代码:
(1).子类对象调用父类中返回this的方法,该方法未被子类重写
(2).子类对象调用父类中返回this的方法,该方法已被子类重写,且返回值类型与父类返回值类型一致
(3).父类对象引用指向子类对象时,即向上转型时,父类对象引用调用未被子类重写的返回this的方法
(4).向上转型时,父类对象引用调用被子类重写的返回this的方法,且返回值与父类返回值类型一致
(5).向上转型时,父类对象引用调用被子类重写的返回this的方法,且返回值类型为父类返回值类型的子类
分析见后文
(11.26)
包human中定义了Person类、Student类及测试类TestMain,其中Student是Person的子类。
Person类代码如下:
package human; public class Person {
String name;
int age; public Person() { }
public Person(String n, String g) {
name = n;
gender = g;
} //test:this作返回值
Person reThis1() {
Person per = new Person("lu","female");
System.out.println("reThis1 per:" + per.name);
return this;
}
Person reThis2() {
Person per = reThis1();
System.out.println("reThis2 per:" + per.name);
return this;
}
Person reThis3() {
name = "ma";
return this;
}
static void equRefer(Person per1, Person per2) {
if(per1 == per2)
System.out.println("per1指向的对象没有改变,仍与per2指向同一个对象");
else
System.out.println("per1指向的对象已改变,与per2指向不同的对象");
System.out.println("per1:" + per1.name);
System.out.println("per2:" + per2.name);
} public static void main(String[] args) {
Person per1 = new Person("liu","female");
Person per2 = per1; per1 = per1.reThis1();
Person.equRefer(per1, per2); per1 = per1.reThis2();
Person.equRefer(per1, per2); System.out.println("调用reThis3之前,per1.name=" + per1.name);
per1 = per1.reThis3();
System.out.println("调用reThis3之后,per1.name=" + per1.name);
}
}
Student类代码如下:
package human; public class Student extends Person {
String stuNumber;
int score; public Student(String n, String g) {
super(n,g);
} Person reThis1() {
Person per = new Person("luPS","female");
System.out.println("reThis1 per S:" + per.name);
return this;
} Student reThis2() {
Person per = reThis1();
System.out.println("reThis2 per S:" + per.name);
return this;
} }
TestMain类如下:
//http://www.cnblogs.com/chanchan/p/7812166.html
package human; public class TestMain {
public static void main(String[] args) { Person per1 = new Person("liuP","female");
Person per2 = per1;
Person per3;
Person per4;
Student stu1 = new Student("liuS","female");
Student stu2 = stu1; //追加2017.11.25
per1 = stu1.reThis3();
if( per1 == stu1 )
System.out.println("per1与stu1指向同一个子类对象");
else
System.out.println("per1与stu1指向不同的对象"); per1 = stu1.reThis1();
if( per1 == stu1 )
System.out.println("per1与stu1指向同一个子类对象");
else
System.out.println("per1与stu1指向不同的对象"); per3 = stu1;
per4 = per3.reThis3();
if( per4 == per3 )
System.out.println("per4与per3指向同一个子类对象");
else
System.out.println("per4与per3指向不同的对象"); per3 = stu1;
per4 = per3.reThis1();
if( per4 == per3 )
System.out.println("per4与per3指向同一个子类对象");
else
System.out.println("per4与per3指向不同的对象"); per3 = stu1;
stu1 = (Student) per3.reThis2(); //向下转型
if( stu1 == per3 )
System.out.println("stu1与per3指向同一个子类对象");
else
System.out.println("stu1与per3指向不同的对象");
} }
输出结果如下:
reThis1 per:lu
per1指向的对象没有改变,仍与per2指向同一个对象
per1:liu
per2:liu
reThis1 per:lu
reThis2 per:liu
per1指向的对象没有改变,仍与per2指向同一个对象
per1:liu
per2:liu
调用reThis3之前,per1.name=liu
调用reThis3之后,per1.name=ma
追加(11.26)
输出结果如下:
per1与stu1指向同一个子类对象
reThis1 per S:luPS
per1与stu1指向同一个子类对象
per4与per3指向同一个子类对象
reThis1 per S:luPS
per4与per3指向同一个子类对象
reThis1 per S:luPS
reThis2 per S:maP
stu1与per3指向同一个子类对象
(11.26)
逐句分析执行过程:
(1).第1句:Person per1 = new Person("liu","female");
创建一个Person对象,将name初始化为“liu”,gender初始化为“female”,并让per1指向该对象。
(2).第2句:Person per2 = per1;
定义一个Person类的对象引用,并与per1指向同一个对象;具体内存分配见图1:
(3).第3句:per1 = per1.reThis1();
由per1调用reThis1()方法,并将返回值赋给per1;reThis1()方法体内定义了一个局部变量per,并创建一个对象,由per指向它;具体内存分配见图2:
紧接着输出reThis1 per:lu;最后返回this,并把返回的值赋给per1。
(4).第4句:Person.equRefer(per1, per2);
调用equRefer(per1,per2)来验证per1的值并未改变;根据下面的输出结果也可知per1仍与per2指向原来的对象,也就是说此时this的值与per1的值是一致的;也可以说,谁调用的返回的就是谁。
输出结果:
per1指向的对象没有改变,仍与per2指向同一个对象
per1:liu
per2:liu
此时的内存图如图3:
(5).第5句:per1 = per1.reThis2();
per1调用reThis2(),由(4)可推测,此时per1的值也不会变,是由per1调用的this所处的方法,所以返回的也是per1;具体来分析的话,reThis2()定义了一个局部变量per,并给其赋值为reThis1(),也就是说reThis2()调用了reThis1(),由(3)、(4)可推知,此时的内存结构是下面这样的:
局部变量per指向的对象与per1是一致的,因为调用reThis1的对象是per1所指的对象,所以返回值也是per1。
此处的输出结果为:
reThis1 per:lu
reThis2 per:liu
(6).第6句:Person.equRefer(per1, per2);
验证上面的结论,per1指向没变,此时的内存分配图如图4所示:
(7).第7、8、9句:
System.out.println("调用reThis3之前,per1.name=" + per1.name);
per1 = per1.reThis3();
System.out.println("调用reThis3之后,per1.name=" + per1.name);
per1调用reThis3();reThis3()中修改了namer的值,由"liu"改为"ma",然后返回this。
调用前后的内存结构分别如图6、图7所示:
输出结果:
调用reThis3之前,per1.name=liu
调用reThis3之后,per1.name=ma
再一次验证了上述的结论。
追加(11.26)
结果分析:
从结果可以看到,返回值与调用方法的对象引用是一致的,是指向同一个子类对象的;
也就是说,即使是由子类来调用父类的返回this的方法,不论子类有没有重写该方法,返回值都是指向调用该方法的子类对象的;
当由指向子类对象的父类对象引用来调用返回this的方法时,同样的,返回值也都指向了 调用该方法的 父类对象引用 所指向的子类对象;
当子类重写了父类的返回this的方法时,且返回值类型是父类返回值类型的子类,这时返回值同上,不过这里涉及到向下转型,代码中已标出,有疑问可以参考笔记15。
综上,这些情况下也适用“谁调用返回谁”。
(11.26)
关于为什么使用this,我是这么理解的:由于定义类的时候尚未创建对象,所以不能确定对象到底叫什么,就用this来统一表示,等到具体调用时就可以知道对象的名字了,然后就用对象的引用替换this;所以为了便于记忆,可以理解成谁调用返回的就是谁。
至于返回this有什么意义,我的理解是:记返回this的方法为A,可能A的方法体中对对象的属性做了某些操作或调用了某些方法完成了某些动作,总之,做完这些操作后就把原对象的引用返回,返回后的状态是对象最新的状态,可能与对象调用方法A前不同。
Java学习笔记14---this作为返回值时返回的是什么的更多相关文章
- Java 学习笔记(14)—— 文件操作
java文件操作主要封装在Java.io.File中,而文件读写一般采用的是流的方式,Java流封装在 java.io 包中.Java中流可以理解为一个有序的字符序列,从一端导向到另一端.建立了一个流 ...
- Java学习笔记14(面向对象七:final、static)
final:意为最终,不可变,是一个修饰词 有时候一个类地功能被开发好了,不想让子类重写,修改,这里就会用到final关键字 final修饰类: 不可以被继承,但是可以继承其他类 示例: public ...
- SQL反模式学习笔记14 关于Null值的使用
目标:辨别并使用Null值 反模式:将Null值作为普通的值,反之亦然 1.在表达式中使用Null: Null值与空字符串是不一样的,Null值参与任何的加.减.乘.除等其他运算,结果都是Null: ...
- [C++学习笔记14]动态创建对象(定义静态方法实现在map查找具体类名对应的创建函数,并返回函数指针,map真是一个万能类)good
[C++学习笔记14]动态创建对象 C#/Java中的反射机制 动态获取类型信息(方法与属性) 动态创建对象 动态调用对象的方法 动态操作对象的属性 前提:需要给每个类添加元数据 动态创建对象 实 ...
- 《Java学习笔记(第8版)》学习指导
<Java学习笔记(第8版)>学习指导 目录 图书简况 学习指导 第一章 Java平台概论 第二章 从JDK到IDE 第三章 基础语法 第四章 认识对象 第五章 对象封装 第六章 继承与多 ...
- Java学习笔记4
Java学习笔记4 1. JDK.JRE和JVM分别是什么,区别是什么? 答: ①.JDK 是整个Java的核心,包括了Java运行环境.Java工具和Java基础类库. ②.JRE(Java Run ...
- java学习笔记11--集合总结
java学习笔记系列: java学习笔记10--泛型总结 java学习笔记9--内部类总结 java学习笔记8--接口总结 java学习笔记7--抽象类与抽象方法 java学习笔记6--类的继承.Ob ...
- java学习笔记8--接口总结
接着前面的学习: java学习笔记7--抽象类与抽象方法 java学习笔记6--类的继承.Object类 java学习笔记5--类的方法 java学习笔记4--对象的初始化与回收 java学习笔记3- ...
- 并发编程学习笔记(14)----ThreadPoolExecutor(线程池)的使用及原理
1. 概述 1.1 什么是线程池 与jdbc连接池类似,在创建线程池或销毁线程时,会消耗大量的系统资源,因此在java中提出了线程池的概念,预先创建好固定数量的线程,当有任务需要线程去执行时,不用再去 ...
随机推荐
- 【Win 10 应用开发】MIDI 音乐合成——乐理篇
针对 MIDI 音乐的 API ,其实在 Win 8.1 的时候就出现.在UWP中采用了新的驱动模式,MIDI 消息传递更加高效. 首先得说明的是,UWP 的 MIDI 相关 API 不是针对 MID ...
- Cocos2d-x 3.0 Android改动APK名、更改图标、改动屏幕方向、改动版本,一些须要注意的问题
非常多新手程序员做出一个游戏后,编译成apk安装在手机上.却发现安装程序名和游戏图标都是Cocos2dx默认的,并且默认屏幕方向是横向.那么须要怎么才干改动为自己想要的呢? 打开你创建的project ...
- MyBatis SQL处理大于、小于号
MyBatis mapper文件是xml文件,需要特殊字符如大于号.小于号后需要转义. 原字符 转义后字符 < < <= <= > > > >=
- JAVA IO分析三:IO总结&文件分割与合并实例
时间飞逝,马上就要到2018年了,今天我们将要学习的是IO流学习的最后一节,即总结回顾前面所学,并学习一个案例用于前面所学的实际操作,下面我们就开始本节的学习: 一.原理与概念 一.概念流:流动 .流 ...
- 60、jQuery其余操作
上篇主要介绍了jQuery,和一些基本用法,这篇主要讲解动画.常用事件.还有一些jQuery的补充内容. 本篇导航: 动画 常用事件 插件 jQuery API 中文文档 一.动画 1.基本 show ...
- [译文]React v16(新特性)
[译文]React v16(新特性) 查看原文内容 我们很高兴的宣布React v16.0发布了! 这个版本有很多长期被使用者期待的功能,包括: fragments (返回片段类型) error bo ...
- 智能合约语言 Solidity 教程系列6 - 结构体与映射
写在前面 Solidity 是以太坊智能合约编程语言,阅读本文前,你应该对以太坊.智能合约有所了解, 如果你还不了解,建议你先看以太坊是什么 本系列文章一部分是参考Solidity官方文档(当前最新版 ...
- iOS UITabView简写瀑布流
代码demo 一.tabViewCell,通过image的比例高算出cell 的高度 #import "TableViewCell.h" @implementation Table ...
- 本地如何操作服务器的mysql,详细教程
前置条件: 1.在阿里云服务器de系统是win service 2012. 2.服务器里自己安装了my sql 5.7 3.本地也安装了my sql 5.7 需求:想通过本地的mysql连接上远程的服 ...
- IT服务(运维)管理实施的几个要点--第一章 IT服务质量的标准
子曰"干的最好就是个60分,稍有纰漏就是不及格" 谈一个事情,最先要谈的就是统一标准,又或者这个标准已经约定俗成,广泛认可,所以就可以略过.对于IT服务质量来说,确实有一个统一的标 ...