6

问这个问题我感觉像个新手——但是为什么当我将下面的 Set 传递到我的方法中并将它指向一个新的 HashSet 时,它仍然以 EmptySet 的形式出现?是不是因为局部变量是在堆栈上分配的,所以当我退出方法时我的new被吹走了?我怎样才能实现功能等效?

import java.util.HashSet;
import java.util.Set;

public class TestMethods {

    public static void main(final String[] args) {

        final Set<Integer> foo = java.util.Collections.emptySet();
        test(foo);

    }

    public static void test(Set<Integer> mySet) {

        mySet = new HashSet<Integer>();

    }

}
4

6 回答 6

8

Java 按值传递引用,将其mySet视为引用的副本foo。在void test(Set<Integer> mySet)中,该mySet变量只是该函数中的局部变量,因此将其设置为其他值不会影响main.

mySet确实引用(或“指向”,如果你喜欢)与foo变量相同的 Set main

如果要更改 main 中的引用,可以执行以下操作:

foo = test(); //foo can't be final now though
 public static Set<Integer>  test() {
   return new HashSet<Integer>();
}
于 2010-07-20T01:31:56.583 回答
8

...是不是因为局部变量是在堆栈上分配的,所以当我退出方法时我的 new 被吹走了?

不,这是因为 Java 的参数传递语义。

Java 参数是“按值”传递的,但在对象或数组类型的情况下,您传递的值是对象/数组引用。当您创建一个新的集合对象并将其分配给 时mySet,您只是在设置局部变量/参数。foo由于 Java 使用按值传递,因此这对方法中的变量没有影响main

当您进入该test方法时,您有两个对HashSet在该方法中创建的实例的引用的副本main;一进foo一进mySet。然后,您的代码将 in 替换为对mySet新创建的引用的引用HashSet,但此新引用不会传递回调用者。(您可以更改代码以将其传回......例如作为test方法的结果。但您必须明确地执行此操作。)

好的 - 但是 - 如果我要在我的方法调用中执行 add 或其他一些操作,则该分配将被保留。这是为什么?

foo这是因为当您使用or中的引用调用实例方法时,该方法会在引用所指mySet的对象 () 上执行。HashSet假设这两个引用指向同一个对象,您的“分配将被保留”。或者更准确地说,您可以通过对同一对象的其他引用的操作来观察操作对对象的一个​​引用的影响。

请记住,Java 方法调用对对象的复制引用,而不是对象本身。

顺便说一句,您将无法将元素添加到由Collections.emptySet(). 该集合对象是不可变的。调用(例如)add它会引发异常。

于 2010-07-20T01:32:34.773 回答
1

您的“foo”指的是进入 test() 调用的空集,测试调用没有修改对象,因此从那里返回时它仍然是一个空集。

在 test() 方法中,“mySet”只是一个本地引用,它在入口处引用原始集合 (foo),当您为该引用分配新的 HashSet 时,您丢失了对原始集合的引用. 但是这些效果完全是 test() 方法的局部,因为 java 只是给 test() 一个对原始集合的引用的副本。

现在,在 test() 中,由于您有对原始对象的引用,您可以修改该对象。例如,您可以向该集合添加元素。但是你不能改变调用函数中的引用,你只能改变它所引用的内容。所以你不能用不同的集合替换一个集合,如果你首先想要一个 HashSet,你必须在 main() 中新的 HashSet。

于 2010-07-20T01:44:54.803 回答
0

不确定我是否理解这个问题。在该test方法中,您正在实例化一个新集合并将其分配给局部mySet变量。 mySetthen 将不再引用与fooback 中相同的集合Main

当你从方法返回时, foo 仍然引用原始emptySet()的,并且HashSet在方法中创建的将被标记为垃圾回收。

于 2010-07-20T01:35:58.300 回答
0
import java.util.HashSet;
import java.util.Set;

public class TestMethods {

    public static void main(final String[] args) {

        final Set<Integer> foo = java.util.Collections.emptySet();
        test(foo);

    }

    public static void test(Set<Integer> mySet) {
        // here mySet points to the same object as foo in main
        mySet = new HashSet<Integer>();
        // mySet now points to a new object created by your HashSet constructor call,
        // any subsequent operations on mySet are no longer associated with foo, because
        // they are no longer referencing the same object
    }
}

我怎样才能实现功能等效?

我不确定我是否理解这个问题,您是否在寻找回报?

    public static Set<Integer> test(Set<Integer> mySet) {
        for(Integer i : mySet){
            // do something??
        }
        mySet = new HashSet<Integer>();
        return mySet;
    }

现在,如果您将 foo 分配给测试返回的内容,您是否拥有“功能等价物”?

于 2010-07-20T01:44:42.563 回答
0

你应该读这本书:

“Java SCJP 认证程序员指南:综合入门(第 3 版)”

于 2010-10-27T18:45:35.230 回答