【问题标题】:passing object reference to a method in java confusions [duplicate]将对象引用传递给java混淆中的方法[重复]
【发布时间】:2021-09-20 06:24:12
【问题描述】:

我很困惑为什么在第一个代码(代码 1)中,myCounter 指向的对象在传递给方法“print”后被更新为值 2。 但是在第二个代码(代码 2)中,str 指向的对象仍然是同一个字面量“This is a string literal”。我认为 str(str 是一个对象引用,就像我认为的 myCounter 一样)经历相同的机制,因为它也被传递给一个方法,所以它不应该像 myCounter 一样更新吗?

这是代码 1:

public class PrimitiveVsReference{

private static class Counter {
    private int count;

    public void advance(int number) {
        count += number;
    }

    public int getCount() {
        return count;
    }
}

public static void main(String args[]) {        
    int i = 30;
    System.out.println("value of i before passing to method : " + i);
    print(30);
    System.out.println("value of i after passing to method : " + i);
    
    Counter myCounter = new Counter();
    System.out.println("counter before passing to method : " + myCounter.getCount());// this gives 0
    print(myCounter); 
    System.out.println("counter after passing to method : " + myCounter.getCount());// now this gives 2 after passing into the method "print"
}

/*
 * print given reference variable's value
 */
public static void print(Counter ctr) {
    ctr.advance(2);
}

/**
 * print given primitive value
 */
public static void print(int value) {
    value++;
}
}

代码 2:

String str = "This is a string literal.";

public static void tryString(String s)
{
    s = "a different string";
}

tryString(str); // isn't this here doing the samething as when myCounter is passed to print in Code 1?
System.out.println("str = " + str); // But this here output the original literal "This is a string literal."

有人可以解释发生了什么吗?

【问题讨论】:

  • 这是修改对象内容(代码1)和创建新对象(代码2)的区别。
  • @MarkRotteveel 所以根据你所说的,user16320675 的第二个答案(没有得到任何投票的解释)是正确的推理。第一个答案(有 2 个赞成票的那个)给出的推理不是正确的答案(即它与不可变或可变无关,对吧?)。这是正确的吗?因为我想了解正确的解决方案。
  • 是的,没错。事实字符串是不可变的与此无关(如果您在代码 1 中的 print 中使用了 ctr = new Counter(),并且 Counter 是一个可变对象,也会发生同样的情况)。
  • @MarkRotteveel 哦,感谢您指出正确的解决方案。

标签: java


【解决方案1】:

由于字符串是不可变的(“一旦创建了 String 实例,就永远不会更改 String 实例的内容”),该赋值创建了一个新的字符串对象,该对象是引用的副本现在指向。原始引用仍然指向“这是一个字符串文字。”

您可以尝试使用StringBufferStringBuilder 并看到不同的结果。

【讨论】:

  • 但是 myCounter 怎么样,您能解释一下为什么要更新 myCounter 吗?
  • 你能解释一下“那个赋值创建一个新的字符串对象”是什么意思吗?是哪个任务?还有“引用的副本现在指向”的含义?谢谢
  • @user16320675 所以它与 str 是否可变无关? str 在这里是一个字符串。但是如果 str 是其他一些类型,说是 A 类型的对象,我们将这个对象 A 传递给方法 tryString(A str){ s = str;} (所以假设 tryString 接受 A 类型的参数),这是否意味着现在 s在赋值s = str 发生后存储对象str 的地址(即堆内存中的地址)?有人可以解释更多。所以它与可变或不可变无关?对吗?
  • @user16320675 那么你能解释一下为什么在第二个代码中,str 没有得到更新吗?但在第一个代码(代码 1)中,对象 myCounter 得到更新?
【解决方案2】:

我将尝试使用 StringBuilder - 一个可变对象 - 基于相关代码发布的 cmets 来说明我的意思。

代码 1

public static void main(String[] args) {
    StringBuilder builder = new StringBuilder("abc");
    System.out.println("before passing to method: " + builder);
    method(builder);
    System.out.println("after passing to method: " + builder);
}

private static void method(StringBuilder bld) {
  bld.append("def");
}

应该输出:

before passing to method: abc
after passing to method: abcdef

上面的代码中只有一个StringBuider的实例,正在改变和显示的那个


代码 2

private static final StringBuilder ANOTHER_ONE = new StringBuilder("a different string");

public static void main(String[] args) {
    StringBuilder builder = new StringBuilder("abc");
    System.out.println("before passing to method: " + builder);
    method(builder);
    System.out.println("after passing to method: " + builder);
}

private static void method(StringBuilder bld) {
  bld = ANOTHER_ONE;  // or bld = new StringBuilder("a different string")
}

应该输出:

before passing to method: abc
after passing to method: abc

以上代码中有两个StringBuider实例;一个正在显示,另一个被分配到method


可以看出,即使对象是可变的,对参数的赋值也不会体现在调用方法时使用的变量中。实际上它是一个表达式,产生一个值,用于初始化方法的参数——在这个具体的例子中,表达式恰好只是一个变量。

你可以想到
s = "a different string"
相似1
s = new String(new char[] {'a', ' ', 'd', 'i', 'f', 'f', 'e', 'r', 'e', 'n', 't', ' ', 'S', 't', 'r', 'i', 'n', 'g'})

1 - 缺少对 intern() 的调用,因此它也被作为所有文字(也更难阅读和输入)进行了实习

【讨论】:

  • 哦,谢谢。我会尝试理解您的代码,因为有时我需要理解。但是,如果那里的解释不正确,为什么人们会赞成 Veke 的第一个答案。
  • 所以我不相信真正的原因是“因为字符串是不可变的”。所以这不是正确的推理。所以我会把你的作为正确的推理。但只是困惑为什么人们现在支持不正确的答案。
  • 这让我更加困惑。
猜你喜欢
  • 2014-05-01
  • 1970-01-01
  • 1970-01-01
  • 2013-10-05
  • 2019-05-05
  • 2016-04-02
  • 1970-01-01
  • 2013-09-15
  • 1970-01-01
相关资源
最近更新 更多