本文内容参考自Java8标准
前言:可看可不看
当年我决定自学Java的时候,这个this关键字曾经困扰了我很久,我怎么都没有办法理解"当前对象"等,都是"当前"…,后来我理解了,用"当前"表述其实没有什么问题,只是对于初学者来说,理解起来会有很大的问题。
下面的内容可能会有一点啰嗦
还是要从前面我写过的博文中的基础知识说起:
先来回顾一下Java的编程过程:
⑴、首先就是创建新的数据类型:类
// 创建新的数据类型:类
//创建一个人类(Person):比较通俗易懂
public class Person{
//表示人类的姓名:
private String name;
//表示人类的性别:
//private String sex;
//表示人类的年龄
private int age;
//如果有必要,创建构造方法。
//也可以不创造构造方法,直接使用默认构造方法。
public Person(){}
//创建一些与人类行为有关的方法:
//方法一:
//...此处省略具体的方法内容。
//方法二:
//...此处省略具体的方法内容。
//...可以有很多的方法
}
⑵、利用现成的类创建对象,按需改变变量的值或调用对应的方法来实现功能。
这里有一点很重要,就是能创建很多个对象,所以有很多书中会将this解释为是当前对象。
// 创建对象,改变变量,调用方法。
//创建对象:
Person p = new Person();
//改变变量:
p.name = "小王";
//调用方法(假设有一个work()方法):
p.work();
//代码直至到这里都没有什么问题。
⑶、执行代码,得出结果。
来,我们再回顾一下⑵:你会发现在⑵中,首先是Person p = new Person(),然后利用p去修改的变量,利用p去调用的方法。那么p是什么呢?p是你创建当前Person对象的时候给这个对象的存储空间取的名称,这个对象的存储空间中拥有Person类中的所有变量和所有方法,所以你可以利用这个存储空间的名称p去修改变量和调用方法。以实现你需要的功能,同时p.name,p.work()正是Java面向对象编程的代码体现。
那么问题来了:
如果你对上面的解释还是不明白,那我再用另外的方式解释一下:
如果你对上面的解释还是不明白,那我再再用另外的方式解释一下:
如果你对上面的解释还是不明白,我再用生活中的一个例子举例:
不能保证完全贴切,但是比较形象:
一家餐饮店很有名,每天都爆满,座位很稀缺,那么肯定会出现占座的情况,于是店主就为先来的人提供了专门占座的东西(为朋友占座)—一个靠枕,那么这个靠枕代表的就是即将要来的这个人(还没有来,也就是没有具体的对象,所以这个靠枕就是this),过了十五分钟,来了一个人,名字叫小王(这个时候通过Person p = new Person()创建了一个具体的对象,代表了小王),那么很显然,这个靠枕代表的就是小王,如果来的是小李,那么这个靠枕代表的就是小李。所以,为什么说this代表的是当前对象了。
最后,再通过代码来解释一下this:
// 代码解释this:
public class Person{
//表示人类的姓名:
private String name;
//表示人类的性别:
//private String sex;
//表示人类的年龄
private int age;
//创空建构造方法。
public Person(){}
//创建有形式参数的构造方法:
public Person(String name,String sex,int age){
//这个方法体要实现的内容就是将实际参数赋值给类变量
//那么类变量怎么表示?这个时候还没有具体的对象引用名称。
//如果有就用具体的对象引用名称,问题是现在没有,只能用this暂时代替
this.name = name;
this.sex = sex;
this.age = age;
//当你创建对象的时候,具体的对象的name,sex,age的值
//都会是你创建对象时实际输入的值。
//Person p = new Person("小王","男",25);对象p的name,sex,age
//分别是"小王","男",25.
//Person p1 = new Person("小刘","女",23);对象p1的name,sex,age
//分别是"小刘","女",23.
//一一对应的。
}
//创建一些与人类行为有关的方法:
//方法eat(),代表吃饭。
public void eat(){
//方法体省略。
}
//方法work(),代表工作。
public void work(){
//如果这个时候类中的work()方法想调用eat()方法如何操作呢?
//对,用this暂时代替实际的对象引用去调用。
this.eat();
//其他方法体内容省略...
}
}
最后,简单总结一句:因为在创建类的时候,没有具体的对象,也就是没有具体的对象标识符,所以暂时用this代替!在创建类的时候,在你需要使用对象标识符的地方全部使用this!
以下内容为Java编程思想第四版中对this关键字的解释
如果有同一类型的两个对象,分别是a和b,你可能想知道,如何才能让这两个对象调用同一个方法呢(比如下面举例的peel()方法)?
代码举例:
// 代码举例
class Banana{
void peel(int i){
//方法体
}
}
public class BananaPeel{
public static void main(String[] args){
Banana a = new Banana(),
b = new Banana();
a.peel(1);
b.peel(2);
}
}
如果只有一个peel()方法,它如何知道是被a还是被b所调用的呢?
为了能用简便、面向对象的语法来编写代码--------即"发送消息给对象",编译器做了一些幕后工作,它暗自把"所操作对象的引用"作为第一个参数传递给peel(),所以,在幕后,上述两个方法调用就变成了这样:
Banana.peel(a,1);
Banana.peel(b,2);
提示:个人认为,这是在编译以后,编译器做好的幕后工作。编译以后,编译器将所有的引用分别作为所有方法的第一个参数放进了方法中。
这是内部的表示形式,我们并不能这样书写代码,并试图通过编译。
假设你希望在方法内部获得对当前对象的引用,由于这个引用是由编译期"偷偷"传入的。所以没有标识符可用。但是,为此,有个专门的关键字:this。this关键字只能在方法内部使用,表示对"调用方法的那个对象"的引用。this的用法和其他对象引用并无不同。但要注意,如果在方法的内部调用同一个类的另一个方法,就不必使用this,直接调用既可,当前方法中的this引用会自动引用于同一个类的另一个方法。
代码示例:
// 同一个类中的方法互调
//类名称Apricot
public class Apricot{
//方法pick();
void pick(){}
//方法pit()
void pit(){
//直接调用方法pick(),不用this.
pick();
}
}
在pit()内部,你可以写this.pick(),但无此必要,编译器能帮你自动添加,只有当需要明确指出对当前对象的引用时,才需要使用this关键字,例如,当需要返回对当前对象的引用时,就常常在return语句里这样写:
// 返回当前对象的引用
//类名称Leaf
public class Leaf{
//int类型变量i,初始化为0.
int i = 0;
//方法increment(),返回类型为Leaf.
Leaf increment(){
//i值+1.
i++;
//返回当前对象的引用.
return this;
}
//方法print()
void print(){
//打印i值。
Syatem.out.print("i="+i);
}
//程序执行入口方法main()
public static void main(String[] args){
//创建Leaf对象,名称为x。
Leaf x = new Leaf();
//多次调用方法increment()。
//调用一次i值就+1.
//因为调用increment()方法的结果就是返回当前对象。
//所以可以进行多次调用.
//也就是在同一条语句里对同一个对象执行多次操作。
x.increment().increment().increment().print();
}
}
this关键字返回了对当前对象的引用,所以很容易在一条语句里对同一个对象执行多次操作。
this关键字对于将当前对象传递给其他方法也很有用:
// 将当前对象传递给其他方法
//类Person
class Person{
//方法eat,带形式参数Apple类型。
public void eat(Apple apple){
//调用方法获得一个对象。
Apple peeled = apple.getPeeled();
//打印字符串"Yummy".
System.out.print("Yummy");
}
}
//类Peeler
class Peeler{
//静态类方法peel,带一个形式参数类型Apple.
static Apple peel(Apple apple){
//返回当前参数引用,也就是apple。
return apple;
}
}
//类Apple
class Apple{
//方法getPeeled,返回类型为Apple.
Apple getPeeled(){
//返回类型为Apple类型,Peeler.peel(this)返回的类型就是Apple。
//将当前对象的引用作为实际参数传入(this代表的就是当前对象的引用)
return Peeler.peel(this);
}
//Apple调用了外部的方法(Peeler的peel()方法),有的时候你必须这么做,
//将执行由于某种原因而必须放在Apple外部的操作(比如你不想重复代码,
//将一个功能专门写在了一个类中),为了将其自身传递给外部方法,
//必须使用关键字this。
//如果不懂上面的举例:可能存在一个工具类,专门接受对象的引用,
//然后执行相应的代码。这种工具类都会是外部类,而并不是每次需要的时候
//都写一遍。相对于每次写一遍,我们更愿意只传递一个引用。
}
//类PassingThis
public class PassingThis{
//程序执行入口方法main.
public static void main(String[] args){
//创建Person对象,调用eat方法,传入的实际对象是一个Apple对象。
new Person().eat(new Apple());
//解析一下执行结果,从这里开始梳理程序执行代码顺序。
//首先是创建了Person对象,但是Person没有构造方法。
//而是直接调用了eat()方法。eat()方法需要一个Apple类型的参数。
//所以直接创建了一个Apple对象,Apple也没有构造方法。
//直接进入了eat方法体。
//Apple peeled = apple.getPeeled();通过Apple类型的getPeeled()
//方法获得了一个Apple对象,引用名称是peeled.
//进入Apple的getPeeled()方法:return Peeler.peel(this);
//直接进入的是Peeler类的peel方法,同时传入了一个引用this,这个this
//实际代表的就是new Person().eat(new Apple());里面的new Apple();
//这个对象的引用。
//Peeler的peel方法需要一个Apple类型的对象作为实际参数,
//返回这个对象的引用。
//这段代码就是为了演示而创建的。实际到最后就是返回了new
//Person().eat(new Apple());中new Apple()创建的这个对象的引用。
//结果只会打印一个"Yummy"字符串。
}
}
PS:时间有限,有关Java SE的内容会持续更新!今天就先写这么多,如果有疑问或者有兴趣,可以加QQ:2649160693,并注明CSDN,我会就博文中有疑义的问题做出解答。同时希望博文中不正确的地方各位加以指正!