Java 中,一个 final 的 List 变量,被往里加了元素,算不算违反了 final 这个关键词在这里暗示的约定?

2021-12-31 10:44:16 +08:00
 Newyorkcity
final 关键词在 java 中,只能保证变量的值不变,但如果变量的值是一个本身提供了修改自身的方法的对象,那调用这一方法对值(内部)做修改,final 是约束不到的。

然而这样的修改,是否是违背了 final 这个关键词放在这里时暗示的约定——该变量是不可变的?或者说,如果让一个全知全能的家伙来编写 Java ,它是否会为 final 所修饰的变量保证无论如何都无法被修改而不仅仅只是引用无法被修改的限制?(也就是说,java 之所以不能实现到这一步,是否可能是因为在编译器层面强制实现这一程度所需要的工程量太大划不来)

谢谢
4252 次点击
所在节点    问与答
55 条回复
seanzxx
2021-12-31 11:50:19 +08:00
@Newyorkcity final 和 immutable 是不一样的
final 是指这个变量不能再赋值,也就保证了这个变量的值不会改变
引用变量,他的值是地址,你改变的是地址指向的内存中内容

举个例子,公司的员工管理系统保存了你的家庭地址,但你做的是改变你家的家具。
如果你的家庭地址是 final ,你就不能再搬家了,但你怎么改变你家的布置是没有限制的
geekfxxk
2021-12-31 11:52:58 +08:00
值类型,引用类型没理解好
yolee599
2021-12-31 11:55:25 +08:00
假设有一个“人”,用来找到这个“人”的关键字叫“身份证号”,现在我们定义“身份证号” 是 final 的,一经赋值就不会变了,无论你身高怎么变,体重怎么变,年龄怎么变,性别怎么变。“身份证号”还是那个“身份证号”。

现在把上面例子的“身份证号”替换为“对象”,是不是就好理解多了。
Asan
2021-12-31 11:58:10 +08:00
final 不能修改改的是引用,但是引用指向的内存是可以涂涂改改的
AoEiuV020CN
2021-12-31 12:01:38 +08:00
这种问题学 c 语言的时候讲的比较清楚,因为不搞清楚真的容易炸,
指针不变和内容不变,两码事,基本类型不是指针,不存在指针不变的用法,引用类型指针不变情况内容变没问题,
timethinker
2021-12-31 12:04:53 +08:00
一个变量到底存储的是什么?变量类型指明了存储的数据如何使用,对于一个 int 类型的变量来说,存储的就是实际的数字。对于对象来说,存储的就是一个内存地址,它被解释为具体类型在内存中的起始地址加上成员变量类型偏移量。以上这些只是一些表面的解释,编译器或者解释器 /虚拟机会根据这些信息来优化,并最终操作计算机。

所以 final 修饰的是变量值不可改变,而不是这个值再被用来解释翻译,并操作其他内存的数据不可改变。
dcsuibian
2021-12-31 12:40:38 +08:00
“final AtomicInteger a= new AtomicInteger(0) 的 a ,由 0 变 1”
a 既不是 0 也不是 1 ,而是一个 AtomicInteger 实例,一直都是这个实例,没有变过
如果我写了一个 final CustomClass c=new CustomClass(arg1,arg2,arg3)
那么我的 c 就一直是这个 CustomClass 啊,你把 AtomicInteger 和数字直接连起来了,但其实它们是分开的
Jooooooooo
2021-12-31 12:45:39 +08:00
final 设计就是如此.
Shawlaw
2021-12-31 13:11:06 +08:00
对象时,final 的是“指针”,定义如此。
xiao109
2021-12-31 13:14:20 +08:00
说明你还是没弄清 java 里基础类型和引用类型的区别
xiao109
2021-12-31 13:16:24 +08:00
简单一点理解就是 final 修饰的变量不能再用=操作符去操作了。
adeng
2021-12-31 13:17:40 +08:00
@Newyorkcity 你有问题,你在按照自己的想法去套,seanzxx 说的很清楚了。你说的“一个数组”,这个数组要有名字,定为 arr ,arr 指向 内存地址 addr1 ,你所谓的“A 时间点”,addr1 啥元素也没有;“B 时间点”有几个元素,addr1 没变成别的啊,addr1 内存还是那块内存,没变成 addr2 内存。arr = addr1 ,始终没有变。
kera0a
2021-12-31 13:18:12 +08:00
楼主肯定明白值类型和引用类型,楼主应该说的是 final 这个概念,应该是只针对指针值不变,还是把指针指向的对象也保护不变。java 中对此的定义是只是保证值不变。

但有些语言例如 swift 的 Array , 使用 let 修饰就会保护 Array 对象不变
kratzer
2021-12-31 13:21:31 +08:00
final 证件号=你
kratzer
2021-12-31 13:24:22 +08:00
证件号就不能再指定给她 /他了
你可以变胖,减肥,变形
Leviathann
2021-12-31 13:36:08 +08:00
swift 是这样的
yaphets666
2021-12-31 13:41:28 +08:00
list 有个地址对吧,有一个变量 a 存储着这个 list 的地址, 你 final 的是变量 a ,不是 list 。
cndotaer
2021-12-31 13:45:04 +08:00
https://docs.oracle.com/javase/specs/jls/se7/html/jls-4.html#jls-4.12.4
If a final variable holds a reference to an object, then the state of the object may be changed by operations on the object, but the variable will always refer to the same object.
dinghmcn
2021-12-31 13:52:05 +08:00
cpp 双 const 能保证值和引用都不能改变,java 其实模糊了值和引用才导致这种理解的偏差
nonoyang
2021-12-31 14:04:37 +08:00
java 归根到底还是值传递,从这个角度看这个 final 没啥问题,说不定未来 jdk20 就支持了呢。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/825448

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX