web-dev-qa-db-fra.com

Est-ce que Java a quelque chose comme les mots-clés ref et out de C #?

Quelque chose comme ce qui suit:

exemple de référence:

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

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

par exemple:

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

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

Non, Java n'a pas les mots clés ref et out de C # pour passer par référence.

Vous ne pouvez passer que par valeur en Java. Même les références sont passées par valeur. Voir la page de Jon Skeet à propos de passage de paramètre en Java pour plus de détails.

Pour faire quelque chose de similaire à ref ou out, vous devez envelopper vos paramètres dans un autre objet et passer la référence de cet objet en tant que paramètre.

89
Mark Byers

Réponse directe: non

Mais vous pouvez simuler référence avec wrappers .

Et procédez comme suit:

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

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

En dehors

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

Et fondamentalement tout autre type tel que:

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

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

Java transmet les paramètres par valeur et ne dispose d'aucun mécanisme pour autoriser le passage par référence. Cela signifie que chaque fois qu'un paramètre est passé, sa valeur est copiée dans le cadre de la pile qui gère l'appel.

Le terme valeur tel que je l'utilise ici nécessite quelques précisions. Dans Java, nous avons deux types de variables: les primitives et les objets. Une valeur d'une primitive est la primitive elle-même et la valeur d'un objet est sa référence (et non l'état de l'objet Par conséquent, toute modification de la valeur dans la méthode modifiera uniquement la copie de la valeur dans la pile et ne sera pas vue par l'appelant. Par exemple, il n'y a aucun moyen d'implémenter une méthode de swap réelle, qui reçoit deux références et les échange (pas leur contenu!).

7
Eyal Schneider

Comme beaucoup d'autres, j'avais besoin de convertir un projet C # en Java. Je n'ai pas trouvé de solution complète sur le Web en ce qui concerne les modificateurs out et ref. Mais, j'ai pu prendre les informations que j'ai trouvées et les développer pour créer mes propres classes afin de répondre aux exigences. Je voulais faire une distinction entre les paramètres ref et out pour la clarté du code. Avec les classes ci-dessous, c'est possible. Puisse cette information sauver le temps et les efforts des autres.

Un exemple est inclus dans le code ci-dessous.

//*******************************************************************************************
//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

En fait, il n'y a ni ref ni out mot-clé équivalent dans Java langage pour autant que je sache. Cependant, je viens de transformer un code C # en Java qui utilise le paramètre out et vous conseille ce que je viens de faire. Vous devez envelopper n'importe quel objet dans une classe wrapper et transmettre les valeurs encapsulées dans une instance d'objet wrapper comme suit:

Un exemple simple d'utilisation de Wrapper

Voici le Wrapper Class;

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

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

Et voici le code de test;

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

}

Un exemple du monde réel

Une méthode C # .NET utilisant le paramètre out

Ici, il existe une méthode C # .NET qui utilise le mot clé out;

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

Équivalent Java du code C # utilisant le paramètre out

Et l’équivalent Java de cette méthode à l’aide de classe de wrapper est le suivant;

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

Classe d'emballage

Et la classe wrapper utilisée dans ce Java est comme ci-dessous;

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
Levent Divilioglu

Trois solutions non officiellement, explicitement mentionnées:

ArrayList<String> doThings() {
  //
}

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

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

Pour Pair, je recommanderais: https://commons.Apache.org/proper/commons-lang/apidocs/org/Apache/commons/lang3/Tuple/Pair.html

1
Andrew