源码中出现final的地方
- 所有的link有关的方法(增删操作)add remove
- 需要保存中间变量的节点(prev和next指针需要修改的节点)
- 像clear get这种不涉及“更改指针指向”的方法不需要对中间变量定义final
final的作用
LinkedList中Node是一个对象,因此适用于第二条引用数据类型,举个例子:
有无final修饰的浅拷贝
People p1 = new People(18,"张三");
People p2 = p1;
-
当:p1 = null;或者p1 = new People(20,“李四”);
实际上是栈中的p1存储的地址改变,但堆空间中之前 new People(18,“张三”);的对象仍然存在。因此p2不受影响 -
当:p1.setAge(21); 此时操作的是堆空间中的唯一对象,p2会受到影响
在源码中:
final E element = x.item;
final Node<E> next = x.next;
final Node<E> prev = x.prev;
使得element next prev三个属性栈空间保存的地址不可再被重定向,但可以修改值,例如:next.prev = prev和prev.next=next 可以对栈所指向的堆成员变量进行修改
使用final初始化的优点
参考链接:
https://www.cnblogs.com/noteless/p/10416678.html
https://www.cnblogs.com/noteless/p/10410368.html
https://www.cnblogs.com/mianlaoshu/articles/3648403.html
https://www.cnblogs.com/maxiaopao/p/9212903.html
https://zhuanlan.zhihu.com/p/88775601
https://www.zhihu.com/question/21762917/answer/19239387
第四条链接中讲final的优点很详细
第五条讲到了重排序
第六条是JVM对方法中的final变量性能调优
安全性分析
- LinkedList本身是不安全,但这并不影响,因为每次事务初始化的都不是同一个Node对象,如果多线程并发并同时add,那么即便是源码定义了final,也可能会出现错误,因此LinkedList在并发场景下需要自行同步
- 但多线程并发对于方法中局部变量是不存在冲突的
- 排除安全性的可能
性能分析
- 在能够通过编译的前提下,无论局部变量声明时带不带final关键字修饰,对其访问的效率都一样。
- 既然一样,那性能上没影响了。排除
规范
参考阿里巴巴的开发手册
不允许修改的局部变量声明为final更多的是一种规范,在实质作用上加与不加没有区别,但他就是个规范。排除任何可能对这个变量进行修改的可能性
本问题花了我14个小时,查阅了无数资料,问了无数的人,最后能总结出来的答案就是:规范
hhhh浪费了我一天的宝贵时间
总结
- 方法内部初始化的final变量是局部变量
- 没有多线程冲突问题
- 局部静态基本数据变量定义final才有JVM优化,而引用类型则没有
- final可以避免误操作可能带来的问题,因此对所有不会修改的局部变量都用final定义
- LikedList仍然是线程不安全的,需要手动上锁