为什么这个Java应用程序会打印出“true”?

3

这是我的第一个类Hello.java。

public class Hello {
    String name = "";
}

这是我的第二个Class Test1.java

public class Test1 {    
    public static void main(String[] args) {
        Hello h = new Hello();
        Test1 t = new Test1();
        t.build(h);
        System.out.println(h.name);
    }
    void build(Hello h){
        h.name = "me";
    }
}

当我运行Test1.java时,它会打印出“me”。我认为我理解了,因为存在“引用传递”的原因。
这是我的第三个类Test2.java。
public class Test2 {
    public static void main(String[] args) {
        Hello h = null;
        Test2 t = new Test2();
        t.build(h);
        System.out.println(h == null);
    }
    void build(Hello h){
        h = new Hello();
    }
}

当我运行Test2.java时,它会打印出“true”,为什么?这是因为“引用传递”不再存在吗?我感到困惑。

2
可能是Java是按引用传递吗?的重复问题。 - polygenelubricants
Java 通过值传递参数。Java 通过值传递引用。 - polygenelubricants
1
这么多括号?是前Lisp程序员吗?:-P - Federico klez Culloca
9个回答

7

您可能已经知道,Java是按值传递的。当您传递一个引用时,该引用会被复制。确切地说,只有引用本身而不是引用的目标会被复制。

让我们看一下第一个示例:当调用build()时,引用h将被复制。因为h(在build()中的副本)没有在build()的某个地方被覆盖,所以它始终指向原始h的内存位置。因此更改h.name会影响原始的h

第二个示例不同:引用h也被复制。但是,在build()中,h被覆盖了。其效果是原始的hbuild()中的h指向不同的内存位置!build()中的h指向新生成的Hello对象,该对象将在build()方法返回后的某个时间被垃圾回收。


3

Java始终是按值传递的。当您拥有引用时,它只传递指向同一对象的引用的副本。在您的情况下,您只需将复制的引用重新路由到另一个对象即可。这就是为什么您的原始引用没有更改的原因。


1

你有两个不同的变量 h。第一个是局部变量在 main 中。第二个是局部变量在 build 中。

如果你将你的 build 变量重命名为 x,那么为什么 main 中的 h 不受影响就会变得明显。

编辑:

public class Test2 {
    public static void main(String[] args) {
        Hello h = null;
        Test2 t = new Test2();
        t.build(h);
        System.out.println(((h == null)));
    }
    void build(Hello x){
        x = new Hello();
    }
}

在这里,您可以清楚地看到,x 最初是 null。然后,x 成为一个新对象。然后,x 死亡了。h 对于 x 的生死状态一无所知。


0
首先,您需要了解对象和引用之间的区别。
在第一种情况下,您直接访问对象(堆内存)并更改值,而在第二种情况下,引用将具有新对象,直到方法结束。之后它将不再可访问。
    public static void main(String[] args){
           String str = null;
           System.out.println(getString(str)== null);
   }

    public static String getString(String s){
            s = new String();
            return s;
    }

以上代码将打印false

0

h.name = "me" 改变了被 h 引用的对象。这个改变会在任何其他引用同一个对象的地方可见。 h = new Hello() 使得 h 引用另一个(新的)对象。这个改变只影响到特定的变量 h - 不会影响之前引用同一对象的任何其他变量。


0

0
在Test1.java中,当您将Hello对象h传递给build()方法时,变量main().hbuild().h指向同一个内存中的对象。
main().h = build().h => 指向同一对象 但是在Test2.java中,即使您将main().h传递给build()方法,后来在build方法内部,您仍然将build().h重新指向了一个新对象。 但这不会影响main().hmain().h != build().h //它们指向不同的对象。
这就是为什么main().h仍然包含null并且您的程序打印true的原因。

0
简单来说:
1)首先创建一个变量'h'并将其指向null。
2)当进入方法“void build(Hello h)”时,创建一个新的变量(也称为'h'),该变量被指向null(指向变量的指针被复制)。
3)当执行'h = new Hello()'时,然后将方法中的新'h'变量更改为指向Hello的新实例(new Hello())。
原始变量'h'保持不变。
就这么简单。

-1

因为 h 等于 null。


3
他正在询问为什么h等于null,即为什么在build内部执行h = new Hello()不会影响main中的h。 - sepp2k

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接