以不变应万变:final关键字和不变形
目录什么是不变形(Immutable)
-
如果对象在被创建后,状态就不能被修改,那么它就是不可变的。
- 例如:person对象,age和name都不能再变
- 具备不变性的对象一定是线程安全的,我们不需要对其采取任何额外的安全措施,也能保证线程安全。
public class Person {
public final int age = 18;
public final String name = "Alice";
}
在其他类中,只可以读取,而不可以赋值。
/**
* 测试final能否被修改
*/
public class TestFinal {
public static void main(String[] args) {
Person person = new Person();
person.age = 178;
}
}
final的作用
3种用法:修饰变量、方法、类
- 属性被声明为final后,该变量则只能被赋值一次。且一旦被赋值,final的变量就不能再被改变,如论如何也不会变。
赋值时机
public class FinalVariableDemo {
private final int a;
/**
* 构造函数中赋值
* @param a
*/
public FinalVariableDemo(int a){
this.a = a;
}
// 代码块中赋值
{
a=7;
}
}
public class FinalVariableDemo {
// 第一种,等号后面赋值
private static final int a;
// 第二种:静态代码块赋值
static {
a=7;
}
}
public class FinalVariableDemo {
// private static final int a;
void testFinal(){
final int b;
b = 5;
int c = b;
}
}
注意点
final修饰方法
-
构造函数不 允许final修饰
-
不可被重写,也就是不能被override,.即便是子类有相同名字的方法,那也不是override,这个和static方法是一个道理。
-
引申:static方法不能被重写
final修饰类
- final修饰类不可被继承,例如典型的String类就是final的
总结
- final修饰对象的时候,只是对象的引用不可变,而对象本身的属性是可以变化的
- final使用原则:良好的编程习惯
不变性和final的关系
- 不变形并不意味着,简单地用final修饰是不可变。
- 对于基本数据类型,
- 如何利用final实现对象不可变?<不对>
总结出,满足以下条件时,对象才是不可变的
- 对象创建后,其状态就不能改变
- 所有属性都是final修饰的
- 对象创建过程中没有发生溢出
把变量写在线程内部——栈封闭
- 在方法里新建的局部变量,实际上是存储在每个线程私有的栈空间,而每个栈的占空间是不能被其他线程所访问到的,所以不会有线程安全问题。这就是著名的“栈封闭”技术,是“线程封闭”技术的一种情况。