因为别人只能进行读取,却不能进行更改。
类用final反正被继承,方法用final防止被重写,变量用final防止被修改。
例子如下:
final修饰变量
代码演示如下:
package immutable;
public class FinalVariableDemo {
// 如果不赋值直接报错
private final int a = 6;
private final int b;
private final int c;
// 赋值方式二,在构造函数中赋值
public FinalVariableDemo(int b) {
this.b = b;
}
// 赋值方式三,在代码块中赋值
{
c = 6;
}
}
package immutable;
public class FinalVariableDemo {
// 如果不赋值直接报错
private static final int a = 6;
private static final int b;
// 赋值方式二,静态代码块
static {
b = 6;
}
// 它无法在构造函数中赋值
}
package immutable;
public class FinalVariableDemo {
void testFinal(){
final int b;
}
}
普通的对象,可能初始化以后为null,但是,final不行,初始化就得给他赋值,在方法中,使用之前就得给他显式赋值。因为它是不可变的。
final修饰方法
final修饰类
final的注意点
如果一个变量知道它不会变那么就用final修饰,这样也起到了提示的作用。
不变性和final的关系
如何利用final实现对象不可变呢?
首先,把所有属性都声明为final不一定可以实现不可变了,如果属性是对象类型的话,只是对象的引用不可变。
然后,一个属性是对象类型的对象,也可能是不可变对象,只要该对象只提供读取的方法,不提供更改的方法即可。
例子如下:
package immutable;
import java.util.HashSet;
import java.util.Set;
public class ImmutableDemo {
// private修饰,所以,外界无法进行获取,也无法进行更改了。
private final Set<String> students = new HashSet<>(4);
// 对students的添加只在构造函数中做过一次,在别的地方没有进行添加。
public ImmutableDemo(){
students.add("小卢");
students.add("小孙");
students.add("小李");
}
// 为外界提供读取方法
public boolean isStudent(String name){
return students.contains(name);
}
}
由此可见,看对象可不可变,主要还是看外界能不能对他里面内容进行更改。
package immutable;
import java.util.concurrent.*;
/**
* 描述: 栈封闭技术
* 演示栈封闭的两种情况,基本变量和对象
* 先演示线程争抢带来的错误结果,然后把变量放到方法内,情况就变了
*/
public class StackConfinement implements Runnable {
int index = 0;
public void inThread(){
int neverGoOut = 0;
for (int i = 0; i < 10000; i++) {
neverGoOut++;
}
System.out.println("栈内保护的数字是线程安全的: " + neverGoOut);
}
@Override
public void run() {
for (int i = 0; i < 10000; i++) {
index++;
}
inThread();
}
public static void main(String[] args) {
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(2, 2, 0, TimeUnit.SECONDS, new SynchronousQueue<Runnable>());
StackConfinement stackConfinement = new StackConfinement();
for (int i = 0; i < 2; i++) {
threadPoolExecutor.submit(stackConfinement);
}
threadPoolExecutor.shutdown();
while(!threadPoolExecutor.isTerminated()){
}
System.out.println("index:" + stackConfinement.index);
}
}
结果如下:
结论分析:实例变量会有线程安全的问题,但是,方法内的变量只能是当前线程可以访问它,所以,不会存在线程安全问题,它具有栈封闭的功能。
答案是true和false
加了final 以后,就是常量了,所以,c会自己等于wukong2,由于a已经建立过,所以,c会知道a的地址
而d没有fianl,编译器不能提前知道d的值,所以e要在运行时确定,所以,是在堆上生成wukong2。所以,他们指向的不是一个地方。
package immutable;
public class FinalStringDemo2 {
public static void main(String[] args) {
String a = "wukong2";
// 通过方法获得,编译器也无法在编译时获得,所以,也是生成在堆上
final String b = getDashxiong();
String c = b + 2;
System.out.println(a == c);
}
private static String getDashxiong() {
return "wukong";
}
}
这个返回是false