java基础篇复习——关于this与super关键字

一、this

        this关键字,总是指向调用该方法的对象。根据this出现位置的不同,this作为对象的默认引用有两种情形:

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

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

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

大部分时候,一个方法访问该类中定义的其他方法、成员变量时加不加this前缀的效果是完全一样的。如:

public class TestStatic {
	
	private void run() {
		System.out.println("跑");
	}
	
	private void jump() {
		run();
		System.out.println("跳");
	}
	
	public static void main(String[] args) {
		TestStatic test = new TestStatic();
		test.run();
		//或者按照下面方式来访问jump()方法
		new TestStatic().jump();		
	}	
}

上面有色字体部分就表示了静态方法不能直接访问非静态方法,通过实例化对象,然后用对象来访问非静态方法。

二、super

        如果需要在子类方法中调用父类被覆盖的实例方法,则可使用super限定来调用父类被覆盖的实例方法。

        super用于限定该对象调用它从父类继承得到的实例变量或方法,正如this不能出现在static修饰的方法中一样,super也不能出现在static修饰的方法中。static修饰的方式是属于类的,该方法的调用者可能是一个类,而不是对象,因而super限定也失去了意义。

        如果在构造器中使用super,则super用于限定该构造器初始化的是该对象从父类继承得到的实例变量,而不是该类自己定义的实例变量。

        如果子类定义了和父类同名的实例变量,则会发生子类实例变量隐藏父类实例变量的情形。在正常情况下,子类里定义的方法直接访问该实例变量默认会访问到子类中定义的实例变量,无法访问到父类中被隐藏的实例变量。在子类定义的实例方法中可以通过super来访问父类中被隐藏的实例变量。

        如果子类里没有包含和父类同名的成员变量,那么在子类实例方法中访问该变量时,则无需显式使用super或父类名作为调用者。如果在某个方法中访问名为a的成员变量,但没有显式指定调用者,则系统查找a的顺序为:

1、查找该方法中是否有名为a的局部变量

2、查找当前类中是否包含名为a的成员变量

3、查找a的直接父类中是否包含名为a的成员变量,依次上溯a的所有父类明知道java.lang.Object类,如果最终不能找到名为a的成员变量,则系统出现编译错误。

        如果被覆盖的时类变量,在子类的方法中则可以通过父类名作为调用者来访问被覆盖的类变量。

注意:当程序创建一个子类对象时,系统不仅会为该类中定义的实例变量分配内存,也会为它从父类继承得到的所有实例变量分配内存,即使子类定义了与父类中同名的实例变量。

        如果子类中定义了与父类中已有变量同名的变量,那么子类中定义的变量会隐藏父类中定义的变量,并不是完全覆盖,因此系统在创建子类对象时,依然会为父类中定义的,被隐藏的变量分配内存空间。

使用super调用和使用this调用很像,区别在于super调用的是其父类的构造器,而this调用的时同一个类中重载的构造器。因此,使用super调用父类构造器也必须出现在子类构造器执行体的第一行,所以this调用和super调用不会同时出现

        当调用子类构造器来初始化子类对象时,父类构造器总会在子类构造器之前执行;不仅如此,执行父类构造器时,系统会再次上溯执行其父类构造器.......依次类推,创建任何java对象,最先执行的总是java.lang.Object类的构造器。

下面程序定义了三个类,他们之间有严格的继承关系,通过这种继承关系可以看到构造器之间的调用关系:

public class Creature {
	public Creature() {
		System.out.println("Creature无参数构造器");
	}

}
public class Animal extends Creature{
	
	public Animal(String name) {
		System.out.println("Animal带一个参数的构造器"+"该动物的name为"+name);
	}
	public Animal(String name,int age) {
		this(name);
		System.out.println("Animal带两个参数的构造器"+"该动物的age为"+age);
	}
}
public class Wolf extends Animal{

	public Wolf(String name, int age) {
		super(name,age);
		System.out.println("Wolf带参数的构造器");		
	}

	public static void main(String[] args) {
		new Wolf("灰太狼", 4);
	}

}

运行结果:


 从上面结果可以看到,创建任何对象总是从该类所在继承树最顶层类的构造器开始执行,然后依次向下执行,最后才执行本类的构造器。

(参考《疯狂Java讲义第3版》)

猜你喜欢

转载自blog.csdn.net/ruijiao_ren/article/details/79477981