这是答案中关于堆栈和堆的一部分:
那么,为什么有堆栈或堆呢?对于离开作用域的东西,堆栈可能会很昂贵。考虑代码: void (String){ bar( arg);.} void (String){ qux( arg);.} void (String){.}参数也是堆栈的一部分。在没有堆的情况下,将在堆栈上传递完整的值集。这是好的“福”和小弦乐..。但是,如果有人在这个字符串中放了一个巨大的XML文件,会发生什么。每个调用都会将整个庞大的字符串复制到堆栈上--这将是相当浪费的。
这就是我在Java虚拟机规范8版中所读到的(第2.5.2章)。( Java虚拟机堆栈):
Java虚拟机栈保存局部变量和部分结果,并在方法调用和返回中发挥作用。
我所知道的是,当我将引用作为参数传递给方法时,会在方法中创建一个局部变量。局部变量与传递的变量具有相同的引用。例如,像这样的事情
void foo(Bar bar) {
// Do something with bar
}变成这样:
void foo(Bar bar) {
Bar localBar = bar;
// Do something with localBar
}所以我的问题是:
Java是否将方法参数复制到被调用方法的堆栈框架中?我在页面开头提到的答案中,我知道它们是复制的,这是一个很深的副本。几乎可以肯定,我错了。
发布于 2017-05-28 12:13:31
在Java中,堆栈和堆的区别并不是很有意义,因为Java没有给您选择值所在的位置。从概念上讲,所有对象都生活在堆中的某个地方,但在Java中,对象与变量不是同一回事。局部变量和方法参数使用堆栈上的空间,但变量从不直接持有对象。这些变量要么包含像int这样的原始值,要么包含对对象的引用。
在Java中,变量赋值总是执行浅拷贝:对于原始值,值被复制。对于对象,引用将被复制。引用的对象不被复制:原始引用和复制引用都引用同一个对象。
方法调用非常类似于对参数的变量赋值。调用方法时,可以认为在堆栈上分配了带有方法参数的堆栈帧,然后我们将参数值分配给每个参数变量。
由于执行了所有参数值的浅拷贝,所以不能通过向方法中的参数赋值来更改外部变量:
void outer() {
int i = 4;
inner(i);
// i will always be 4 at this point
}
void inner(int j) {
j = 7; // this assignment only affects the *local* j
}但是,如果传递一个对象,则不存在深度复制,因此对对象的更改在方法之外是可见的:
void outer() {
ArrayList<String> xs = new ArrayList<>();
inner(xs);
// xs has been modified at this point, and contains "foo"
}
void inner(ArrayList<String> ys) {
ys.add("foo");
}您所引用的答案中的部分并不解释Java是如何工作的,而是为什么不对每个方法调用进行深度复制。
Java的方法调用的行为非常类似于C和C++:一切都是通过值传递的。不同之处在于,Java对象不是C和C++意义上的对象,而是像指向实际对象的指针。对于变量赋值和方法调用,然后通过值传递该指针。
发布于 2017-05-28 12:31:35
在Java中,您有对象(所有继承自java.lang.Object,堆分配)和基元类型(bool、char、整数类型、float、double,以及指向对象的指针(称为营销引用))。
变量是基本类型的,因此很少复制,并且总是通过值传递。
对象根本不能传递,但是指向它们的指针可以通过引用有效地传递它们,而不是复制它们。
基元类型的深拷贝与浅拷贝相同。
除非您显式地创建对象,否则不会发生对象的副本,那么您自己就有责任在适当的情况下执行/避免结构共享。
https://softwareengineering.stackexchange.com/questions/349731
复制相似问题