Java中的关键字有许多个,今天主要介绍this、super和final。
this:
在Java中this指代的是当前类的对象的引用,简单说就是指当前类实列化的对象,注意不是指当前类。this主要有以下作用:
1、区别成员变量与局部变量:this.属性名 指代的就是当前类的成员变量。 这个在我们封装类提供getter/setter的时候最常见:
如下代码:参数中的局部变量a与类中的成员变量a同名,这时就需要用this.a来指定成员变量a,如果不使用this,那么根据Java中的就近原则 就等于是把参数中的局部变量a赋值给自己,这样外界在调用setA()方法是毫无作用,getA()方法也不会得到预期的值
public class AClass {
private int a;
private String b;
public void setA(int a) {
//这里参数中的局部变量a与类中的成员变量a同名,这时就需要用this.a来指定成员变量a
//如果不使用this,那么根据Java中的就近原则 就等于是把参数中的局部变量a赋值给自己,
// 这样外界在调用setA()方法是毫无作用,getA()方法也不会得到预期的值
this.a = a;
}
public void setB(String b) {
this.b = b;
}
public int getA() {
return a;
}
public String getB() {
return b;
}
}
2、this调用本类方法或者本类中的其他构造方法
在当前类中我们调用其他普通方法一般就直接使用方法名的方式,但是默认前面其实是有this的,但是Java虚拟机默认了省略this的这种方式,所以我们是否加this都不会报错。
构造方法中使用this调用本类中的其他构造方法,详情请看上一章节(构造函数)
super:
super关键字代表父类的引用,所以super关键字也只存在与继承关系中。
super关键字主要有如下作用:
1、子类和父类都存在相同名称的成员变量时,使用super.成员变量名 来指代父类中的成员变量,如果没有super,那么默认是子类的成员变量:
public class AClass {
public String num = "abc"; //父类中的成员变量num
}
public class BClass extends AClass {
public int num = 20;//子类中的成员变量num
public void fn() {
Log.i("TAG", "num = " + num); //指子类中的成员变量 输出:20
Log.i("TAG", "num = " + super.num);//使用super指父类中的成员变量 输出:abc
}
}
2、子类使用super调用父类中的构造函数,详情请看上一章节(构造函数)
final:
final关键字可以修饰变量、方法和类。
final修饰变量:
被final修饰的变量一旦被赋值后就不能再次修。首先如果这个变量是一个基本数据类型,比如int、String等被final修饰后值就不能改变,这时这个变量就是一个常量;其次如果这个变量是一个引用数据类型,比如数组、集合等被final修饰后这个变量的内存地址的引用不能被修改,但是其本身内部数据是可以改变的,也就是说如果数组、集合被final修饰也可以添加删除数据。
public class DemoActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_demo);
final StringBuilder builder = new StringBuilder();//使用final修饰StringBuilder
//可以正常添加内部数据
builder.append("a");
builder.append("b");
Log.i("TAG", "builder:" + builder.toString());//输出ab
builder = new StringBuilder();//这里会报编译错误:内存地址的引用不能被修改
}
}
final修饰的变量必须被初始化,否则会编译出错。我们可以通过以下几种方式初始化final修饰的变量:
1、在声明final变量的同时就赋值,这种方式是最常见的初始化final变量的方式:
public class DemoActivity extends AppCompatActivity {
private final double PI = 3.14;//声明的同时就赋值
@Override
protected void onCreate(Bundle savedInstanceState) {
2、在初始化器中初始化,常见的初始化器如构造函数。我们可以给一个final修饰的变量只声明不赋值,这种变量即为空白变量,之后在构造函数中去初始化这个变量,需要注意的是如果有多个构造函数,那么每个构造函数中都需要初始化一次这个变量,或者通过this调用其他已经初始化过final变量的构造函数,否则编译会报错:
public class AClass {
private final double PI;//仅仅声明一个final修饰的变量,不赋值
public AClass() {
PI = 3.14; //构造函数中赋值
}
public AClass(String a) {
this(a, 0);//通过this调用其他构造函数
}
public AClass(String a, int b) {
PI = 3.14159;//可以赋不同的值,创建对象时调用哪个构造函数 final变量的值就是对应构造函数中的值
}
public void fn() {
Log.i("TAG", "PI=" + PI);
}
}
public class DemoActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_demo);
AClass A = new AClass();
A.fn();//输出:PI=3.14;
AClass B = new AClass("a", 0);
B.fn();//输出3.14159
}
}
final修饰方法:
final修饰方法大概有两个原因:锁定方法,让此方法不被重写;提高方法运行效率。
如果一个方法设计得比较完整,不想被子类重写,那么可以用final来修饰这个方法。
当一个方法被final修饰,那么JVM会针对这个方法的调用转为内联调用,大概意思就是:不采用普通方法那套调用流程,直接把方法展开执行里面的代码,这样在一定程度上节省了调用开销。但是如果一个方法本身含有许多流程代码,那么也达不到节约开销的效果。
final修饰类:
一个类被final修饰后就是一个不可被继承的类,而且这个类中的所有方法都默认为是final方法,但是变量却不会被默认为final变量。常见的final类如:String、Double、Integer等。
被final修饰后的类不能扩展功能,所以JVM不在花费开销去关心类的继承,而且由于final类中的方法都默认是final方法,在一定程度上也会节约开销。