this

来源:互联网 发布:淘宝店铺售卖 编辑:程序博客网 时间:2024/05/21 08:58


从这篇博客开始,我会重点整理下Java里面的几个关键字。


Java提供了一个this关键字,this关键字总是指向调用该方法的对象。这句话一定要读个10遍以上。

根据this出现位置的不同,this作为对象的默认引用有两种情形。

1),构造器中引用该构造器正在初始化的对象

2),在方法中引用调用该方法的对象


this关键字最大的作用就是让类中的一个方法,访问该类里的另一个方法或实例变量。

this可以代表任何对象,当this出现在某个方法体中时,它所代表的对象是不确定的,但它的类型是确定的,它所代表的对象只能是当前类,只有当这个方法被调用时,它所代表的

对象才能确定下来,谁在调用这个方法,this就代表谁


总结一下,this关键字主要有三个应用。

1),this调用本类中的属性,也就是类中的成员变量

Java允许局部变量和成员变量同名,如果方法里的局部变量和成员变量同名,局部变量会覆盖成员变量

如果需要在这个方法中引用被覆盖的成员变量,则可使用this(对于实例变量)或类名(对于类变量)作为调用者来限定访问成员变量。

现在定义一个Dog类,每个小狗都有一个name名字的,然后这个类里面有一个给小狗起名字的setName方法,看如下代码:

public class Dog{/** * 一只小狗有自己的一个名字 */private String name;/** * 给小狗起名 *  * @param name 给小狗起的名字。 */public void setName(String name){name = name;}}

上面这段代码中,有一个成员变量name,同时在方法中有一个形式参数,名字也是name,然后在方法中将形式参数name的值传递给成员变量name,虽然我们可以看明白这个代

码的含义,但是作为Java编译器它是怎么判断的呢?到底是将形式参数name的值传递给成员变量name,还是反过来将成员变量name的值传递给形式参数name呢?也就是说,两

个变量名字如果相同的话,那么Java如何判断使用哪个变量?

此时this这个关键字就起到作用了。this这个关键字其代表的就是对象中的成员变量或者方法。也就是说,如果在某个变量前面加上一个this关键字,其指的就是这个对象的成员变

量或者方法,而不是指成员方法的形式参数或者局部变量。修改上面的代码如下:

public class Dog{/** * 一只小狗有自己的一个名字 */private String name;/** * 给小狗起名 *  * @param name 给小狗起的名字。 */public void setName(String name){this.name = name;}}

在上面这个代码中,this.name代表的就是对象中的成员变量,又叫做对象的属性,而后面的name则是方法的形式参数,代码this.name=name就是将形式参数的值传递给成员变

量。 一般情况下,在Java语言中引用成员变量或者成员方法都是以对象名.成员变量或者对象名.成员方法的形式。不过有些程序员即使在没有相同变量的时候,也喜欢使用this.成

员变量的形式来引用变量,这主要是从便于代码的阅读考虑的。一看到这个this关键字就知道现在引用的变量是成员变量或者成员方法,而不是局部变量。这无形中就提高了代码

的阅读性。不过话说回来,这是this关键字在Java语言中的最简单的应用。从这个应用中,我们可以看出this关键字其代表的就是对象的名字。

其实如果是局部变量的话,也是相同的道理。如上面的第一段代码中,name不是形式参数,而是一个局部变量。此时Java也会遇到相同的疑惑,即变量名name代表的到底是局部

变量还是形式参数?name=name到底代表的是什么含义?根据局部变量的作用域,在方法内部,如果局部变量与成员变量同名的话,那么是以局部变量为准。可是在name=name

这个赋值语句中,将局部变量的值赋值给自己,显然并不是很合适。根据代码的含义,本来的意思应该是将局部变量赋值给成员变量。为了更清晰的表达这个含义,为此最好采用

如下的书写格式name=this.name。


2),this调用本类中的其他方法

假设定义了一个Dog类,这个Dog对象的run()方法需要调用它的jump()方法,那么应该怎么做?一般情况下我们会写出如下的代码来实现上面情景中的功能:

public class Dog{/** * 定义一个小狗自己的jump方法 */public void jump(){System.out.println("这里是小狗自己的jump()方法。。。");}/** * 定义一个小狗自己的run方法,需要借助小狗的jump方法 */public void run(){Dog dog = new Dog();dog.jump();System.out.println("这里是小狗自己的run()方法。。。");}public static void main(String[] args){new Dog().run();// 这里是小狗自己的jump()方法。。。// 这里是小狗自己的run()方法。。。}}

使用这种方式确实可以实现在run()方法中调用jump()方法,上面的测试调用了小狗的run()方法,也确实间接的调用了小狗的jump()方法,但是这种做法是否够好呢?

现在我们来分析一下,上面的测试代码中,创建一个Dog对象,调用小狗的run()方法,在run()方法中又创建了一个Dog对象,然后使用这个新的对象调用小狗的jump()方法。这里

就会产生三个问题:

1,在run()方法中调用jump()方法时是否一定需要一个Dog对象?答案是肯定的,因为没有使用static修饰的成员变量和方法都必须要使用对象来调用。

2,是否一定需要重新创建一个Dog对象?答案是否定的,因为当程序调用run()方法时,一定会提供一个Dog对象,这样就可以直接使用这个已经存在的Dog对象,并不需要重新创

建新的Dog对象。

3,上面的编码实现是否符合实际意义呢?答案是否定的,在Dog对象的run()方法内重新创建了一个新的Dog对象,并调用它的jump()方法,这意味着一个Dog对象的run()方法需要

依赖于另一个Dog对的jump()方法,这并不符合逻辑,因为一个小狗是蹦是跳和其他的小狗是什么情况并没有什么关系呀。


为了解决上面讲的几点,需要在run()方法中获得调用该方法的对象,通过this关键字就可以满足这个要求。代码修改如下:

public class Dog{/** * 定义一个小狗自己的jump方法 */public void jump(){System.out.println("这里是小狗自己的jump()方法。。。");}/** * 定义一个小狗自己的run方法,需要借助小狗的jump方法 */public void run(){// 在这里this关键字可以省略。this.jump();System.out.println("这里是小狗自己的run()方法。。。");}public static void main(String[] args){new Dog().run();// 这里是小狗自己的jump()方法。。。// 这里是小狗自己的run()方法。。。}}


在现实世界里,对象的一个方法依赖于另一个方法的情形如此常见,因此,Java允许对象的一个成员直接调用另一个成员,可以省略this前缀

大部分时候,一个方法访问该类中定义的其他方法,属性时加不加this前缀的效果是完全一样的,这里说的大部分情况下,值得是方法中不存在与属性同名的局部变量,这点前面

已经整理到了。

对于static修饰的方法而言,可以使用类来直接调用该方法,如果在static修饰的方法中使用this关键字,则这个关键字就无法指向合适的对象。Java语法规定,静态成员不能直接访

问非静态成员,所以static修饰的方法中不能使用this引用。如果确实需要在静态方法中访问另外一个普通方法,则只能重新创建一个对象,也就是在静态方法中new一个对象出来

然后再打点调属性或者方法。


3),this调用本类中的其他构造方法,调用时要放在构造方法的首行

上面已经整理到了,使用this关键字可以调用本类中的其他方法,除此之外,this引用也可以用于构造器中作为默认引用,由于构造器是直接使用new关键字来调用,而不是使用对

象来调用的,所以this在构造器中代表构造器正在初始化的对象。

public class Dog{/** * 定义一个name属性 */private String name;public Dog(){// 定义一个name局部变量,和name属性同名了,默认将覆盖name属性String name = "LinkinPark的小狗";// 使用this关键字来表示正在初始化的对象的属性,而不是构造器中的局部变量// 如果没有局部变量和属性同名,this关键字也是可以省略的this.name = "NightWish的小狗";}public static void main(String[] args){System.out.println(new Dog().name);// NightWish的小狗}}

与普通方法类似的是,大部分的时候,在构造器中访问其他成员变量和方法时都可以省略this前缀,但如果构造器中有一个与成员变量同名的局部变量,又必须在构造器中访问这

个被覆盖的成员变量,则必须使用this前缀。

当this作为对象的默认引用使用时,程序可以像访问普通引用变量一样来访问这个this引用,甚至可以把this当成普通方法的返回值

public class Dog{private String name;private Integer age;public Dog setName(String name){this.name = name;return this;}public Dog setAge(Integer age){this.age = age;return this;}public static void main(String[] args){// 以前我比较喜欢这种链式写法,但是可能造成实际意义的模糊,现在不这样子编码啦new Dog().setName("LinkinPark的小狗").setAge(10);}}

上面的代码中,使用this作为几个属性的set方法的返回值造成了实际意义的模糊,这个方法的含义本身只是说给对象的几个属性赋值,不应该就返回值,但是却返回了一个指向自

己的引用,实际意义不算合理。所以,如果在某个方法把this作为返回值,可以多次连续调用同一个方法,从而使得代码更加简洁,但是这可能造成实际意义的模糊,所以不建议

这么使用

在构造器中,可以使用this关键字调用另一个重载的构造器。使用this调用另一个重载的构造器只能在构造器中使用,而且必须作为构造器执行体的第一条语句。使用this调用重载

的构造器时,系统会根据this后括号里的实参来调用形参列表与之对应的构造器

public class Dog{private String name;private Integer age;public Dog(String name){this.name = name;}public Dog(String name, Integer age){// 构造器中this调用重载的构造器,必须第一行this(name);this.age = age;}}

最后在补充一点,一定要记住,this关键字总是指向调用该方法的对象。在《java编程思想》里面,对这块是这样描述的:

假定我们在一个方法的内部,并希望获得当前对象的句柄,由于那个句柄是由编译器“秘密”传递的,所以没有标识符可用。然而,针对这一目的有个专用的关键字:this

看下面一段代码:

public class SubClass extends SuperClass{public static void main(String[] args){new SuperClass();// 看一下这里的this引用是什么对象:SuperClass}}class SuperClass{public SuperClass(){System.out.println("看一下这里的this引用是什么对象:" + this.getClass().getSimpleName());}}
不用怀疑,在初始化一个子类的时候,总是要调用父类的构造器,所以在父类的构造器中this关键字执行的子类的对象,而不是父类。因为初始化子类调用父类的构造器,而不是

父类自己调用自己的构造器,所以this就是子类,而不是父类,这点我刚开始的时候也没太注意,今天重新整理this关键字才发现的,以后这里一定要注意了,所以说有的时候咬文

嚼字还是有很大好处的


1 0
原创粉丝点击