1. 不变性
如果对象在被创建后,状态就不能被修改,那么他就是不可变的,不仅仅是对象的引用指向不可变,还包括成员变量等都是不可变的
具有不可变特性的对象一定是线程安全的
2. final
根据程序上下文环境,Java关键字final有“这是无法改变的”或者“终态的”含义,它可以修饰非抽象类、非抽象类成员方法和变量。你可能出于两种理解而需要阻止改变:设计或效率
在早期final
的作用和现在有所不同
早期:效率
- 会把final方法的调用转为内嵌调用,提高效率
现在:设计
- 类防止被继承,方法防止被重写,变量防止被修改
- 天生就是线程安全的,不需要额外的同步开销
2.1 final
修饰变量
被final
修饰的变量,意味着值不能被改变,如果变量是对象,那么对象的引用不可变,但是对象自身的内容仍然可以改变
属性被声明为final
后,该变量则只能被赋值一次,且一旦被赋值,final
变量就不能再被改变
变量有类变量,成员变量,方法中变量,他们都能被final
修饰
① final static variable
(类变量)
赋值时机:
- 在声明变量的等号右边赋值
- 在static静态代码块赋值
② final instance variable
(成员变量)
赋值时机:
- 在声明变量的等号右边赋值
- 在构造方法中赋值
- 在类的初始化代码块中赋值
③ final local variable
(方法中的变量)
赋值时机:
- 没有特定的赋值时机,但是必须在使用这个变量前赋值
2.2 final
修饰方法
特点:
- 构造方法不允许
final
修饰 - 不可被重写,子类不允许重写父类的
final
方法
为什么要使用final方法
① 把方法锁定,防止任何继承类修改它的意义和实现
② 高效,在以前编译器在遇到调用final
方法时候会转入内嵌机制,大大提高执行效率
关于子类不能重写父类的方法还有一个场景就是子类不能重写父类的静态方法,他和fianl是有所不同的
public class Parent {
public static void staMethod(){
System.out.println("调用父类静态方法");
}
public void baseMethod(){
System.out.println("调用父类实例方法");
}
}
public class Son extends Parent {
public static void staMethod(){
System.out.println("重写父类静态方法");
}
public void baseMethod(){
System.out.println("重写父类实例方法");
}
public static void main(String[] args){
Parent parent=new Son();
parent.baseMethod();//重写父类实例方法
parent.staMethod();//调用父类静态方法
}
}
静态方法在编译期间就会分配内存,直到程序退出才会释放,实例方法是在创建对象时才分配相应的内存,也就是说静态变量是在创建的时候就绑定了,而不是在后期动态绑定
因此即便是在子类对象中定义一个于父类一模一样的静态方法,但是这个静态方法属于子类本身,在内存中会分配两块控件去存放这两个静态变量,因此静态方法不存在重写
2.3 final
修饰类
特点:
final
类不能被继承,因此final
类的成员方法没有机会被覆盖,默认都是final
的
3. 不变性和final
的关系
不可变并不意味着简单的使用final修饰就是不可变的
- 对于基本数据类型,确使被final修饰就具有不可变性
- 对于对象类型,还需要保证对象被创建以后,状态永远不可变
不可变类
不变类的意思是创建该类的实例后,该实例的实例变量是不可改变的
① 使用private
和final
修饰符来修饰该类的成员变量
② 提供带参的构造器用于初始化类的成员变量;
③ 仅为该类的成员变量提供getter
方法,不提供setter
方法,因为普通方法无法修改final
修饰的成员变量;
4. 栈封闭技术
在方法里的局部变量是存储在线程私有的栈空间的,而每个栈空间不能被其他线程访问到,所以不会有线程安全问题,这就是栈封闭技术,是线程封闭技术的一种情况