-2

私は、Javaの標準などの配列が、基本的な数値型と同様に、配列への参照を渡すのではなく、コピーとして渡されると誤って述べているものをオンラインで読みint []、コピーを変更しようと思ったときに配列を上書きしてしまいました。90年代半ば頃のJavaのターゲットオーディエンスにとって物事をより簡単にするための設計上の選択としてこれをチョークで書くことはできますか?(オブジェクトを構文的にC配列と同じように見せますか、それとも配列は実際にはJavaの「オブジェクト」型ではありませんか?)

つまり、なぜ彼らは次のようなことをしなかったのですか?

Array array = new Array(<size>);

さらに、一貫性を確保するために、すべて(リテラルを除く)を参照渡しにしないのはなぜですか?( sは、の値としてではなく、intへの参照として渡されるため、そのメソッド内のメソッドの引数である変数を変更すると、元の変数の値などが変更されます。)intint

Javaでの参照渡しと値渡しの説明へのリンク

4

6 に答える 6

12

Java では何も参照によって渡されませんが、変数の値が何であるかを知る必要があります。

タイプの変数の値が配列int[]ではありません。配列への参照です。プリミティブの配列であっても、すべての配列は参照型です。

あなたが書くとき:

int[] x = { 1, 2, 3, 4, 5 };
someMethod(x);

次に、xのsomeMethodが値渡しで に渡されます。これは配列への参照です。メソッドは配列の内容を変更できますが、xそれ自体の値を変更することはできません。これは、Java が参照渡しを使用している場合に可能でした。

式の値が参照またはプリミティブ値のいずれかであることを理解すると、多くのことがより明確になります。たとえば、次のコードを見てください。

int[] x = { 1, 2, 3, 4, 5 };
int[] y = x;
y[0] = 10;
System.out.println(x[0]);

結果はどうなると思いますか?代入演算子は値を RHS から LHS にコピーします。つまり、xyは同じ配列への参照です。したがって、最終行は 10 を出力します。この「値のコピー」は、引数の受け渡しに使用される原則とまったく同じです。

ここに矛盾はありません。何が起こっているのか、そして値渡しと参照渡しが実際に何を意味するのかを理解する必要があるだけです。

編集:これについてまだ疑問があることに本当に驚いています。

Java 言語仕様のセクション 8.4.1 (Formal Parameters)から:

メソッドまたはコンストラクターが呼び出されると (§15.12)、実引数式の値は、メソッドまたはコンストラクターの本体の実行前に、新しく作成されたパラメーター変数、宣言された Type のそれぞれを初期化します。

これは実質的に、値渡しセマンティクスの定義です。引数のは、パラメーターの初期として使用されます。

これらの値は参照である場合もあれば、プリミティブな値である場合もあります。渡される値であるという事実は変わりません。

編集:あなたが使用する定義は、私の見解では表現が悪いですが、Javaがすべてを値で渡すと主張することが誤解を招くという意味ではありません。

値渡しの場合は次のようになります。

これは変数のコピーを作成し、変数が配列のように大きい場合は非常に遅く非効率になる可能性があります。

C と C++ について話していたことに注意してください (ただし、実際には C++ にも参照渡しがあります) variable のコピーを作成することについて説明しています。それはまさに Java が行うことです。違いは、Java では、変数の値が常にプリミティブ値または参照のいずれかであるということです。決して物ではありません。

この重要な点を理解すれば(引数の受け渡しだけでなく重要な点でもあります)、Java はすべてを値渡しであると正しく言うのはまったく簡単です。メソッドまたはコンストラクターが呼び出されると、引数が評価され、がパラメーターの初期値として使用されます。これは値渡しであり、Java がすべてのパラメーターに対して行うことです。

リンク先の PDF については、IMO というトピックについての恥ずべき議論です。それは参照渡しの意味を混乱させ、正当な理由もなく String を特殊なケースにします (String はたまたま不変ですが、他のクラスもそうである可能性があります)。私の見解を裏付けるリンクをいくつか提供すると役に立ちますか?

さらに何百もあります。これに戸惑うのはあなたが初めてではありませんが、Java は実際にはすべてを値渡しします。参照も同様です。

于 2009-08-10T21:58:04.567 に答える
7

Java ではすべてが値渡しです。すべての。オブジェクト型 (配列) の場合、値によって渡されるのは参照です。いいえ、それは参照渡しと同じではありません。

于 2009-08-10T21:58:14.443 に答える
2

そうですね。メモリアドレスも値であることは否定できません。したがって、参照渡しは実際には値渡しの特殊なケースにすぎません。

SOでこれまでで最も多くのFilistineの回答に対して+1。

ところで、私も答えの一部を持っているかもしれないと思います

「一貫した動作を確保するために、なぜすべてを参照渡しにしなかったのですか?」

その場合、システムは引数がリテラルである呼び出しをどのように処理しますか。たとえば、'result = f(2);' です。?

そのリテラルも参照によって渡されてはなりませんか? もしそうなら、参照を更新する何らかの呼び出しによってリテラルの値を変更する可能性が開かれるのではないでしょうか? その場合、「リテラル」という用語はやや不適切になる可能性があり、多くの可能なコードの最適化はコンパイラが実装できなくなりますか?

于 2009-08-10T22:13:02.447 に答える
1

はい、int[]オブジェクトです。はい、構文は C/C++ プログラマーを取り込むためのものでした。いいえ、設計上の選択が悪いわけではありません。2 つのステートメントは矛盾していません。

于 2009-08-10T21:59:18.263 に答える
1

少なくともパフォーマンスの観点からは、配列を参照渡しすることは非常に理にかなっています。そうしないと、多くの不要なコピーが必要になります。

そうは言っても、不変の配列オブジェクトが必要であることに同意します。

于 2009-08-10T21:59:46.497 に答える
0

これは、Java オブジェクトが「値によって渡される」ことの意味についてよくある誤解です。すべての Java オブジェクト、配列、およびプリミティブは値で渡されますが、オブジェクトと配列の場合、渡される値は実際には元のオブジェクトへのポインター (または、必要に応じて参照) です。

これが違いです。Java と C++ の両方で、次の関数を記述できます。

void myFunc(int[] arr) {
    arr[0] = 17;
}
myFunc(myLocalArray);

これにより、どちらの言語でも、arr[0] に格納される値は、myFunc の「arr」変数内と myLocalArray 内の両方で 17 になります。

もちろん、これは非常に興味深いことですが、「参照渡し」とは何の関係もありません。

参照によって配列を渡すということは、C++ のような言語 (Java ではなく) で、次のことができることを意味します。

void myFunc(int[] arr) {
    arr = null;
}
myFunc(myLocalArray);

ここでは、myLocalArray オブジェクトをまったく別のオブジェクト (この場合は null ですが、何でもかまいません) に完全に置き換えました。オブジェクトを変更しただけではなく (特定のインデックスに格納された値を変更したなど)、myLocalArray が正当な配列を指していたという証拠をすべて根本的に消去しました。

Java では、これを行うことはできません。

したがって、Java の基本的なルールは次のとおりです。

  1. オブジェクト内のすべての編集 (たとえば、状態を変更する関数の呼び出し、状態の直接変更、配列内の値の変更など) は、元のオブジェクト (呼び出し関数内) に作用します。あなたが特に作成しない限り、コピーは作成されません。
  2. ローカル オブジェクトを新しいオブジェクトで完全に上書きしても、呼び出し元の関数のオブジェクトには影響しません。
于 2009-08-10T22:09:42.233 に答える