代码之家  ›  专栏  ›  技术社区  ›  Pete

Java逐值-你能解释这个吗?

  •  2
  • Pete  · 技术社区  · 16 年前

    我读 this excellent article 它是有意义的:Java是严格按照值传递的;当对象是一个参数时, 对象的引用按值传递 .

    但是,我完全不明白为什么下面的代码片段可能有效。 Foo 具有字符串成员变量 a 它是不变的,每次都需要燃烧。 第一种烧掉(注释掉)的方法应该可以很好地工作。 第二种方法集 一 对传递的值的引用。如果 newstr 是临时变量。预期输出结果为:

    Totally temp
    NULL
    

    然而,我得到

    Totally temp
    Totally temp
    

    为什么?只是运气好,临时变量引用仍然是好的吗?

    public class Foo {
        String a;
        public Foo(){}
        public void burna(String newstr){
               // a = new String(newstr);
               a = newstr; /*this should not work: */ 
            }
    }
    
    public class foobar {
        Foo m_foo;
        public foobar(){};
        public void dofoo(){
            String temp = new String("Totally temp\n");
            m_foo.burna(temp);
            System.out.print(m_foo.a);
        }
    
    }
    
     public static void main(String[] args) {
            Foo myfoo = new Foo();
            foobar myfoobar = new foobar();
    
            myfoobar.m_foo = myfoo;
            myfoobar.dofoo();
            System.out.print(myfoo.a);
    
        }
    
    6 回复  |  直到 12 年前
        1
  •  3
  •   Donnie    16 年前

    问题似乎是您不理解垃圾收集是如何工作的。只要对对象的至少一个引用保持有效,则不会收集该对象。

        2
  •  11
  •   Jon Skeet    16 年前

    foo有一个字符串成员变量a,它是不可变的,每次都需要烧掉它。

    不,它没有:它没有标记为 final :

    public class Foo {
        String a;
        ...
    }
    

    变量是完全可变的-您可以随时将其更改为引用不同的字符串,这就是您在 burna 方法。

    我现在不明白你为什么认为这行不通:

    public void burna(String newstr){
        a = newstr; /*this should not work: */ 
    }
    

    这是设置 价值 属于 a 成为 价值 属于 newstr -它是对字符串(或空)的引用。就这样。我不知道你所说的“烧掉”一个变量是什么意思。

    你在打电话 伯纳 并传入一个带有文本“totally temp \n”的字符串引用-所以 一 设置为对该字符串的引用。

    你所说的“如果 纽斯特 是一个临时变量。“没有”临时变量这样的东西。有一个 地方的 变量-但对象不会因为引用它的变量超出范围而被破坏。这就是让你困惑的地方吗?

    你的计划有好几件事要做 foobar 在理解方面,课堂可能对你没有帮助。你能试着简化你的代码到它仍然让你困惑的程度吗,但是事情却少了些?然后我们可以更精确地隔离混乱的根源。

        3
  •  2
  •   sepp2k    16 年前

    有两个对字符串“totally temp \n”的引用。一个是 temp 另一个是 a 在 Foo 对象。在最后 dofoo 临时雇员 超出范围,所以这是一个较少的参考。但是,您仍然有其他引用,因此该字符串不会被垃圾收集。

        4
  •  2
  •   Philipp    16 年前

    这个 String 对象是不可变的,但 Foo 对象不是。 myfoobar.m_foo 和 myfoo 指向同一对象,从而共享 a 成员。

        5
  •  1
  •   Jesper    16 年前

    您可能习惯于C++中变量和对象的工作方式。

    非基元类型的变量总是 参考文献 对于Java中的对象,不同于C++,其中变量本身代表对象。

    Java中的对象总是在堆上分配。对象从不堆栈*作为“临时变量”,就像在C++中一样。

    *:实际上,JVM可能会进行一些优化并将对象放在堆栈上,但这与理解变量和对象在Java中如何工作的概念无关。

        6
  •  0
  •   Vibha Sanskrityayan    12 年前

    因为Java也通过值传递对象引用。现在,这是一个棘手的问题:

    公共空虚棘手(点arg1,点arg2)

    {

    Ag1.x=100;

    Ag1.y=100;

    点温度=arg1;

    ARG1= ARG2;

    Ag2=温度;

    }

    公共静态void main(string[]参数)

    {

    点PNT1=新点(0,0);

    点PNT2=新点(0,0);

    system.out.println(“x:”+pnt1.x+“y:”+pnt1.y);

    system.out.println(“x:”+pnt2.x+“y:”+pnt2.y);

    system.out.println(“”);

    棘手(PNT1、PNT2);

    system.out.println(“x:”+pnt1.x+“y:”+pnt1.y);

    system.out.println(“x:”+pnt2.x+“y:”+pnt2.y);
    }

    **如果我们执行这个main()方法,我们会看到以下输出:

    X:0 Y:0

    X:0 Y:0

    X:100 Y:100

    X:0 Y:0**