final 和effectively final区别

1 篇文章 0 订阅

参考:
https://www.jianshu.com/p/ade870238d18

最近在学习多线程的知识,感觉自己超级无知,写了这么久代码,我连匿名内部类都搞不太懂哈哈,但是我愿意学,哪怕从头开始。

首先贴一下我学习的代码

package cn.ctwom.projone;

import java.util.ArrayList;
import java.util.List;

/**
 * @title:
 * @description:
 * @author: jiangman
 * @time: 2018/12/29 10:13
 */
public class WaitAndNotify {
    private volatile static List list = new ArrayList();

    public void add(){
        list.add("a");
    }

    public int size(){
        return list.size();
    }

    public static void main(String[] args){
        //final修饰的变量是不可以修改的,所以相当于是常量。
        //如下的两个对象变量一个是为了调用其中的方法而存在,一个是为了加锁而存在。
        //所以不存在修改其本身的问题,那么既然不会修改那为什么还要加呢?
        //这里之所以加上了final,是为了防止其他的地方会修改这两个对象,出现线程调度问题。
        //比如:不加final如果对这两个对象进行重复赋值的话,代码是会在编译期就发现报错的,会进行提示,所以还是得要加的。(当然不重复赋值是没问题的)
        //报错信息:Variable 'waitAndNotify' is accessed from within inner class, needs to be final or effectively final
        //inner class:内部类 说的是new Runnable实现的这个匿名内部类
        final WaitAndNotify waitAndNotify = new WaitAndNotify();

        final Object lock = new Object();

        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    synchronized (lock){
                        
                        for(int i = 0; i < 10; i++){
                            waitAndNotify.add();
                            System.out.println("当前线程:"+Thread.currentThread().getName()+"添加了一个元素");
                            Thread.sleep(500);
                            if(waitAndNotify.size()==5){
                                System.out.println("已经发出通知...");
                                lock.notify();
                                lock.wait();
                            }
                        }
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"t1");

        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (lock){
                    if(waitAndNotify.size()!=5){
                        try {
                            lock.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    System.out.println("当前线程:"+Thread.currentThread().getName()+"收到通知线程");
                    lock.notify();
                    throw new RuntimeException();
                }
            }
        },"t2");
        t2.start();
        t1.start();
    }
}

31行和33行 我都用了final关键字,如果还是当前这些代码,其实去掉了这两个final关键字编译也是不会报错的。因为没有对变量重新赋值,那么jdk1.8就默认他是一个常量了,如果你在其他地方给它重新赋值一下,那么他就会报红:

Variable 'waitAndNotify' is accessed from within inner class, needs to be final or effectively final

当然这只针对jdk1.8哈,8之前的不加final编译是肯定不会通过的,非要你加上了final它才安心。
那么final 和effectively final到底啥意思啥区别呢?
具体的如下,是我参考的最上面链接的博友找到的解释,反正我看懂了嘿嘿。

总之,总结下来就是说:
针对于jdk1.8,对于一个变量,如果没有给它加final修饰,而且没有对它的二次赋值,那么这个变量就是effectively final(有效的不会变的),如果加了final那肯定是不会变了哈。就是这个意思。

在学习局部内部类(local inner class)时,遇到了effectively final 的说法。一时不知所云,就google了一下。下面是stackoverflow上的解答,看完,顿时豁然开朗,记载一下,供后来者查阅。
Difference between final and effectively final
其中一位回答,感觉很好:
… starting in Java SE 8, a local class can access local variables and parameters of the enclosing block that are final or effectively final. A variable or parameter whose value is never changed after it is initialized is effectively final.
For example, suppose that the variable numberLength is not declared final, and you add the marked assignment statement in the PhoneNumber constructor:
public class OutterClass {
int numberLength; // <== not final
class PhoneNumber {
PhoneNumber(String phoneNumber) {
numberLength = 7; // <== assignment to numberLength
String currentNumber = phoneNumber.replaceAll(
regularExpression, “”);
if (currentNumber.length() == numberLength)
formattedPhoneNumber = currentNumber;
else
formattedPhoneNumber = null;
}

}

}
Because of this assignment statement, the variable numberLength is not effectively final anymore. As a result, the Java compiler generates an error message similar to “local variables referenced from an inner class must be final or effectively final” where the inner class PhoneNumber tries to access the numberLength variable:
如果你给变量numberLength 又重新赋值了,则numberLength就不再是effectively final。java 编译出错 “local variables referenced from an inner class must be final or effectively final”
作者:ae12
链接:https://www.jianshu.com/p/ade870238d18
來源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值