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);privatevoid 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:
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.
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. .."
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.
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[]).
Réponses:
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:
Imprimera
Hello
sur la console. Les options si vous souhaitez imprimer le code ci-dessusGoodbye
sont d' utiliser une référence explicite comme suit:la source
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:
la source
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:
cas de test:
la source
AtomicReference
(pour les non-primitifs)? OuAtomicSomething
(par exempleAtomicBoolean
:) pour les primitives?int
place deInteger
,bool
au lieu deBoolean
et 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?De James Gosling dans "The Java Programming Language":
la source
The pronouncement of the language god should be declared the answer
Pas 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.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.
la source
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.
la source
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 dansjava.util.concurrent.atomic.AtomicMarkableReference.get(boolean[])
.la source