JavaにはC#のrefおよびoutキーワードのようなものがありますか?


113

次のようなもの:

refの例:

void changeString(ref String str) {
    str = "def";
}

void main() {
    String abc = "abc";
    changeString(ref abc);
    System.out.println(abc); //prints "def"
}

例:

void changeString(out String str) {
    str = "def";
}

void main() {
    String abc;
    changeString(out abc);
    System.out.println(abc); //prints "def"
}


5
IMOあなたは多くを逃していません。私がこれまでrefまたはoutC#で使用するのTryParse()は、メソッドがブール値の結果を返すようなパターンを使用しているときだけで、解析された値をそこから取得する唯一の方法は、refまたはを使用することですout
ロバートハーベイ、

3
何だと思う、それは私が使用する必要があるものです!;)
食欲をそそるエリジウム

これを行うもう1つの方法は、ステータスとnull許容値の両方を含む複合オブジェクトを返すことです。しかし、私はそれが少しRube Goldbergっぽいことを認めます。
Robert Harvey

1
定義済みの使用可能なオブジェクト(タプルなど)がある場合に限り、複合オブジェクトを返すことに問題はありません。しかし、待ってください。効率を上げるには、消去されていないジェネリックスがプリミティブ型を処理する必要があります:)
Pavel Minaev

回答:


102

いいえ、JavaにはC#refout参照渡しのキーワードなどはありません。

Javaでは値によってのみ渡すことができます。参照も値で渡されます。詳細については、Javaでのパラメーターの受け渡しに関するJon Skeetのページを参照してください。

似た何かをするrefか、outあなたは別のオブジェクト内のあなたのパラメータをラップし、パラメータとしてのそのオブジェクト参照を渡す必要があります。


5
これは拡張する必要があります。値として渡すことができるのは、プリミティブ(int、short、charなど)のみです。そして、ノー、アウトはありません。
Corey Sunwold

14
100%正しいわけではありません。配列またはクラスを渡す場合、配列またはオブジェクトへの参照は値で渡されます。配列またはオブジェクトの内部を変更すると、呼び出し元に反映されます。
Romain Hippeau

12
@fearofawhackplanet:ええと、あなたが使用しない限りref
ロバートハーベイ、

2
@fearofawhackplanet:Reference parameters need the ref modifier as part of both the declaration and the invocation - that means it's always clear when you're passing something by reference. yoda.arachsys.com/csharp/parameters.html
Mark Byers、

5
CLRの観点からは、マネージ参照(T&)を値で渡します(はい)。しかし、C#には独自の用語があり、特にタイプの値などは含まれていませんref T-C#の観点からrefは、厳密にパラメータ修飾子であり、それに関して「値による参照の受け渡し」といっても意味がありません。 。
Pavel Minaev

30

正解:いいえ

しかし、ラッパーを使用して参照をシミュレートできます。

そして、次のようにします。

void changeString( _<String> str ) {
    str.s("def");
}

void testRef() {
     _<String> abc = new _<String>("abc");
     changeString( abc );
     out.println( abc ); // prints def
}

でる

void setString( _<String> ref ) {
    str.s( "def" );
}
void testOut(){
    _<String> abc = _<String>();
    setString( abc );
    out.println(abc); // prints def
}

そして基本的に次のような他のタイプ:

_<Integer> one = new <Integer>(1);
addOneTo( one );

out.println( one ); // May print 2

28
痛い。それは醜いです。
貪欲なエリジウム

46
私は決して言わなかった、あなたはこのエレガントな方法でそれをすることができる:P
OscarRyz

それで、次のことが機能しないのはなぜですか。aWrapper [0] = st.nextToken(); bWrapper [0] = new Integer(st.nextToken()); } ParseLine(newline、new String [] {a}、new Integer [] {b});
Elad Benda、

3
@ user311130コードは読みにくいですが、次のような新しい質問を作成できます:「この回答<リンクへのリンク>が見つかりましたが、次は機能しません<コードはこちら>
OscarRyz

それは厄介ですが、現時点でJavaについて考えることができる「最もクリーンな」方法で問題を解決するので、私はまだこれを同じように与えています...
Pangamma

8

実際、私が知る限り、Java言語にはrefキーワードもoutキーワードもありません。しかし、私はC#コードを使用するJavaに変換しましパラメータました。これで、今行ったことをアドバイスます。次のように、オブジェクトをラッパークラスにラップし、ラッパーオブジェクトインスタンスにラップされた値を渡す必要があります。

ラッパーを使用する簡単な例

これがラッパークラスです。

public class Wrapper {
    public Object ref1; // use this as ref
    public Object ref2; // use this as out

    public Wrapper(Object ref1) {
        this.ref1 = ref1;
    }
}

そして、これがテストコードです。

public class Test {

    public static void main(String[] args) {
        String abc = "abc";
        changeString(abc);
        System.out.println("Initial object: " + abc); //wont print "def"

        Wrapper w = new Wrapper(abc);
        changeStringWithWrapper(w);
        System.out.println("Updated object: " + w.ref1);
        System.out.println("Out     object: " + w.ref2);
    }

    // This won't work
    public static void changeString(String str) {
        str = "def";
    }

    // This will work
    public static void changeStringWithWrapper(Wrapper w) {
        w.ref1 = "def";
        w.ref2 = "And this should be used as out!";
    }

}

実際の例

出力パラメーターを使用するAC#.NETメソッド

ここに、outキーワードを使用ているC#.NETメソッドがあります。

public bool Contains(T value)
{
    BinaryTreeNode<T> parent;
    return FindWithParent(value, out parent) != null;
}

private BinaryTreeNode<T> FindWithParent(T value, out BinaryTreeNode<T> parent)
{
    BinaryTreeNode<T> current = _head;
    parent = null;

    while(current != null)
    {
        int result = current.CompareTo(value);

        if (result > 0)
        {
            parent = current;
            current = current.Left;
        }
        else if (result < 0)
        {
            parent = current;
            current = current.Right;
        }
        else
        {
            break;
        }
    }

    return current;
}

outパラメータを使用しているC#コードに相当するJava

そして、ラッパークラスの助けを借りてこのメソッドに相当するJavaは次のとおりです。

public boolean contains(T value) {
    BinaryTreeNodeGeneration<T> result = findWithParent(value);

    return (result != null);
}

private BinaryTreeNodeGeneration<T> findWithParent(T value) {
    BinaryTreeNode<T> current = head;
    BinaryTreeNode<T> parent = null;
    BinaryTreeNodeGeneration<T> resultGeneration = new BinaryTreeNodeGeneration<T>();
    resultGeneration.setParentNode(null);

    while(current != null) {
        int result = current.compareTo(value);

        if(result >0) {
            parent = current;
            current = current.left;
        } else if(result < 0) {
            parent = current;
            current = current.right;
        } else {
            break;
        }
    }

    resultGeneration.setChildNode(current);
    resultGeneration.setParentNode(parent);

    return resultGeneration;
}

ラッパークラス

そして、このJavaコードで使用されるラッパークラスは次のとおりです。

public class BinaryTreeNodeGeneration<TNode extends Comparable<TNode>>  {

    private BinaryTreeNode<TNode>   parentNode;
    private BinaryTreeNode<TNode>   childNode;

    public BinaryTreeNodeGeneration() {
        this.parentNode = null;
        this.childNode = null;
    }

    public BinaryTreeNode<TNode> getParentNode() {
        return parentNode;
    }

    public void setParentNode(BinaryTreeNode<TNode> parentNode) {
        this.parentNode = parentNode;
    }

    public BinaryTreeNode<TNode> getChildNode() {
        return childNode;
    }

    public void setChildNode(BinaryTreeNode<TNode> childNode) {
        this.childNode = childNode;
    }

}

以前の回答を参照してください。
パシュテ2017

詳細な回答を反対票を投じることは面白いです。私はSOをチェックアウトしましたが、デモコードで正確な正確な答えを見つけることができませんでした。そのため、私が覚えている限りこの答えを書きました。単一の回答を待ち、他のすべての回答に反対票を投じる場合、SOは質問の所有者から確認を得た以外のすべての回答を禁止する必要があります。
Levent Divilioglu 2017

OK、あなたが回答を編集した場合にのみ、私は反対票を削除できます。他の回答を読んで、これらのソリューションを使用したくない理由を説明してください。ラッパー(特に、面白さのためのREFおよびOUTラッパー)。5人が短く完全な例を挙げて回答、Eyalのみが基本的に「できません」と書きました。
パシュテ

1
この答えは元気です。これはトップの回答に似ていますが、Javaでラッパークラスを使用する方法の完全な例を示しています。
2018

8

Javaは値によってパラメーターを渡しますが、参照渡しを可能にするメカニズムはありません。つまり、パラメーターが渡されるたびに、そのが呼び出しを処理するスタックフレームにコピーされます。

ここで使用する「」という用語は、少し明確にする必要があります。Javaには、プリミティブとオブジェクトの2種類の変数があります。プリミティブの値はプリミティブ自体であり、オブジェクトの値はそのリファレンスです(参照されるオブジェクトの状態ではありません)。したがって、メソッド内の値を変更しても、スタック内の値のコピーのみが変更され、呼び出し元には表示されません。たとえば、実際のswapメソッドを実装する方法はありません。2つの参照を受け取り、それらを交換します(コンテンツではありません)。


6

他の多くの人と同様に、C#プロジェクトをJavaに変換する必要がありました。outおよびref修飾子に関する完全な解決策がWeb上で見つかりませんでした。しかし、私は見つけた情報を利用し、それを拡張して、要件を満たす独自のクラスを作成することができました。コードをわかりやすくするために、refパラメーターとoutパラメーターを区別したかったのです。以下のクラスで可能です。この情報が他の人の時間と労力を節約できますように。

以下のコードに例が含まれています。

//*******************************************************************************************
//XOUT CLASS
//*******************************************************************************************
public class XOUT<T>
{
    public XOBJ<T> Obj = null;

    public XOUT(T value)
    {
        Obj = new XOBJ<T>(value);
    }

    public XOUT()
    {
      Obj = new XOBJ<T>();
    }

    public XOUT<T> Out()
    {
        return(this);
    }

    public XREF<T> Ref()
    {
        return(Obj.Ref());
    }
};

//*******************************************************************************************
//XREF CLASS
//*******************************************************************************************

public class XREF<T>
{
    public XOBJ<T> Obj = null;

    public XREF(T value)
    {
        Obj = new XOBJ<T>(value);
    }

    public XREF()
    {
      Obj = new XOBJ<T>();
    }

    public XOUT<T> Out()
    {
        return(Obj.Out());
    }

    public XREF<T> Ref()
    {
        return(this);
    }
};

//*******************************************************************************************
//XOBJ CLASS
//*******************************************************************************************
/**
 *
 * @author jsimms
 */
/*
    XOBJ is the base object that houses the value. XREF and XOUT are classes that
    internally use XOBJ. The classes XOBJ, XREF, and XOUT have methods that allow
    the object to be used as XREF or XOUT parameter; This is important, because
    objects of these types are interchangeable.

    See Method:
       XXX.Ref()
       XXX.Out()

    The below example shows how to use XOBJ, XREF, and XOUT;
    //
    // Reference parameter example
    //
    void AddToTotal(int a, XREF<Integer> Total)
    {
       Total.Obj.Value += a;
    }

    //
    // out parameter example
    //
    void Add(int a, int b, XOUT<Integer> ParmOut)
    {
       ParmOut.Obj.Value = a+b;
    }

    //
    // XOBJ example
    //
    int XObjTest()
    {
       XOBJ<Integer> Total = new XOBJ<>(0);
       Add(1, 2, Total.Out());    // Example of using out parameter
       AddToTotal(1,Total.Ref()); // Example of using ref parameter
       return(Total.Value);
    }
*/


public class XOBJ<T> {

    public T Value;

    public  XOBJ() {

    }

    public XOBJ(T value) {
        this.Value = value;
    }

    //
    // Method: Ref()
    // Purpose: returns a Reference Parameter object using the XOBJ value
    //
    public XREF<T> Ref()
    {
        XREF<T> ref = new XREF<T>();
        ref.Obj = this;
        return(ref);
    }

    //
    // Method: Out()
    // Purpose: returns an Out Parameter Object using the XOBJ value
    //
    public XOUT<T> Out()
    {
        XOUT<T> out = new XOUT<T>();
        out.Obj = this;
        return(out);
    }

    //
    // Method get()
    // Purpose: returns the value
    // Note: Because this is combersome to edit in the code,
    // the Value object has been made public
    //
    public T get() {
        return Value;
    }

    //
    // Method get()
    // Purpose: sets the value
    // Note: Because this is combersome to edit in the code,
    // the Value object has been made public
    //
    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();
    }
}


-1

javaには標準的な方法はありません。ほとんどのスワップは、クラスにパッケージ化されているリストで行われます。しかし、それを行う非公式な方法があります:

package Example;

import java.lang.reflect.Field;
import java.util.logging.Level;
import java.util.logging.Logger;



 public class Test{


private static <T> void SetValue(T obj,T value){
    try {
        Field f = obj.getClass().getDeclaredField("value");
        f.setAccessible(true);
        f.set(obj,value);
        } catch (IllegalAccessException | IllegalArgumentException | 
            NoSuchFieldException | SecurityException ex) {
            Logger.getLogger(CautrucjavaCanBan.class.getName()).log(Level.SEVERE, 
       null, ex);
        }
}
private  static  void permutation(Integer a,Integer b){
    Integer tmp = new Integer(a);
    SetValue(a, b);
    SetValue(b, tmp);
}
 private  static  void permutation(String a,String b){
    char[] tmp = a.toCharArray();
    SetValue(a, b.toCharArray());
    SetValue(b, tmp);
}
public static void main(String[] args) {
    {
        Integer d = 9;
        Integer e = 8;
        HoanVi(d, e);
        System.out.println(d+" "+ e);
    }
    {
        String d = "tai nguyen";
        String e = "Thai nguyen";
        permutation(d, e);
        System.out.println(d+" "+ e);
    }
}

}

1
これは、パラメーターの参照セマンティクスを提供するものではなく、リフレクションを使用して不変に設計されたオブジェクトを変更するだけです。これはひどい考えですが、パラメーターの参照セマンティクスはまだ提供されていません。
サービー2018
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.