-1

我無法理解這是如何工作Java對象引用和Java方法

public void addToRule(Rule r) { 
    if (!getRuleList().contains(r)) { 
     getRuleList().addElement(r); 
    } 
} 

如果我運行此代碼:

obj.addToRule(r); 
System.out.println(getRuleList().contains(r)); 

它打印出true這怎麼可能發生?

btw ruleList是主類的向量成員,不是靜態變量(不要認爲這很重要,但無論如何共享)。

import java.util.Vector; 


public class RuleEngine{ 

    private Vector ruleList = new Vector(); 

    public Vector getRuleList(){ 
     return ruleList; 
    } 

    public void addToRule(Rule r){ 
     if(!getRuleList().contains(r)) 
      getRuleList().addElement(r); 
    } 

    public static void main(String args[]){ 
     RuleEngine re = new RuleEngine(); 
     Rule r = new Rule("Rule1"); 
     re.addToRule(r); 
     System.out.println(re.getRuleList().contains(r)); 
    } 
} 

class Rule{ 
    public String name = ""; 
    public Rule(String nam){ 
     this.name=nam; 
    } 
} 

確定人們告訴我,這是因爲在Java中通過引用傳遞。我知道了。但我能做些什麼來獲得該對象的副本而不是其參考?

+0

它應該返回true。無論如何,問題是什麼?!重新格式化您的代碼,使其更加可理解,否則其他人會給你-1 ;-) – lzap

+0

我無法理解此行爲 – MozenRath

+0

它不編譯... – dacwe

回答

0

從您的評論看來,您似乎還沒有完全理解Java中的值和引用之間的區別。基本上,對象總是作爲Java中的引用傳遞。

考慮

class Test { 
    private List list = new ArrayList(); 
    public List getList() { 
     return list; 
    } 
} 

getList()方法將一個參考返回到list對象。它會而不是返回list對象的副本。以來的首次getList()被稱爲做這樣的事情

Test test = new Test(); 
String s = "ABC"; 
test.getList().add(s); 
System.out.println(test.getList().contains(s)); 

將返回true,一個referece到返回列表,在這些add(s)被調用。第二次調用getList()時,它會將引用返回到相同的列表,而不是它的副本,而不是新列表 - 同一個引用。調用contains(s)將返回true,因爲它與添加對象s的列表相同。

但是請考慮這一點。

Test test1 = new Test(); 
Test test2 = new Test(); 
String s = "ABC"; 
test1.add(s); 
System.out.println(test2.getList().contains(s)); 

這將打印出「false」。爲什麼? test1.getList()返回對內部列表的引用test1test2.getList()返回對test2內部列表的引用。在此,s已添加到test1:s列表中,因此它不會包含在test2:s列表中。

+0

當我實現該方法會發生什麼'addToRule()'這樣的: \t'公共無效addToRule(規則r){ \t \t如果(!getRuleList()。contains(r)){ \t \t \t Vector list = getRuleList(); \t \t \t list.addElement(r); \t \t} \t} ' – MozenRath

+0

我試過並發現它仍然是正確的。我能做些什麼來獲得規則列表的副本而不是參考? – MozenRath

+0

這取決於。你想只包含與原始列表相同的對象引用的列表副本嗎?如果是這樣,您可以使用addAll方法(http://download.oracle.com/javase/6/docs/api/java/util/Collection.html#addAll%28java.util.Collection%29)。如果您希望它包含列表中所有對象的副本,則必須手動克隆所有對象並將它們添加到新列表中。請參閱http://download.oracle.com/javase/6/docs/api/java/lang/Object.html#clone%28%29。 – pap

0

它應該始終打印true,因爲您將規則添加到規則列表中,以防它不在那裏。什麼情況是:

  • 你告訴要添加的對象增加一條規則,其規則列表
  • 對象檢查如果規則存在,如果沒有,將其添加

所以它保證在代碼執行後包含規則。

+0

是的,但我不打電話給我添加規則的規則列表的副本。我認爲適當的代碼應該是:if(!getRuleList())。包含(r)){setRuleList(getRuleList()。addElement(r)); }' – MozenRath

+1

你爲什麼不告訴我們完整的代碼? – Bozho

+0

看我不希望它發出虛假。這是我正在查看的一些先前存在的代碼,並且我們無法理解什麼時候可以做到這一點,什麼時候做不到。 – MozenRath

1

我猜getRuleList()正在返回一個參考到列表(或類似的東西)。如果您熟悉C,請將其視爲指針(或更具體地說,指針的副本)。當您致電getRuleList()時,您正在處理該對象的相同底層實例。

爲了證明,請嘗試:System.out.println(getRuleList() == getRuleList()); ==運算符只會比較兩個引用是否指向同一個對象(不是深度等於.equals)。你會看到,直到你撥打setRuleList()與不同的對象參考該聲明成立。

這些假設當然沒有看到你的完整代碼。

1

因此,要回答您的問題,您必須首先了解Java如何傳遞變量。

可變具有值:

int i = 1234; 
Person p = new Person("Peter"); 

現在,將變量i正好包含1234,而變量P包含所創建的人的記憶ADRESS。

所以我包含1234和p包含地址(讓我們說a4dfi3)。

anyMethodYouLike(p); 
System.out.println(p.getName()); 
public void anyMethodYouLike(Person somePerson) { 
    somePerson.rename("Homer"); 
} 

所以在這個例子中,我們給這個方法anyMethodYouLike變量p ... wait!我們給方法賦值變量(a4dfi3)。該方法然後調用這個變量的重命名(它仍然與p有相同的地址,因此它修改了p指向的同一個人)。 因此,在方法之後,人物p的名字指向,得到打印,這導致「Homer」。

someOtherMethod(p); 
System.out.println(p.getName()); 
public void someOtherMethod(Person somePerson) { 
    somePerson = new Person("Walter"); 
} 

在這個例子中,我們仍然給我們的人的地址稱爲「彼得」的方法。但是這一次,該方法在somePerson中創建了一個新的Person(因此在一些Person中重寫了地址,讓我們說13n37s。 但是!a4dfi3的Person沒有改變!print print仍然輸出「Peter」而不是「Walter 」

現在,讓我們來看看這個行爲與原語:

someMethod(i); 
System.out.println(i); 
public void someMethod(int someInt) { 
    someInt++; 
} 

所以,我的價值(1234)被傳遞給someInteger然後someInteger被遞增到1235,但我仍然是1234。

這是Java中的對象和原語之間的最大區別

希望我能幫到, Ferdi265