有时会遇到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类代码如下:

  1. package human;
  2.  
  3. public class Person {
  4. String name;
  5. int age;
  6.  
  7. public Person() {
  8.  
  9. }
  10. public Person(String n, String g) {
  11. name = n;
  12. gender = g;
  13. }
  14.  
  15. //test:this作返回值
  16. Person reThis1() {
  17. Person per = new Person("lu","female");
  18. System.out.println("reThis1 per:" + per.name);
  19. return this;
  20. }
  21. Person reThis2() {
  22. Person per = reThis1();
  23. System.out.println("reThis2 per:" + per.name);
  24. return this;
  25. }
  26. Person reThis3() {
  27. name = "ma";
  28. return this;
  29. }
  30. static void equRefer(Person per1, Person per2) {
  31. if(per1 == per2)
  32. System.out.println("per1指向的对象没有改变,仍与per2指向同一个对象");
  33. else
  34. System.out.println("per1指向的对象已改变,与per2指向不同的对象");
  35. System.out.println("per1:" + per1.name);
  36. System.out.println("per2:" + per2.name);
  37. }
  38.  
  39. public static void main(String[] args) {
  40. Person per1 = new Person("liu","female");
  41. Person per2 = per1;
  42.  
  43. per1 = per1.reThis1();
  44. Person.equRefer(per1, per2);
  45.  
  46. per1 = per1.reThis2();
  47. Person.equRefer(per1, per2);
  48.  
  49. System.out.println("调用reThis3之前,per1.name=" + per1.name);
  50. per1 = per1.reThis3();
  51. System.out.println("调用reThis3之后,per1.name=" + per1.name);
  52. }
  53. }

Student类代码如下:

  1. package human;
  2.  
  3. public class Student extends Person {
  4. String stuNumber;
  5. int score;
  6.  
  7. public Student(String n, String g) {
  8. super(n,g);
  9. }
  10.  
  11. Person reThis1() {
  12. Person per = new Person("luPS","female");
  13. System.out.println("reThis1 per S:" + per.name);
  14. return this;
  15. }
  16.  
  17. Student reThis2() {
  18. Person per = reThis1();
  19. System.out.println("reThis2 per S:" + per.name);
  20. return this;
  21. }
  22.  
  23. }

TestMain类如下:

  1. //http://www.cnblogs.com/chanchan/p/7812166.html
    package human;
  2.  
  3. public class TestMain {
  4. public static void main(String[] args) {
  5.  
  6. Person per1 = new Person("liuP","female");
  7. Person per2 = per1;
  8. Person per3;
  9. Person per4;
  10. Student stu1 = new Student("liuS","female");
  11. Student stu2 = stu1;
  12.  
  13. //追加2017.11.25
  14. per1 = stu1.reThis3();
  15. if( per1 == stu1 )
  16. System.out.println("per1与stu1指向同一个子类对象");
  17. else
  18. System.out.println("per1与stu1指向不同的对象");
  19.  
  20. per1 = stu1.reThis1();
  21. if( per1 == stu1 )
  22. System.out.println("per1与stu1指向同一个子类对象");
  23. else
  24. System.out.println("per1与stu1指向不同的对象");
  25.  
  26. per3 = stu1;
  27. per4 = per3.reThis3();
  28. if( per4 == per3 )
  29. System.out.println("per4与per3指向同一个子类对象");
  30. else
  31. System.out.println("per4与per3指向不同的对象");
  32.  
  33. per3 = stu1;
  34. per4 = per3.reThis1();
  35. if( per4 == per3 )
  36. System.out.println("per4与per3指向同一个子类对象");
  37. else
  38. System.out.println("per4与per3指向不同的对象");
  39.  
  40. per3 = stu1;
  41. stu1 = (Student) per3.reThis2(); //向下转型
  42. if( stu1 == per3 )
  43. System.out.println("stu1与per3指向同一个子类对象");
  44. else
  45. System.out.println("stu1与per3指向不同的对象");
  46. }
  47.  
  48. }

输出结果如下:

  1. reThis1 per:lu
  2. per1指向的对象没有改变,仍与per2指向同一个对象
  3. per1:liu
  4. per2:liu
  5. reThis1 per:lu
  6. reThis2 per:liu
  7. per1指向的对象没有改变,仍与per2指向同一个对象
  8. per1:liu
  9. per2:liu
  10. 调用reThis3之前,per1.name=liu
  11. 调用reThis3之后,per1.name=ma

追加(11.26)

输出结果如下:

  1. per1stu1指向同一个子类对象
  2. reThis1 per S:luPS
  3. per1stu1指向同一个子类对象
  4. per4per3指向同一个子类对象
  5. reThis1 per S:luPS
  6. per4per3指向同一个子类对象
  7. reThis1 per S:luPS
  8. reThis2 per S:maP
  9. stu1per3指向同一个子类对象

(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作为返回值时返回的是什么的更多相关文章

  1. Java 学习笔记(14)—— 文件操作

    java文件操作主要封装在Java.io.File中,而文件读写一般采用的是流的方式,Java流封装在 java.io 包中.Java中流可以理解为一个有序的字符序列,从一端导向到另一端.建立了一个流 ...

  2. Java学习笔记14(面向对象七:final、static)

    final:意为最终,不可变,是一个修饰词 有时候一个类地功能被开发好了,不想让子类重写,修改,这里就会用到final关键字 final修饰类: 不可以被继承,但是可以继承其他类 示例: public ...

  3. SQL反模式学习笔记14 关于Null值的使用

    目标:辨别并使用Null值 反模式:将Null值作为普通的值,反之亦然 1.在表达式中使用Null: Null值与空字符串是不一样的,Null值参与任何的加.减.乘.除等其他运算,结果都是Null: ...

  4. [C++学习笔记14]动态创建对象(定义静态方法实现在map查找具体类名对应的创建函数,并返回函数指针,map真是一个万能类)good

    [C++学习笔记14]动态创建对象   C#/Java中的反射机制 动态获取类型信息(方法与属性) 动态创建对象 动态调用对象的方法 动态操作对象的属性 前提:需要给每个类添加元数据 动态创建对象 实 ...

  5. 《Java学习笔记(第8版)》学习指导

    <Java学习笔记(第8版)>学习指导 目录 图书简况 学习指导 第一章 Java平台概论 第二章 从JDK到IDE 第三章 基础语法 第四章 认识对象 第五章 对象封装 第六章 继承与多 ...

  6. Java学习笔记4

    Java学习笔记4 1. JDK.JRE和JVM分别是什么,区别是什么? 答: ①.JDK 是整个Java的核心,包括了Java运行环境.Java工具和Java基础类库. ②.JRE(Java Run ...

  7. java学习笔记11--集合总结

    java学习笔记系列: java学习笔记10--泛型总结 java学习笔记9--内部类总结 java学习笔记8--接口总结 java学习笔记7--抽象类与抽象方法 java学习笔记6--类的继承.Ob ...

  8. java学习笔记8--接口总结

    接着前面的学习: java学习笔记7--抽象类与抽象方法 java学习笔记6--类的继承.Object类 java学习笔记5--类的方法 java学习笔记4--对象的初始化与回收 java学习笔记3- ...

  9. 并发编程学习笔记(14)----ThreadPoolExecutor(线程池)的使用及原理

    1. 概述 1.1 什么是线程池 与jdbc连接池类似,在创建线程池或销毁线程时,会消耗大量的系统资源,因此在java中提出了线程池的概念,预先创建好固定数量的线程,当有任务需要线程去执行时,不用再去 ...

随机推荐

  1. 【swift-总结】函数

    swift的函数在swift2中的使用改变了不少 /** *param: personName 參数 *returns: String为返回值 */ func sayHello(personName: ...

  2. Android长按事件和点击事件问题处理,OnItemLongClickListener和OnItemClickListener冲突问题

    今天在做demo时,须要设置ListView的item的长按和点击事件.OnItemLongClickListener和OnItemClickListener,然而点击事件能够实现,可是在长按操作时会 ...

  3. redmine工作流程总结

    1.需求调研员和測试员新建问题,问题跟踪为支持,指派给产品经理 2.产品经理对收到的问题进行分类处理,功能类型的,改动跟踪状态为功能,指派给自己.是bug类型的,将跟踪类型改动错误类型,指派给技术经理 ...

  4. Objective-C 和 Swift 混编项目的小 Tips(一)

    本文主要闲聊一些 Objective-C 和 Swift 混编项目带来的一些潜规则,希望能帮到对此感到疑惑的朋友.下面我们开始进入主题: 命名 官方 Guide 上只是简单叙述(Using Swift ...

  5. SSM学习(三)--集成spring mvc

    spirng mvc是一个mvc框架,与struts2类似,都是基于Servlet封装而成的框架,所以要了解spring mvc或者struts2比需先了解Servlet,本篇我们先把spring m ...

  6. flask中的session,render_template()第二和参数是字典

    1. 设置一个secret_key 2.验证登入后加上session,这是最简单,不保险 . 3.注意render_template传的参数是字典

  7. Netty学习笔记(一):接收nodejs模拟表单上传的文件

    好久不写博客了,也好久不写代码了,这两天临时遇上一个事情,觉得不难,加上觉得手有些生,就动手做了一下,结果遇上了不少坑,有新坑,有老坑,痛苦无比,现在总算差不多了,赶紧记录下来,希望以后不再重复这种痛 ...

  8. 【MySQL】查看支持的引擎show engines;

  9. Spring框架(四)AOP面向切面编程

    一.前言 在以前的项目中,很少去关注spring aop的具体实现与理论,只是简单了解了一下什么是aop具体怎么用,看到了一篇博文写得还不错,就转载来学习一下,博文地址:http://www.cnbl ...

  10. 关于使用Xcode9.0使用[UIImage imageNamed:]返回null的问题

    最近升级Xcode9.0,没少折腾,再加上iOS11出现的问题,又要适配一些奇怪的问题.这都没啥,但是如果Xcode出问题,那问题可真是难找.因为习惯的操作潜意思的告诉自己这样做是不会错的. 在Xco ...