在java中是否存在函数中的变量未链接的情况?

时间:2015-11-25 08:51:00

标签: java

特别是我想知道arg是否总是被链接,或者它是否只是因为函数decloration是static而被链接?

在编写成千上万行代码之前,我们很高兴知道它们是否有任何怪癖,期望它是单向的,但在1个边缘情况下它不是。

根据记录,我了解string = new String[2];内的changeValue()会创建一个新字符串,而且这些更改不会传播到main string的实例;

以下是一些示例代码,用于说明我所指的内容。

public class TestLink {

    public static void changeValue(Object object) {
        object.foo = "changed";
    }

    public static void changeValue(String[] string) {
        string[0] = "changed";
    }

    public static void main(String[] args) {
        String[] string = new String[2];
        string[0] = "not changed";
        changeValue(string);
        if (string[0].equals("not changed")) {
            System.out.println("not linked");
        } else {
            System.out.println("linked");
        }
        System.out.println(string[0]);
        /*
        output:
        linked
        changed
        */
    }
}

2 个答案:

答案 0 :(得分:4)

从问题中的代码来看,它听起来像你真正要求的是:"是否存在一个边缘情况,我将数组引用传递给方法并修改其内容,但是那个修改实际上并没有发生?"

不,没有。让我们提取一些代码并更改一些名称,以免误导:

public static void changeValue(String[] arg) {
    arg[0] = "changed";
}

public static void main(String[] args) {
    String[] foo = new String[2];
    foo[0] = "not changed";
    changeValue(foo);
    if (foo[0].equals("not changed")) {
        System.out.println("not linked");
    } else {
        System.out.println("linked");
    }
    System.out.println(foo[0]);
}

changeValue接受数组引用(指向数组的值),并更改该数组的内容。如果代码编译(例如,所有类型等都是正确的)并且在运行时不会抛出(您没有将null或零长度数组传递到changeValue) ,然后不,没有边缘情况,那就不会起作用。

该代码中发生了什么?

如果我们深入了解该代码中的内容,我们就会明白为什么答案是"否。"我发现图片可以提供帮助,所以让我们在这里投入一些ASCII艺术。

这一行:

String[] foo = new String[2];

在内存中给我们这个:

                  +----------+
foo(ref 5426)---->| String[] |
                  +----------+
                  | 0: null  |
                  | 1: null  |
                  +----------+

我们有一个包含值的变量foo。该值称为对象引用,因为它引用了一个对象(在本例中是一个数组,因此我们有时将其称为数组引用)。这只是告诉JVM对象所在位置的值。我将它显示为ref 5426只是为了表明它是一个像任何其他值一样的值,而不是一些神奇的东西;我完全随机选择了5426,我们从未看到实际值,JVM将它隐藏起来。

然后你这样做:

    foo[0] = "not changed";

给我们:

                  +-------------+
foo(ref 5426)---->| String[]    |
                  +-------------+     +---------------+
                  | 0: ref 1897 |---->|    String     |
                  | 1: null     |     +---------------+
                  +-------------+     | "not changed" |
                                      +---------------+

例如,数组中的第一个条目包含值,该值是对字符串对象的引用。

然后我们这样做:

    changeValue(foo);

foo获取值并将该值传递给changeValuechangeValue接收参数arg中的值。所以现在我们有了这个:

                  +-------------+
foo(ref 5426)--+->| String[]    |
               |  +-------------+     +---------------+
               |  | 0: ref 1897 |---->|    String     |
               |  | 1: null     |     +---------------+
               |  +-------------+     | "not changed" |
               |                      +---------------+
arg(ref 5426)--+

由于main尚未返回,foo仍然存在,并且其值为ref 5426。该值已复制到arg,因此arg也具有值ref 5426。该值告诉JVM数组的位置。

然后你做:

    arg[0] = "changed";

给了我们:

                  +-------------+                       +---------------+
foo(ref 5426)--+->| String[]    |                       |    String     |
               |  +-------------+     +-----------+     +---------------+
               |  | 0: ref 2785 |---->|  String   |     | "not changed" |
               |  | 1: null     |     +-----------+     +---------------+
               |  +-------------+     | "changed" |
               |                      +-----------+
arg(ref 5426)--+

数组中的第一个条目不再指向旧字符串,您已使用指向新字符串的新值替换了该值。 (旧的字符串一直挂着,直到垃圾收集器摆脱它,但我们不再关心,我们没有任何引用它。)

changeValue已完成,因此返回,arg(参数)消失。

由于foo仍然具有相同的值(ref 5426),当您查找其中的第一个条目时,您会看到changeValue放置的值。

这怎么告诉我们答案是"没有"?

因为有一个边缘情况,上面没有工作,所以必须是这些事情之一:

  • foo的值传递到changeValue并将其作为arg接收,因某些原因无效。

  • foo的值传递到changeValue并将其作为arg接收,并因某种原因制作副本

  • 当我们使用它来获取数组并进行更改时,我们得到ref 5426会有所不同。

没有任何边缘情况会发生任何这些事情。 : - )

答案 1 :(得分:0)

声明为static的函数在此上下文中没有任何意义。你做的是你传递了一个String数组。此函数内部函数与main函数中的数组相同。因此,数组通过引用传递 *并且String类型是一种特殊情况,传递它会创建新的String,尽管它是非基本类型。原始类型仅按值传递。

您的边缘案例列于here,另外还有Stringbyteshortintlongfloatdoublebooleanchar - 全部正如你所说的那样,这些都是“没有联系”的。这些不是通过引用传递 *。

* Java本身不通过引用传递。 引用通过值传递的。 Is Java "pass-by-reference" or "pass-by-value"?

修改

在Java中忘记通过引用传递。这种语言完全基于按值传递概念(取消链接,如您所说),引用由值本身传递,从而创建您的链接行为。这个编辑的信用归于T.J.克劳德。为了方便起见,我只是使用术语通过引用传递