これはJavaのスタックとヒープに関する 答え の一部です:
では、なぜスタックやヒープがまったく必要なのでしょうか。スコープから外れるものの場合、スタックは高価になる可能性があります。コードを考えてみましょう:
void foo(String arg) { bar(arg); ... } void bar(String arg) { qux(arg); ... } void qux(String arg) { ... }
パラメータもスタックの一部です。ヒープがない場合は、スタックに値の完全なセットを渡します。これは「foo」と小さな文字列では問題ありませんが、誰かがその文字列に巨大なXMLファイルを挿入するとどうなりますか。各呼び出しは巨大な文字列全体をスタックにコピーします-そしてそれはかなり無駄です。
これは私が読んだものです Java®仮想マシン仕様Java SE 8 Edition (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呼び出されたメソッドのスタックフレームにメソッドパラメータをコピーしますか?から 答え 最初に参照しますページのコピー、それらがコピーされていることを理解し、それはディープコピーです。ほぼ間違いなく、私は間違っています。
Javaでは、Javaでは値が存在する場所を選択できないため、スタックとヒープの区別はあまり意味がありません。概念的には、すべてのオブジェクトはヒープ上のどこかに存在しますが、Javaでは、オブジェクトは変数と同じではありません。ローカル変数とメソッドパラメータはスタック上のスペースを使用しますが、変数がオブジェクトを直接保持することはありません。変数には、int
などのプリミティブ値、またはオブジェクトへのreferencesが含まれます。
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がどのように機能するかを説明していませんが、各メソッド呼び出しに対してnotを行うことが望ましい理由を説明しています。
Javaのメソッド呼び出しの動作は、CおよびC++に非常に似ています。すべてが値で渡されるです。違いは、JavaオブジェクトはCおよびC++の意味でのオブジェクトではなく、実際のオブジェクトに対してpointerのように動作することです。変数の割り当てとメソッドの呼び出しの場合、そのポインターは値で渡されます。
Javaでは、オブジェクトがあります(すべてJava.lang.Object
、ヒープ割り当て)およびプリミティブ型(bool
、char
、整数型、float
、double
、およびオブジェクトへのポインター(マーケティング目的の参照))。
変数はプリミティブ型であるため、簡単にコピーされ、常に値によって渡されます。
オブジェクトをまったく渡すことはできませんが、オブジェクトへのポインターは、コピーするのではなく、参照によって効果的に渡すことができます。
プリミティブ型の深いコピーは、浅いコピーと同じです。
明示的に作成しない限り、オブジェクトのコピーはまったく発生せず、適切な構造の共有を行う/回避するのはあなた自身の責任です。