1.final是啥
final是个java的保留关键字,它的意思是,用了final来修饰,就表示它是不可变的。
那么问题来了,“不可变”是什么东西????
其实,对于变量,方法,类,final的“不可变”代表着不同的含义。
2.final用于变量上
先看下面代码:
public class FinalTest {
//final 数据必须初始化,要么在声明的时候,要么在构造的时候(构造方法里面)
public final String name = "qwe";
//final + static 必须在声明的时候初始化,表示这是一个静态常量(额外知识点)
public static final String name2 = null;
public static void main(String[] args) {
FinalTest test = new FinalTest();
//下面这句话编译器直接报错,因为它修改了name,准确的说是 name的引用
//test.name = "asd";
}
}
当final去修饰变量时,代表着这个变量的引用地址不可变。什么是引用地址?我们知道在Java中String是不可变的,当我把 name 变量赋值为 asd 时,不是代表着 qwe 变成了 asd,而是jvm会先在内存中生成 asd,现在内存中有 qwe,asd 两个东西(不考虑GC),然后它会把name原来指向的内存地址(qwe的内存地址),指向新的内存地址(asd的内存地址)。那对于name来说,引用地址是不是发生变化了?而final修饰的变量,目的就是让name的内存地址不能变。所以这就是final对于变量的“不可变”。
下面来思考另一个问题。假如我有Person类,它有个name属性:
class Person{
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
非常简单,当我把Person 实例出一个 final对象时:
public static void main(String[] args) {
final Person person = new Person();
person.setName("123");
}
以上代码会报错吗?答案是不会!为什么呢?我们先看看代码,首先final修饰的是 person 对象,person对象的“引用地址”变了吗?并没有,只是person的name属性的引用地址变了,而name又没有用final修饰,所以自然不会报错,但是下面的情况是会报错的:
final Person person = new Person();
//person = new Person(); //编译器报错,因为修改了它的引用
3.final用于方法上
final用于方法上的意思就比较简单了,它意味着,子类不能重写父类的这个方法,看代码:
public class FinalTest {
public final void say(String str){
System.out.println("say " + str);
}
}
class FinalSon extends FinalTest{
//编译器报错,不能重写父类的final方法
//public final void say(String s){}
}
以上的例子很容易就说明了final对于类的作用,有时候我们会看到下面这样的代码:
public void say2(final String str){
//编译器报错
//str = "333";
}
当我们理解了 final 作用于变量上的意义时,理解这个就非常简单了,final 用于变量上是什么意思?就是变量的“引用地址”不可变,所以上面的代码连编译器都通不过
4.final作用于类上
final作用在类上面就更简单,它代表着这个类不能被继承,也有大家默认的一个意思(约定俗成):这个类的功能已经圆满了,不需要修改了。(是不需要,不是不能),看代码:
final class FinalF{
}
//编译器直接报错
class Final2 extends FinalF{
}
简单粗暴,事实上,String类就是用final修饰的:
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
....
}
5.总结
至此,final终于搞清楚了,总之一句话---“不可变”,这也是final设计之初的意图。