1、什么是不可变性?
如果对象在被创建后,状态就不能修改,那么就是不可变的
据有不可变性的对象一定是线程安全的,我们不需要对其采取任何额外的安全措施,也能够保证线程安全。
**
2、final的作用
类防止被继承,方法防止被重写,变量防止被修改
天生线程安全
2.1、final 修饰变量
final修饰变量意味着值不能更改,final修饰对象, 意味着对象引用不能变,但是对象内容可以变化
- 类属性中的成员变量
赋值时机:
(1)声明变量等号右边直接赋值
(2)构造方法中赋值
(3)类的初始代码块赋值
- 类属性中的静态变量
(1)声明变量等号右边直接赋值
(2)静态代码块赋值
- 方法中的变量
(1)不规定赋值时机,但是使用前必须赋值
public class FinalVariable {
private final int a = 5;
private final static int b = 5;
// private final static int b = 5; 静态变量第一种赋值时机
// static {
// b = 5; 静态变量第二种赋值时机
// }
// private final int a = 5; 实例变量第一种赋值时机
// public FinalVariable(int a) {
// this.a = a; 实例变量第二种赋值时机
// }
// {
// a = 5; 实例变量第三种赋值时机
// }
public void doSomething(){
//方法中的变量 不规定赋值时机,但是使用前必须赋值
final int a = 5;
}
}
2.2、final修饰方法
不允许修饰构造方法
修饰普通方法,表示不可被重写,和static类似
静态方法不可被重写(但是子类和父类可以有相同名字的方法)
2.3、final修饰类
不可被继承
String
3、不变性和final的关系
不变性并不意味着简单被final修饰后就是不可变的
- 对于基本类型,确实被final修饰后据有不变性
- 但是对于对象类型,需要对象保证自身被创建后,状态永远不会变才可以
如何利用final做到对象不可变
- 对象创建后,状态不可修改
- 所有属性都是final修饰的
- 对象创建过程中没有发生溢出
栈封闭技术,方法内的变量线程不共享,线程安全
4、 面试题
public static void main(String[] args) {
//指向常量池
String a = "java2";
// final 修饰编译时已经确定,被当作编译时期的常量使用
final String b = "java";
//指向常量池的java
String c = "java";
//编译时发现b是常量,就直接得到d的值为java2,刚好声明了java2,所以a和d指向常量池的java2
String d = b + 2;
// c不是final修饰,d的值要到运行时才确定
String e = c + 2;
System.out.println(a == d);
System.out.println(a == e);
}