黑马程序员——面向对象5:this关键字

来源:互联网 发布:js数组对象去重复 编辑:程序博客网 时间:2024/05/21 10:48

------- android培训、java培训、期待与您交流! ----------

一、this关键字的作用

代码1

class Car{privateString brand;privateint price; Car(String brand){brand = brand;}Car{String brand, int price}{brand = brand;price = price;} public void showInfo(){System.out.println(“brand= ”+ brand +“, price = ”+price);}} class CarDemo{publicstatic void main(String[] args){Carc1 = new Car(“宝马”);c1.showInfo();}}
运行上述代码,结果如下:

num = null, price = 0

       上面的结果表明了一个问题:创建Car对象时传入的实际参数“宝马”虽然赋给了构造函数中的形式参数brand,却并没有赋给堆内存中Car对象的成员变量brand。这是因为方法中的局部变量的指代总是遵循“就近原则”,例如上述代码中本意是将形式参数(局部变量)brand的值赋给对象的成员变量brand,但是由于“就近原则”,方法中的两个brand都指代的是形式参数brand,最后的结果就是形式参数brand将自己的值又赋给了自己。

       上面说了这么多,其实就一句话,“系统”自己是没法区分成员变量和局部变量的,需要程序员手动标识。

这时,就要引入一个新的关键字,“this”,并将上述代码进行修改,

代码2

class Car{private String brand;private int price; Car(String brand){this.brand = brand;}Car{String brand, int price}{this.brand = brand;this.price= price;} public void showInfo(){System.out.println(“brand= ”+ brand +“, price = ”+price);}} class CarDemo{public static void main(String[] args){Carc1 = new Car(“奔驰”);c1.showInfo();}}
加上this后,运行结果是:

num = 奔驰, price = 0


从上面这个结果来看,构造方法中形式参数的值确实赋给了堆内存中Car对象的成员变量num。那么这里就引入可this所代表的含义:this代表本类对象。

那么,可能有的朋友就有疑问了,Car这个类的本类对象多了,只要“new”就有很多,那到底指的是谁呢?请看下面的代码,

代码3

class CarDemo2{public static void main(String[] args){Car c1 = new Car(“丰田”);Car c2 = new Car(“本田”);}}
当创建c1所指向的Car对象时,将“丰田”作为实际参数传给了对应的构造方法,又将这个值赋给了这个构造方法内的形式参数brand,最终通过赋值语句将形式参数(局部变量)的值赋给了c1所指向的堆内存中的Car对象。这里,this就是指代了this所在方法的所属对象,换句话说,this就是指代了this所在方法的调用者。这里因为是c1所指向的对象在调用this所在的构造函数,那么this.brand指的就是c1指向的Car对象内的成员变量brand。下面的c2同理。

大家再思考一个问题,能否把代码改成c1.brand = brand呢?答案是显然是不可以的。

比如,下面的例子,

代码4

class Car{private Car c = new Car(); Car(String brand){c.brand= brand;}} class CarDemo3{public static void main(String[] args){Car c =new Car(“雪铁龙”);}}
这里构造方法c.brand = brand中的c显然不是指的主函数中的c,而是Car对象内部成员变量c,所以,换句话说,在一个对象的内部出了this关键字以外,没有别的办法可以指向本类对象。

 

小知识点1:

       代码2的运行结果是,num = 奔驰, price = 0。为什么c1.showInfo()打印的是c1所指向对象的成员变量值呢?这看起来好像很自然,大家可能会想因为是c1调用的showInfo方法,当然就是打印c1的成员变量值。其实,这里showInfo()方法是有省略的,完整的应该是这样:

System.out.println(“brand= ”+ this.brand +“, price = ”+this.price);

所以大家可以想到,之所以打印c1的成员变量值,其实是因为变量名前都省略了this,而this又是指代本类对象。所以其实,Java中是靠对象去区分成员(包括变量和方法)的所属的。因此,在对象内部调用成员,前面都省略了this。而之所以生了this主要是为了简化代码书写,但随之牺牲就是代码的阅读性了。

  总结:那说了这么多,到底什么时候显示的写this关键字呢?就是在需要指代this所在方法的调用者的时候,换句话说,哪个对象在调用this所在的方法,那么this就代表那个对象。

 

二、this关键字的应用

1. this关键字的第一个用法:代表本类对象

先看一个需求:给手机定义一个用于比较屏幕尺寸是否相同的功能。为代码简练,省去了成员变量的set和get方法,而是直接将成员变量公有,下同。代码如下:

代码5:

class Phone{private float screenSize;private String brand;      Phone(float screenSize){this.screenSize = screenSize;}Phone(String brand){this.brand = brand;}Phone(float screenSize, Stringbrand){this.screenSize = screenSize;this.brand = brand;} public void showInfo(){System.out.println(“brand= ”+brand+“, screenSize = ”+screenSize);} public boolean compare(Phone p){return this.screenSize == p.screenSize;}} class PhoneDemo{public static void main(String[] args){Phone p1 = new Phone(4.7);Phone p2 = new Phone(3.5f);System.out.println(p1.compare(p2));}}
上述代码的运行结果是:false。这里,compare方法内的this就代表了,最后一行输出语句中的p1,因为是p1在调用他自己的compare方法,那么compare方法中的this就代表了调用compare方法的对象——p1。那么,我们再一次强调this的用法:当需要在某个方法中指代这个方法的调用者时,用this关键字来表示这个调用者。大家需要注意的是,与类类型变量一样,无论p1还是this都不是对象本身,而是指向对象的Phone类类型变量。

  大家思考一个问题,上述代码Phone类的compare方法的参数列表能否改成float screenSize呢?从编译以及运行的角度来说当然是可以的。但还是不建议这样做,首先,从直观的理解上,给人一种拿手机对象(本类对象)和另一个手机对象的属性作比较的错觉,不符合生活实际;其次,直接传入屏幕尺寸,功能上比较狭窄,如果将一个手机对象传入,那么这个对象的品牌和尺寸属性就可以调用了。

 

2. this关键字的第二个用法:实现构造方法间的互相调用

大家通过观察可以发现,Phone类的三个构造方法其实是有重复的。其实,第三个构造方法的功能完全可以通过前两个构造方法来实现,没有必要再重复地写代码。那么该如何写呢?代码如下:

代码6:

class Phone{private float screenSize;private String brand;      Phone(float screenSize){this.screenSize = screenSize;}Phone(String brand){this.brand= brand;}Phone(float screenSize, Stringbrand){this(screenSize);this(brand);} public void showInfo(){System.out.println(“brand= ”+ brand +“, screenSize = ”+screenSize);} public boolean compare(Phone p){return this.screenSize == p.screenSize;}} class PhoneDemo2{public static void main(String[] args){Phone p1 = new Phone(4.7, “iPhone6”);p1.showInfo();}}
运行结果为:

brand = iPhone, screenSize = 4.7

上述代码中黑体字部分就是修改后的代码,那么这里就引入了this关键字的第二个用法:实现构造函数之间的互相调用。这里我要引用《Java编程思想》中的解释1:通常写this的时候,都是指“这个对象”或者“当前对象”,而且它本身表示当前对象的引用。而在构造方法中,如果为this添加参数列表,那么就表示对符合此参数列表的某个构造方法的明确调用。实际上,这与普通方法的调用有相似之处,同名方法之间依靠参数列表的不同进行区别(重载)。

使用带参数列表this关键字需要注意一下三点:

1) 带参数列表的this关键字,时能用于构造方法之中,其他方法中不能使用的。

2) 带参数列表的this关键字(this()),只能定义在构造方法的第一行。要先执行构造方法内调用的其他构造方法来初始化,然后再进行其他初始化操作。

3) 不要出现下面的情况:

代码7:

class Phone{Phone(){this(4.0);}Phone(float screenSize){this();} class PhoneDemo3{     public static void main(String[] args){Phone p = new Phone();}}
上述代码一执行就会出现死循环——两个构造方法之前不停的再互相调用。

 

注释:

1.《Java编程思想》,中文第四版,Bruce Eckel著,陈昊鹏译,机械工业出版社。倒数第三行(不包括代码)。

0 0
原创粉丝点击