前言:
这篇博文就是系统的学习一下Java中的this关键字,本人对this关键字的理解知识简单的停留在对 类的成员变量进行赋值,这次所以决定系统的体会一下this 关键字
转自:
一、构造方法中的this关键字
构造方法是一个类的对象在通过new关键字创建时自动调用的,在程序中不能向调用其他方法一样通过方法名(也就是类名)来调用。但如果一个类有多个构造方法,可以在一个构造方法中通过this(paras…)来调用其他的构造方法。
使用this来调用其他构造方法有如下几个约束。1) 只能在构造方法中通过this来调用其他构造方法,普通方法中不能使用。
2) 不能通过this递归调用构造方法,即不能在一个构造方法中通过this直接或间接调用该构造方法本身 。
1 class test { 2 test() { 3 this(1); 4 } 5 test(int a){ 6 this(); 7 } 8 test(int a, int b) { 9 this(1, 2);10 }11 }
解释:test()方法中调用了 test(int)构造方法,而test(int)构造方法又调用了test()构造方法,构成递归调用。test(int, int)中调用了自身,也构成了递归调用。都是不允许的。
3) 通过this调用其他构造方法必须放在构造方法的第一行中执行。
由于super调用父类的构造函数也必须放在构造方法的第一行中执行,因此,通过this和super调用构造方法不能同时出现一个构造方法中。也不能在一个构造方法中多次调用不同的构造方法。
在构造方法中也可以使用this关键字来访问本类中的成员变量和成员函数。其用法和非构造方法中的this关键字相同。
二、非构造方法中的this关键字
在Java中可以通过通过this关键字来调用类中的成员变量和方法。其用法是。
1) this.xxx; 访问类中的成员变量xxx 2) this.yyy(paras…); 访问类中的成员方法yyy 3) this; 当前类对象的引用 this关键字访问类的成员变量和成员函数时不受访问权限的控制,可以访问本类中所有的成员变量和方法,包括private的成员变量和方法。也可以通过this访问本类的static成员,不过由于static成员可以通过类名直接访问,如果通过this来访问会有“The static field ××× should be accessed in a static way”的警告信息。不能在类的static成员或static块中使用this。
三、继承关系下的this关键字
在继承关系下,父类中的this关键字并不总是表示父类中的变量和方法。this关键字的四种用法如前文所述,列举如下。
1) this(paras…); 访问其他的构造方法 2) this.xxx; 访问类中的成员变量xxx 3) this.yyy(paras…); 访问类中的成员方法yyy 4) this; 当前类对象的引用 对第一种,无论子类是否有相同参数的构造方法,this(paras…);访问的始终是父类中的构造方法。 对第二种,无论子类是否有覆盖了该成员变量,this.xxx;访问的始终是父类中的成员变量。 对第三种,如果子类重写了该成员方法,则this.yyy(paras…);访问的是子类的成员方法,如果子类没有重写该成员方法,则this.yyy(paras…);访问的是父类的成员方法。 对第四种,this始终代表的是子类的对象。public class ClassTest { public static void main(String[] args) { Child child = new Child(); child.show(); }}class Parent { public String str; Parent(){ this(1); } Parent(int a) { this.str = "Parent"; this.show(); } public void show() { System.out.println(this.str); }}class Child extends Parent { public String str; Child() { } Child(int a) { str = "Child"; } public void show() { System.out.println(str); super.show(); }}
main()函数中有两条语句,new Child()和child.show()。
第一条语句new Child()时要执行Child类的构造方法,但是Child类是Parent类的子类,因此会先执行Parent类的构造方法。Child类的无参构造函数中没有使用super和this来调用父类或本类中的其他的构造方法,因此会调用父类的无参构造函数。
在父类的无参构造函数Parent()中调用了执行了this(1),此调用表示执行父类中有一个整数参数的构造方法,虽然子类中也有一个有一个整数参数的构造方法,但是并不会被执行。
父类中有一个整数参数的构造方法执行this.str=”Parent”,这里的this.str代表的是父类中的成员变量str,虽然子类中也有一个成员变量str,但是并不会被赋值。
将父类中的成员变量str赋值为”Parent”后,接着执行了this.show(),虽然父类中有一个show()方法,但由于子类重写了show()方法,所以this.show()执行的子类的show()方法。
子类的show()方法首先执行了打印str的操作,此时打印的显然是子类中的str,子类的str没有被赋值,因为打印null。
接着子类的show()方法执行了super.show(),即调用了父类的show()方法,在父类的show()方法中执行了打印this.str的操作,this.str同样代表父类中的成员变量str,因此打印”Parent”。
第二条语句child.show()先是执行子类的show()方法,子类的show()先是打印了子类的str值(null),然后执行了父类的show()打印了父类的str值(”Parent”)。 两条语句的打印结果为null, Parent, null, Parent。 如果将第一条语句改为new Child(1),则执行的是子类的有一个整数参数的构造方法,仍然是先执行父类的无参构造方法,初始化父类的str为”Parent”,然后执行子类的show(),子类的show()打印子类的str值(null),然后执行父类的show(),父类show()打印父类的str值(”Parent”),然后执行子类的构造方法将子类的str初始化为”Child”。第二条语句child.show()先是执行子类的show()方法,子类的show()先是打印了子类的str值(”Child”),然后执行了父类的show()打印了父类的str值(”Parent”)。
两条语句的打印结果为null, Parent, Child, Parent。
四、super和this的异同
super在一个类中用来引用其父类的成员,它是在子类中访问父类成员的一个桥梁,并不是任何一个对象的引用,而this则表示当前类对象的引用。在代码中Object o = super;是错误的,Object o = this;则是允许的。
super关键字的作用在于当子类中覆盖了父类的某个成员变量,或者重写了父类的某个成员方法时还能够访问到父类的成员变量和成员方法。如果子类中没有重写父类的成员变量和成员方法,则子类会继承父类的所有非private的成员变量和成员方法。这时在子类中无论通过this来访问成员和通过super来访问成员,结果都是一样的。
五、super.getClass()和this.getClass()
getClass()是Object类定义的一个final方法,所有Java类的getClass()都继承自Object类。如前文所述,如果子类没有重写父类的某个成员方法,那么通过super来访问还是还是通过this来访问结果都是一样的。因此,super.getClass()和this.getClass()结果是一样的。Object类的getClass()方法返回的是该对象的运行时类,一个对象的运行时类是该对象通过new创建时指定的类。因此,super.getClass()和this.getClass()返回的都是new对象时指定的类。
1 public class ClassConstructorTest { 2 public static void main(String[] args) { 3 Child child = new Child(); 4 child.show(); 5 } 6 } 7 8 class Parent { 9 private Parent mSelf;10 Parent(){11 mSelf = this;12 }13 public void show() {14 System.out.println(this.getClass().getName());15 System.out.println(super.getClass().getName());16 System.out.println(mSelf.getClass().getName());17 }18 }19 20 class Child extends Parent {21 public void show() {22 System.out.println(this.getClass().getName());23 System.out.println(super.getClass().getName());24 super.show();25 }26 }
打印的类名都是Child。