-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