java中的immutable和final有什么区别?

时间:2015-12-04 11:48:55

标签: java

我最近被问到了这个问题。但是无法简明扼要地解释这两个概念的确切区别。

例如

最终和永恒不变:

getResources().getString(R.string.my_server)

如果我现在写

final String name = "John";

我会收到编译错误

不可变:

name = "Sam";

它有效。

我认为这解释了应用程序中的一部分。但是,我可以对这两个主题得到一个好的,易于理解的解释吗?

9 个答案:

答案 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)

<强>不可变: http://www.programcreek.com/2009/02/diagram-to-show-java-strings-immutability/

当您更改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中的StringString,这意味着您无法更改状态一旦创建引用immutable所指向的对象,即使将其更改为name,它现在也是一个不同的对象,它由引用Sam和上一个对象所指向name将没有引用,并且如果没有其他引用指向垃圾回收器,则它可以在运行时被垃圾回收器收集。