堆栈与堆上的Java内存分配

Ami*_*ani 6 java heap stack allocation

我觉得自己像是一个问这个问题的新手 - 但是为什么当我将下面的Set传递给我的方法并将其指向一个新的HashSet时,它仍然作为EmptySet出现?是因为局部变量是在堆栈上分配的,所以当我退出方法时,我的新东西会被吹走吗?我怎样才能实现功能等同?

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>();

    }

}
Run Code Online (Sandbox Code Playgroud)

nos*_*nos 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>();
}
Run Code Online (Sandbox Code Playgroud)


Ste*_*n C 8

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

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

Java参数是"按值"传递的,但在对象或数组类型的情况下,传递的值是对象/数组引用.创建并分配新的设置对象时mySet,只需设置局部变量/参数即可.由于Java使用pass by value,因此这foomain方法中的变量没有影响.

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

好的 - 但是 - 如果我要在方法调用中添加或执行其他操作,则会保留该分配.这是为什么?

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

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

顺便说一句,您将无法将元素添加到返回的集合中Collections.emptySet().该set对象是不可变的.add在它上面调用(例如)将抛出异常.