浅谈final关键字

浅谈final关键字

final关键字的含义?

final是Java中一个保留的关键字。可以声明变量、方法、类,虽然在不同的场景下有细微区别,但总体上都是指,“是不可变的”。

final修饰变量

我们经常会使用到“常量”,在Java中,用final修饰过的变量,只能进行一次赋值操作,并且在生存周期中不能改变它的值。

需要注意,final会告诉编译器,这个数据不会修改,那么编译器就可能会在编译时期就对该数据进行替换甚至执行计算,这样可以对我们的程序起到一点优化。如果进行一次赋值操作后,再次进行一次赋值,这时编译不通过

final变量只可读

1
2
3
4
5
6
public static void main(String[] args) {
final int a = 1;
a = 2; //编译错误
final String s = "A";
s = "B"; //编译错误
}

对于基本类型变量和引用变量,其效果有些区别:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class ClassA {
int value = 0;
}
public class Main {
public static void main(String[] args) {
/* 声明赋值一起 */
final int a = 1;
//a = 4 编译失败
/* 先声明,后赋值 */
final int b;
b = 2;

final ClassA A= new ClassA();
//A = new ClassA(); 编译失败
System.out.println(A.value);
//输出:0
A.value = 1;
System.out.println(A.value);
//输出:1
}
}

我们发现对于a我们不能进行重新赋值,使`a`成为常量。但对于A.value我们进行了从新赋值。这时因为对于基本数据类型,一旦被final修饰,就不能改变其值;对于引用类型,只是限定引用变量的引用不可改变,“引用”实际上就是一个“地址”,但是该地址所对应的内存空间内的值是可以改变的。

对于集合对象声明为final指的是引用不能被更改,但是你可以向其中增加,删除或者改变内容。

1
2
3
4
5
6
7
8
public class Main {
public static void main(String[] args) {
final List list = new ArrayList();
list.add(1); //有效操作
list.add(2); //有效操作
list = new ArrayList(); //编译失败
}
}

对于final修饰变量的初始化赋值:可以声明时赋值,也可以在构造函数中初始化赋值。

###

对于final修饰变量的初始化赋值:可以声明时赋值,也可以在构造函数中初始化赋值。

final修饰方法的参数

对于自己创建的变量,我们知道只能赋值一次,那对方法参数进行final修饰呢?

它表示在整个方法中,我们不会(实际上不能)改变参数的值。

1
2
3
4
5
6
7
8
9
10
public class Main {
public static void main(String[] args) {
/.../
}
public void fun(final int num) {
//num = 1; 不允许
int a = num;
a = 2;
}
}

final修饰方法

final关键字也可以修饰方法,它表示该方法不能被子类方法重写。如果一个方法已经确定不需要修改,可以声明为final,这样会提高效率,因为final方法在编译时就已经静态绑定了,不需要在运行时动态绑定。

关于privatefinal关键字有一点联系,类中所有的private方法都隐式地指定为是final的,由于无法在类外使用private方法,所以也就无法重写它。

final修饰类

使用final来修饰的类叫作final类。final类通常功能是完整的,它们不能被继承。Java中有许多类是final的,譬如String, Interger以及其他包装类。

不可变类

创建不可变类要使用final关键字。不可变类是指它的对象一旦被创建了就不能被更改了。String是不可变类的代表。不可变类有很多好处,譬如它们的对象是只读的,可以在多线程环境下安全的共享,不用额外的同步开销等。

final与String类的不可变性

相关阅读:String类的不可变性

我们先来看一个例子:

1
2
3
4
5
6
7
8
9
10
11
12
public class Main {
public static void main(String[] args) {
final String s1 = "A";
System.out.println(s1);
//A
s.replace("A", "B");
System.out.println(s1);
//A

System.out.println(s1.replace("A", "B"));
}
}

首先我们发现s1的值并没有改变,这就是String的不可变形,我们平时说“String是字符串常量”也是这个意思,在源码中String类本身就被final修饰过,所以可以这么说,用final修饰的String类型,它就不能再改变了,正如上述例子s1将一直是A

而对于replace()方法,其底层源码是返回一个new StringBuilder.toString().相当于是一个新的String.