2012-02-07 236 views
2

我想問一個非常簡單的問題。我只是將一個String對象傳遞給一個函數,但結果很奇怪。我認爲,因爲我傳遞了一個對象(通過引用),結果應該是「Here」而不是「Hello」。這是爲什麼發生?將字符串傳遞給函數

public class MainStr 
{ 

/** 
* @param args 
*/ 
public static void main(String[] args) 
{ 
    String str = "Hello!"; 
    System.out.println(str); 
    changeString(str); 
    System.out.println(str); 


} 

static void changeString(String str) 
{ 
    str=" HERE"; 
} 

} 

謝謝。

編輯:

public class MainStr 
{ 

String str; 
/** 
* @param args 
*/ 
public static void main(String[] args) 
{ 
    MainStr ms = new MainStr(); 
    ms.str = "Hello!"; 
    System.out.println(ms.str); 
    changeString(ms); 
    System.out.println(ms.str); 


} 

static void changeString(MainStr ms) 
{ 
    ms.str=" HERE"; 

} 

} 

如果是這樣的話,那麼爲什麼如果我通過它的包裝對象內部的工作?包裝對象,它不是通過引用?

PS:爲什麼這樣工作?字符串是一個對象。爲什麼我需要另一個包裝對象來更改對象!如果我想通過引用傳遞某些東西會怎麼樣?那可能嗎?

+0

Java正在處理所有複雜類型的引用。字符串和所有使用的定義類型都由引用表示。你可以把引用看作一個你無法訪問的C++指針。 – 2012-02-07 21:14:54

+0

@salamis Remeber Java永遠是傳值!形式參數(這是方法changeString中的str)只是指向內存位置的引用的副本,其中「Hello!」是。因此,當您現在指定「HERE」而不是指向「Hello!」時指向「這裏」,而原始的不變。 「HERE」將被垃圾收集。 – MalsR 2012-02-07 21:22:02

回答

7

Java按值傳遞對象引用,這意味着當您調用函數時會發生以下情況。

String origStr = "Some String" 

// origStr -> "Some String " 

當對象被傳遞給它看起來像這樣

//origStr -> "Some String " <- passedStr 

然後在功能重置什麼passedStr點

//origStr -> "Some String " 
//passedStr -> "Other String" 

原始字符串還是指「值一些字符串「,但它的副本現在引用」其他字符串「

當您返回時m函數原始字符串引用仍指向「一些字符串」

//編輯:爲什麼你可以修改另一個對象引用的對象?

可以說我有StringWrapper,它是一個包含字符串的類。

去渣,看起來像這樣

origStr -> strWrpA -> "Some String" 

當你把它傳遞給函數的以下情況就像上面

origStrWrp -> strWrpA -> "Some String" 
passedStrWrp --/^ 

注意這兩個變量如何在內存中指向strWrpA。 現在如果我決定修改strWrpA.myString,Java將 跟在指向包裝器中實際字符串的指針。到strWrpA的指針 將保持不變。 這意味着我可以更改對象的內容,即使 我通過原始參考的副本訪問它。

     "Some String " 
origStrWrp -> strWrpA -> "I got Changed!" 
passedStrWrp --/^ 

,如果你這樣做

//Does Nothing 
function (origStrWrp) 
{ 
origStrWrp=new StringWrapper("Other String") // This only reassigns the copy of the reference and would give you the same problem 
} 
//Changes internal object 
function (origStrWrp) 
{ 
origStrWrp.myString = "Other String" // This doesn't change the reference, it changes the object that it refers to. 
} 
+0

爲什麼這不會發生與其他對象? – glarkou 2012-02-07 21:02:29

+0

是什麼讓你覺得它不是? – RussS 2012-02-07 21:03:26

+0

因爲如果我使用包裝對象它的工作。我可以發佈一些代碼,如果你想! – glarkou 2012-02-07 21:04:22

0

str=" HERE";實際上改變了str指向的對象。它不會更改原始對象。如果您想修改原始文件,請將其放入包裝對象中。

實施例:

public class MainStr { 

    static class StringWrapper { 
     public String str; 
    } 

    public static void main(String[] args) { 
     StringWrapper foo = new StringWrapper(); 
     foo.str = "Hello!"; 
     System.out.println(foo.str); 
     changeString(foo); 
     System.out.println(foo.str); 
    } 

    static void changeString(StringWrapper str) 
    { 
     str.str = "Bye!"; 
    } 
} 
+0

如果只有'字符串是可變的... – 2012-02-07 20:55:58

+0

@他不可變有一些好處:http://stackoverflow.com/questions/3407403/whats-the-advantage-of-a-string-be-immutable – mtsz 2012-02-07 20:58:31

+0

@他通過「修改」我的意思是把它設置爲別的東西(即改變它指向的對象,而不是內部數據) – jli 2012-02-07 20:59:41

0

是,爪哇通過引用傳遞類參數。不可能告訴它以其他方式做。

您可以將字符串包裝到另一個類中或使用庫中的StringBuilder

P.S.

str =「HERE」;

只是將舊引用替換爲指向" HERE"的新引用。這不會觸及函數外部的舊引用str。

P.P.S.

也許我的術語是錯誤的。所以,簡單地說,String類型的Java變量包含對該字符串的引用。該引用被傳遞到函數中。賦值正在改變一個引用,而不是原始對象。

+2

它通過值傳遞,而不是引用。 – Max 2012-02-07 21:01:42

+0

Java是通過引用傳遞的。例如,函數可以修改StringBuilder。當然,參考本身是通過價值傳遞的。 – 2012-02-07 21:08:02

2

字符串在Java中是不可變的。爲了這個工作,你需要從hangeString方法返回新創建的字符串實例。

static String changeString(String str) 
{ 
    return " HERE"; 
} 
4

在Java引用中按值傳遞。這裏是popular SO discussion來理解這個話題。引用str的作用域僅限於將引用作爲值傳遞給changeString方法。

+0

請檢查編輯的問題。 – glarkou 2012-02-07 21:09:56

+0

還值得在薩拉米斯上面的鏈接閱讀;)這很有趣。你會發現這個鏈接有幫助http://javadude.com/articles/passbyvalue.htm?repost – MalsR 2012-02-07 21:57:07

0

你混合的東西你也有同樣的問題,因爲你有沒有包裝。 雖然這兩個變量被稱爲「STR」他們是在不同的「範圍」

第一隻是你主要方法 內有效,而第二隻是你changeString方法內有效。

看來,如果你想完成你的使用changeString使主要方法中可用的變化的目標;你必須:

一)創建方法之外的變量 - 這樣就會有一個類(全球)範圍:

喜愛 份額[G +]共享[FB]共享[TW]

我想問一個非常簡單的問題。我只是將一個String對象傳遞給一個函數,但結果很奇怪。我認爲,因爲我傳遞了一個對象(通過引用),結果應該是「Here」而不是「Hello」。這是爲什麼發生?

public class MainStr 
{ 
String str = null; 

public static void main(String[] args) 
{ 
    str = "Hello!"; 
    System.out.println(str); 
    changeString(); // there is no argument to supply 
    System.out.println(str); 


} 

static void changeString() 
{ 
    str= str + " HERE"; // variable is changed here 
} 

} 

二)讓changeString返回一個字符串,並使用:

public class MainStr 
{ 

/** 
* @param args 
*/ 
public static void main(String[] args) 
{ 
    String str = "Hello!"; 
    System.out.println(str); 
    str = changeString(str); // str has return value assigned to it! 
    System.out.println(str); // otherwise it would print out 'Hello!' 


} 

static String changeString(String str) 
{ 
    str = str.concat(" HERE"); 
    return str; 

} 
} 

注:在第二個選項 (b)您仍然是兩個變量,不同的範圍和名稱相同。

,而在第一個選項(A)只有一個,在整個

希望這闡明你的疑惑變量。

祝你好運!

Nicolas