web-dev-qa-db-ja.com

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

次のようなもの:

参照例:

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"
}
99

いいえ、Javaには、参照渡しのためのC#のrefおよびoutキーワードのようなものはありません。

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

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

89
Mark Byers

直接的な答え:いいえ

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

そして、次のことを行います。

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
25
OscarRyz

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

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

7
Eyal Schneider

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

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

//*******************************************************************************************
//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();
    }
}
6
James W Simms

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

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

ラッパークラス;

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!";
    }

}

実世界の例

出力パラメーターを使用するC#.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

そして、Javawrapper classの助けを借りてこのメソッドに相当するものは次のとおりです。

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;
    }

}
6

公式には明らかにされていない3つのソリューション:

ArrayList<String> doThings() {
  //
}

void doThings(ArrayList<String> list) {
  //
}

Pair<String, String> doThings() {
  //
}

ペアについては、以下をお勧めします。 https://commons.Apache.org/proper/commons-lang/apidocs/org/Apache/commons/lang3/Tuple/Pair.html

1
Andrew