经常会在程序中用到同名变量或方法,区分对了才能正确引用,得到所要的结果,这通常得要靠this和super了;
在说明这两个关键字之前先做些准备:
1、扩展类会继承基类的方法和变量,在内存中为其开辟空间;
2、对于变量x,java的搜索顺序:局部变量 => 本类成员变量 => 直接父类成员变量 => 间接父类成员变量 => …… => java.lang.Object类变量;
现在,来看个例子:
class A{ int x; A(int x){ x=x; System.out.println(x); } }按照上面说的搜索顺序,构造函数体中的变量x指的都是形参,这与我们的本意可能就不相符,为了给成员变量x赋值并输出之,通常可以作如下改变:
A(int x){ this.x=x; System.out.println(this.x); }这里我们使用了关键字this,this指代的是调用本方法/变量的本类实例,这样就将成员变量跟形参进行了区分;
既然指代的是实例,那实例自然可以调用变量以及方法,因此,this通常有如下用法:
- 调用本类实例变量:this.x; //x为实例变量,对于类变量,通常不建议通过 “实例名.变量名” 的方式来调用;
- 调用本类实例方法:this.f([para1,……]); //这跟上一点是一个意思,都指代本类实例,自然可以调用方法和变量;
- 调用构造函数:this([para1,……]); //将构造函数单独列出,可以是无参或带参的;
既然涉及到"实例",那有些地方就不能使用:static方法,我们都知道static方法都是属于类的,可以使用类名直接进行调用,不依赖实例而存在,二者的内存空间不一样,可以这样简单验证下:
假设static方法可以直接引用实例变量,存在这种可能:在未建立实例前即引用类方法,这自然会产生错误;
因此在static代码块/方法中不允许使用this;
this在内部类中的应用也比较频繁,内部类可以共享外部类的成员变量,同样存在同名变量的可能,如下代码所示:
class B{ int x=1; class C{ int x=2; void f(){ int x=3; System.out.println(x);//3 System.out.println(this.x);//2 System.out.println(B.this.x);//1 } } }其中this.x的写法等效于C.this.x,在引用外部类成员变量时可以运用该种写法,当然new出一个实例也OK;
在涉及到继承关系时,就会使用到另一个关键字super,虽然扩展类继承了基类的变量/方法,但若扩展类中存在同名变量/方法,则在引用时自然也只能调用到扩展类的成员;
我们直到继承时,扩展类建立对象时也在内存中为基类开辟了内存区,因此基类的同名变量/方法并没有被重写,只是被隐藏了,类似this的使用,我们通过super来调用他们;
super通常有如下限定:
- 用于扩展类中调用基类被隐藏的实例变量/方法(private修饰的自然是引用不到的);
- 扩展类的构造方法须引用基类构造方法,并且super([para1,……])语句需放在执行体第一行;
- 扩展类构造方法中若调用基类无参构造方法,则可默认省略不写;
参考this,可知super有如下用法:
- 调用基类实例变量:super.x;
- 调用基类实例方法:super.f([para1,……]);
- 调用基类构造函数:super([para1,……]);
在《Java语言规范》中解释道,super.x,实际指代的是本类当前对象的成员变量x,若假设当前类的基类为A,则super.x会被看成犹如:((A)this).x;因此下面代码输出是一样的:
class A{ int x=1; } class B extends A{ int x=2; { System.out.println(super.x);//1 System.out.println(((A)this).x);//1 } }最后还是得再强调super也是实例相关的关键字,不能用于static修饰的方法或代码块中,否则会引起编译错误;