我最近被问到了这个问题。但是无法简明扼要地解释这两个概念的确切区别。
例如
最终和永恒不变:
getResources().getString(R.string.my_server)
如果我现在写
final String name = "John";
我会收到编译错误
不可变:
name = "Sam";
它有效。
我认为这解释了应用程序中的一部分。但是,我可以对这两个主题得到一个好的,易于理解的解释吗?
答案 0 :(得分:45)
final
表示您无法将对象的引用更改为指向另一个引用或其他对象,但您仍然可以改变其状态(使用setter)方法,例如)。 不可变意味着对象的实际值无法更改,但您可以将其引用更改为另一个。
关于问题的第二部分(不变性部分),编译器创建一个新的String
对象,其值为" Sam",并指向name
对它的引用
答案 1 :(得分:15)
final
确保对象的地址保持不变。其中Immutable
表示我们无法在创建后更改对象的状态。
final
只是一个关键字,而Immutable
是一种模式。
如果是您的第一个问题,您已将变量标记为
final
,这意味着您将无法更改其内存地址,并且无法再次分配值。如果您的第二个问题
Immutable
确保您无法更改您创建的对象的状态。
答案 2 :(得分:4)
对象无法更改。
final String s = "Hello";
// Not allowed.
s = "Bye";
无法更改对象的内容。
BigInteger one = BigInteger.ONE;
// Does not change `one` or `BigInteger.ONE`.
one.add(BigInteger.ONE);
// Have to do it this way.
BigInteger two = one.add(one);
答案 3 :(得分:4)
当您将某个字段声明为final
时,该引用将不会更改。它总是指向同一个对象。
如果Object不是immutable
,则其上的方法可用于更改Object本身 - 它是相同的Object,但其属性已更改。
答案 4 :(得分:4)
当您更改String时,创建新的String对象('abcdef')并将引用从'abce'更改为'abcdef'。但是您无法删除的 'ABCD'即可。只更改参考。这是不可改变的。
<强>最终强>
实际上最终是关键字。当您将其添加到变量时,您无法更改参考。
答案 5 :(得分:2)
当您使用关键字&#34; final&#34;时,这意味着您无法更改变量指向的对象的引用。因此,在这种情况下变量&#34; name&#34;不能指向另一个字符串对象。但请注意,我们可以更改对象的内容,因为我们使用的是最终引用。此外,java中的字符串本质上是不可变的。即你不能改变它的内容。 因此,在您的情况下,final将对字符串对象进行最终引用。并且由于您无法将变量更改为指向另一个字符串对象,因此代码将失败。
请参阅以下代码以了解最终变量的工作情况。
public class test {
public static void main(String[] args) {
final A aObject = new A();
System.out.println("Old value :" + aObject.a);
aObject.a = 2;
System.out.println("New value :" + aObject.a);
}}
class A {
public int a = 1;}
答案 6 :(得分:1)
不可变意味着一旦对象的构造函数完成执行,该实例就不能被更改。
这很有用,因为它意味着你可以传递对象的引用,而不用担心其他人会改变它的内容。特别是在处理并发时,对于永不改变的对象没有锁定问题
e.g。
class Foo
{
private final String myvar;
public Foo(final String initialValue)
{
this.myvar = initialValue;
}
public String getValue()
{
return this.myvar;
}
}
Foo不必担心getValue()的调用者可能会更改字符串中的文本。
如果你想象一个类似于Foo的类,但是使用StringBuilder而不是String作为成员,你可以看到getValue()的调用者能够改变Foo实例的StringBuilder属性。
final是Java中的保留关键字,用于限制用户,它可以应用于成员变量,方法,类和局部变量。最终变量通常在Java中使用static关键字声明,并被视为常量。例如:
public static final String hello =&#34; Hello&#34 ;; 当我们将final关键字与变量声明一起使用时,存储在该变量中的值不能在后面改变。
例如:
public class ClassDemo {
private final int var1 = 3;
public ClassDemo() {
...
}
}
注意:声明为final的类不能被扩展或继承(即,不能有超类的子类)。值得注意的是,声明为final的方法不能被子类覆盖。
使用final关键字的好处在此thread
中得到了解决答案 7 :(得分:0)
不可变:字符串和包装类是不可变的。由于String常量池,它们不能在对象内部更改它们的值,但是它们可以更改包含不同值的对象的引用。
String s1 = new String("cant't change");
最终:当我们创建String
的引用时Final String s2 = "cant't change";
s2
的引用指向其内部具有“无法更改”值的对象。
现在,引用s将始终指向保持值“无法更改”的对象。它的参考不能改变。
答案 8 :(得分:0)
final String name = "John";
当您编写以上代码时,您的代码告诉编译器引用name
将始终指向相同的内存位置。现在为什么要说内存位置,因为引用所指向的对象可能像数组或整数列表那样易变。因此,如果我说final int[] arr = {5,6,1};
我可以做arr[2] = 3;
但我不能做arr = {3,4,5}
,因为您将尝试为最终分配一个新的int[]
>变量arr
,它是一个新的内存位置,看到此编译器将显示错误。
String name = "John";
name = "Sam";
类型为name
的{{1}}变量为不可变,因为Java中的String
为String
,这意味着您无法更改状态一旦创建引用immutable
所指向的对象,即使将其更改为name
,它现在也是一个不同的对象,它由引用Sam
和上一个对象所指向name
将没有引用,并且如果没有其他引用指向垃圾回收器,则它可以在运行时被垃圾回收器收集。