2011-04-06 62 views
74

我知道這可能是非常愚蠢的,但是要求很多地方,在Java的Integer類是不可變的,但下面的代碼:是整數永恆

Integer a=3; 
Integer b=3; 
a+=b; 
System.out.println(a); 

執行沒有給予任何麻煩(預期)結果6.如此有效地改變了a的值。這不是說Integer是可變的嗎? 第二個問題和一些小題目:「不可變類不需要拷貝構造函數」。任何人都在意解釋爲什麼?

+12

該類是不可變的,但自動裝箱正在發生時髦的事情發生:http://stackoverflow.com/questions/3085332/comparison-between-variables-pointing-to-same-integer-object – birryree 2011-04-06 00:31:19

+0

謝謝,拳擊是關鍵字我需要谷歌:) – 2011-04-06 00:37:52

+6

你正在混淆不變值與最終值或常量值。 – 2013-08-14 06:43:03

回答

77

不可變並不意味着a永遠不能等於另一個值。例如,String是不可改變的,但我卻仍然可以這樣做:

String str = "hello"; 
// str equals "hello" 
str = str + "world"; 
// now str equals "helloworld" 

到底發生了什麼呢?由於String是不可變的,因此明確str未被更改。但它現在等於不同的東西。這是因爲str現在是一個完全新實例化的對象,就像你的Integer一樣。所以a的值沒有變化,但它被一個全新的對象取代,即new Integer(6)

+11

「這是因爲str現在是一個完全新實例化的對象」。或者,相反,str(varibale)_points_指向一個新的對象。對象本身不可變,但由於變量不是最終的,它可以指向不同的對象。 – Sandman 2011-04-06 07:20:52

+0

是的,它指向由'+ ='操作實例化的另一個對象。 – 2011-04-06 12:20:44

+9

嚴格地說,它*不需要*是一個*新*對象。拳擊使用'Integer.valueOf(int)',該方法維護'Integer'對象的緩存。所以'Integer'變量上'+ ='的結果可能是之前存在的一個對象(或者它甚至可以是同一個對象......在'a + = 0'的情況下)。 – 2012-05-01 01:11:52

41

a是「參考」,以一些整數(3),你的速記a+=b真正意義做到這一點:

a = new Integer(3 + 3) 

所以,不,整數是不可變的,而是指向它們的變量是*。

*很可能有一成不變的變量,這些用關鍵字final,這意味着基準可能不會改變表示。

final Integer a = 3; 
final Integer b = 3; 
a += b; // compile error, the variable `a` is immutable, too. 
3

不可變並不意味着您不能更改變量的值。這只是意味着任何新的任務都會創建一個新對象(爲其分配一個新的內存位置),然後將值分配給它。

要了解自己這一點,在一個循環中執行整數分配(與循環外部聲明整數),並期待在內存中的活動對象。

複製構造函數不需要不可變對象的原因很簡單。由於每個作業都會創建一個新對象,因此該語言在技術上已經創建了一個副本,因此您不必創建另一個副本。

4

是整數是不可變的。

A是指向一個對象的引用。當你運行一個+ = 3時,它重新賦值A來引用一個新的Integer對象,並使用不同的值。

您從未修改原始對象,而是指向不同對象的引用。

閱讀對象和引用here之間的差異。

2

「不可改變的類不需要拷貝構造函數」。任何人都在意解釋爲什麼?

的原因是,有很少任何需要複製(或複製甚至沒有任何一點),一個不可改變的類的實例。對象的副本應該與原來的「一樣」,如果相同,則不需要創建它。

有一些基本的假設,但:

  • 它假定您的應用程序不放在類的實例的對象標識任何意義。

  • 它假定該類已經超載equalshashCode,以便根據這些方法實例的副本與原始副本相同。

任何一個或兩個這些假設的可能是假的,也可以擔保的另外一個拷貝構造函數。

16

您可以確定該對象已使用System.identityHashCode()改變(一個更好的辦法是使用純==但其並不明顯,與其值已更改參考)

Integer a = 3; 
System.out.println("before a +=3; a="+a+" id="+Integer.toHexString(System.identityHashCode(a))); 
a += 3; 
System.out.println("after a +=3; a="+a+" id="+Integer.toHexString(System.identityHashCode(a))); 

打印

before a +=3; a=3 id=70f9f9d8 
after a +=3; a=6 id=2b820dda 

你可以看到對象a的底層「id」指已經改變。

+0

System.identityHashCode()是一個非常好的提示。謝謝你。 – 2017-03-24 12:50:55

9

要問最初的問題,

Integer a=3; 
Integer b=3; 
a+=b; 
System.out.println(a); 

Integer是不變的,所以什麼事情上面是「A」變爲價值6.新的參考初始值3留在沒有參考內存(它沒有被改變),所以它可以被垃圾回收。

如果發生這種情況的字符串,它會保留在池中(在PermGen空間中)比整數更長的時間段,因爲它期望有引用。

0

我可以明確指出的整數(和其他的信條一樣浮的,短片等)都是通過簡單的示例代碼不變:

示例代碼

public class Test{ 
    public static void main(String... args){ 
     Integer i = 100; 
     StringBuilder sb = new StringBuilder("Hi"); 
     Test c = new Test(); 
     c.doInteger(i); 
     c.doStringBuilder(sb); 
     System.out.println(sb.append(i)); //Expected result if Integer is mutable is Hi there 1000 
    } 

    private void doInteger(Integer i){ 
     i=1000; 
    } 

    private void doStringBuilder(StringBuilder sb){ 
     sb.append(" there"); 
    } 

} 

實際結果

結果涉及到他您好有100(在兩個SB的情況下,和i是可變對象),而不是預期的結果您好有1000

這表明通過我在主創建的對象沒有被修改,而sb被修改。

所以StringBuilder演示了可變行爲但不是整數。

因此Integer是不可變的。因此,事實證明

另一個不只是整數代碼:

public class Test{ 
    public static void main(String... args){ 
     Integer i = 100; 
     Test c = new Test(); 
     c.doInteger(i); 
     System.out.println(i); //Expected result is 1000 in case Integer is mutable 
    } 

    private void doInteger(Integer i){ 
     i=1000; 
    } 


} 
+0

你正在做兩件不同的事情 - 試圖重新分配整數並在stringbuilder上調用一個方法。如果你做'private void doStringBuilder(StringBuilder sb){sb = new StringBuilder(); }'然後'sb'不變。 – MT0 2016-04-04 08:10:42

+0

我添加了StringBuilder(這是可變的),以便將Integer與另一個可變對象並置。如果你想要的話,你可以刪除所有與StringBuilder相關的代碼,只需打印出我看到100. – 2016-04-04 08:20:28

+0

@ MT0添加了極簡代碼供您參考。 – 2016-04-04 08:23:47

0

這是我的理解不變

int a=3;  
int b=a; 
b=b+5; 
System.out.println(a); //this returns 3 
System.out.println(b); //this returns 8 

如果INT可能會變異, 「一」 將打印8但它並不是因爲它是不可變的,所以它是3.你的例子只是一個ne分配。

-1
public static void main(String[] args) { 
    // TODO Auto-generated method stub 

    String s1="Hi"; 
    String s2=s1; 

    s1="Bye"; 

    System.out.println(s2); //Hi (if String was mutable output would be: Bye) 
    System.out.println(s1); //Bye 

    Integer i=1000; 
    Integer i2=i; 

    i=5000; 

    System.out.println(i2); // 1000 
    System.out.println(i); // 5000 

    int j=1000; 
    int j2=j; 

    j=5000; 

    System.out.println(j2); // 1000 
    System.out.println(j); // 5000 


    char c='a'; 
    char b=c; 

    c='d'; 

    System.out.println(c); // d 
    System.out.println(b); // a 
} 

輸出是:

嗨 再見 千千 d 一個

所以焦炭是可變的,字符串整數和INT是不可改變的。

+0

此答案不提供任何其他信息。 – 2017-10-09 12:51:39