Puis-je transmettre des paramètres par référence en Java?


Réponses:


225

Java est déroutant car tout est passé par valeur . Cependant, pour un paramètre de type référence (c'est-à-dire pas un paramètre de type primitif), c'est la référence elle-même qui est passée par valeur, donc elle semble être pass-by-reference (et les gens le prétendent souvent). Ce n'est pas le cas, comme le montre ce qui suit:

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

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

Imprimera Hellosur la console. Les options si vous souhaitez imprimer le code ci-dessus Goodbyesont d' utiliser une référence explicite comme suit:

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
En outre, un tableau de longueur 1 peut être utilisé pour créer une référence si vous voulez vraiment confondre les gens :)
Christoffer

2
AtomicReference et les classes correspondantes (AtomicInteger) sont les meilleures pour de telles opérations
Naveen

3
AtomicReference est exagéré, vous ne voulez pas nécessairement de barrière mémoire là-bas, et cela pourrait vous coûter cher. JRuby avait un problème de performance en raison d'une variable volatile utilisée lors de la construction d'un objet. L'option d'utiliser array comme référence ad-hoc me semble assez bonne, et je l'ai vu plusieurs fois utilisé.
Elazar Leibovich

Je ne pense pas que cela soit déroutant, mais c'est un comportement normal.Les types de valeur existent sur la pile et les types de référence existent sur le tas, mais des références aux types de référence existent également sur la pile. Ainsi, vous opérez toujours avec une valeur qui se trouve sur la pile. Je crois que la question ici était: est-il possible de passer une référence de pile qui pointe sur une autre valeur qui est également sur la pile. Ou passer la référence d'une autre référence qui pointe sur une valeur qui vit sur le tas?
eomeroff

cette grande info. J'avais utilisé des tableaux mais cela semble être quelque chose de construit pour le travail. Je ne sais pas sur les performances de ceci par rapport aux tableaux cependant, si dans une boucle critique de performances
steveh

65

Puis-je transmettre des paramètres par référence en Java?

Non.

Pourquoi ? Java n'a qu'un seul mode de transmission d'arguments aux méthodes: par valeur.

Remarque:

Pour les primitives, cela est facile à comprendre: vous obtenez une copie de la valeur.

Pour tous les autres, vous obtenez une copie de la référence et cela s'appelle également passer par valeur.

Tout est dans cette image:

entrez la description de l'image ici


25

En Java, il n'y a rien au niveau du langage similaire à ref . En Java, il n'y a que le passage par valeur sémantique

Par curiosité, vous pouvez implémenter une sémantique de type ref en Java en enveloppant simplement vos objets dans une classe mutable:

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

cas de test:

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

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

Pourquoi ne pas utiliser java.lang.ref.Reference à la place?
Codé en dur

java.lang.ref.Reference n'a pas de méthode set, elle n'est pas modifiable
dfa

pourquoi ne pas utiliser AtomicReference(pour les non-primitifs)? Ou AtomicSomething(par exemple AtomicBoolean:) pour les primitives?
Arvin

Malheureusement, <T> n'accepte pas les types primitifs. Je voudrais faire ceci: Ref <int>
jk7

1
@ jk7 Est-ce vraiment assez important de devoir utiliser à la intplace de Integer, boolau lieu de Booleanet ainsi de suite? Autrement dit, les classes wrapper (qui sont automatiquement déballées si vous vous inquiétez de la syntaxe) ne fonctionnent pas?
Paul Stelian

18

De James Gosling dans "The Java Programming Language":

"... Il y a exactement un mode de passage de paramètre en Java - passer par valeur - et cela simplifie les choses. .."


2
La déclaration du dieu de la langue doit être déclarée la réponse.
ingyhere

3
@ingyhere:: The pronouncement of the language god should be declared the answerPas vraiment. Malgré ce que le créateur de Java pense ou croit, la réponse absolue viendrait d'une citation de la spécification du langage.
paercebal

1
En fait, c'est dans le JLS, dans la section 8.4.1 , et le JLS cite Gosling comme premier auteur: "Lorsque la méthode ou le constructeur est invoqué (§15.12), les valeurs des expressions d'argument réelles initialisent les variables de paramètres nouvellement créées , chacune du type déclaré, avant l'exécution du corps de la méthode ou du constructeur. "
ingyhere

Exactement. Le sarcasme des membres à faible représentant n'est pas utile.
duffymo

11

Je ne pense pas que vous puissiez. Votre meilleure option pourrait être d'encapsuler l'élément que vous voulez passer "par ref" sur une autre instance de classe, et de transmettre la référence de la classe (externe) (par valeur). Si tu vois ce que je veux dire...

c'est-à-dire que votre méthode change l'état interne de l'objet auquel elle est passée, qui est alors visible par l'appelant.


7

Java est toujours passé par valeur.

Lorsque vous passez une primitive, c'est une copie de la valeur, lorsque vous passez un objet, c'est une copie du pointeur de référence.


4

Une autre option est d'utiliser un tableau, par exemple void method(SomeClass[] v) { v[0] = ...; } mais 1) le tableau doit être initialisé avant la méthode invoquée, 2) on ne peut toujours pas implémenter par exemple la méthode de swap de cette façon ... Cette façon est utilisée dans JDK, par exemple dans java.util.concurrent.atomic.AtomicMarkableReference.get(boolean[]).

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.