Javaで参照によってパラメーターを渡すことはできますか?


回答:


225

すべてが値で渡されるため、Javaは混乱しています。ただし、参照型のパラメーター(プリミティブ型のパラメーターではない)の場合、値によって渡されるのは参照自体であるため、参照渡しであるように見えます(多くの場合、それはそうであると主張します)。次のように、これは当てはまりません。

Object o = "Hello";
mutate(o)
System.out.println(o);

private void mutate(Object o) { o = "Goodbye"; } //NOT THE SAME o!

印刷されますHelloコンソールに。上記のコードを印刷する場合のオプションは、次のように明示的な参照Goodbye使用することです。

AtomicReference<Object> ref = new AtomicReference<Object>("Hello");
mutate(ref);
System.out.println(ref.get()); //Goodbye!

private void mutate(AtomicReference<Object> ref) { ref.set("Goodbye"); }

48
また、本当に人を混乱させたい場合は、長さ1の配列を使用して参照を作成できます:)
Christoffer

2
AtomicReferenceおよび対応するクラス(AtomicInteger)は、このような操作に最適です
Naveen

3
AtomicReferenceはやり過ぎです。必ずしもメモリバリアが必要なわけではなく、コストがかかる可能性があります。オブジェクトの構築時に使用される揮発性変数のため、JRubyにはパフォーマンスの問題がありました。配列をアドホック参照として使用するオプションは私には十分に思えますが、複数回使用されているのを見てきました。
Elazar Leibovich、2012年

これが混乱することはないと思いますが、これは正常な動作です。値型はスタックに存在し、参照型はヒープに存在しますが、参照型の参照はスタックにも存在します。したがって、常にスタックにある値で操作します。ここでの質問は次のとおりだったと思います:スタックにある他の値を指すスタックからの参照を渡すことは可能ですか?または、ヒープ上に存在するいくつかの値を指す他の参照の参照を渡しますか?
eomeroff

これは素晴らしい情報です。私は配列を使用していましたが、これはその仕事のために構築されたもののようです。これとアレイのパフォーマンスについてはわかりませんが、パフォーマンスが重要なループの場合
steveh

65

Javaで参照によってパラメーターを渡すことはできますか?

番号。

どうして ?Javaには、メソッドに引数を渡すモードが1つしかありません。値によるものです。

注意:

プリミティブの場合、これは簡単に理解できます。値のコピーを取得します。

他のすべての場合は、参照のコピーを取得します。これは、値による受け渡しとも呼ばれます。

それはすべてこの写真にあります:

ここに画像の説明を入力してください


25

Javaでは、言語レベルでrefに似たものはありません。Javaではセマンティックな値渡しのみがあります

好奇心のために、オブジェクトを可変クラスにラップするだけで、refのようなセマンティクスをJavaに実装できます。

public class Ref<T> {

    private T value;

    public Ref(T value) {
        this.value = value;
    }

    public T get() {
        return value;
    }

    public void set(T anotherValue) {
        value = anotherValue;
    }

    @Override
    public String toString() {
        return value.toString();
    }

    @Override
    public boolean equals(Object obj) {
        return value.equals(obj);
    }

    @Override
    public int hashCode() {
        return value.hashCode();
    }
}

テストケース:

public void changeRef(Ref<String> ref) {
    ref.set("bbb");
}

// ...
Ref<String> ref = new Ref<String>("aaa");
changeRef(ref);
System.out.println(ref); // prints "bbb"

代わりにjava.lang.ref.Referenceを使用しないのはなぜですか?
ハードコーディング

java.lang.ref.Referenceにはsetメソッドがないため、変更できません
dfa

AtomicReference(非プリミティブに対して)なぜ使用しないのですか?またはAtomicSomething(例AtomicBoolean:)プリミティブの場合?
Arvin

残念ながら、<T>はプリミティブ型を受け入れません。これを行います:Ref <int>
jk7

1
@ jk7は、使用する必要がありますし、それは本当に重要十分ですint代わりにIntegerbool代わりのBooleanとそうで?つまり、ラッパークラス(構文を心配すると自動的にアンラップされる)が機能しません。
ポール・ステリアン

18

「Javaプログラミング言語」のJames Goslingから:

「... Javaにはパラメーターを渡すモードが1つだけあります-値で渡す-これは物事をシンプルに保ちます...」


2
言語の神の発音は答えを宣言する必要があります。
ingyhere 2013年

3
@ingyhere::The pronouncement of the language god should be declared the answerそうでもない。Javaの作成者が考えたり信じたりしていることにかかわらず、絶対的な答えは言語仕様の引用から得られます。
paercebal

1
実際、JLSのセクション8.4.1にあり、JLSはGoslingを最初の著者として引用しています。「メソッドまたはコンストラクターが呼び出されると(§15.12)、実際の引数式の値は、新しく作成されたパラメーター変数をそれぞれ初期化します。メソッドまたはコンストラクターの本体が実行される前の宣言された型の。」
ingyhere 2015

丁度。低担当者からの皮肉は役に立ちません。
duffymo 2015

11

できないと思います。あなたの最良のオプションは、別のクラスインスタンスに「参照によって」渡したいものをカプセル化し、(外部)クラスの参照を(値によって)渡すことです。意味がわかれば...

つまり、メソッドは、渡されたオブジェクトの内部状態を変更します。この状態は、呼び出し元に表示されます。


7

Javaは常に値渡しです。

プリミティブを渡すと値のコピーになり、オブジェクトを渡すと参照ポインターのコピーになります。


4

別のオプションは、配列を使用することです。 void method(SomeClass[] v) { v[0] = ...; } ただし、1)メソッドを呼び出す前に配列を初期化する必要があります。2)たとえば、この方法でswapメソッドを実装することはできません...この方法は、JDK、たとえばで使用されjava.util.concurrent.atomic.AtomicMarkableReference.get(boolean[])ます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.