web-dev-qa-db-fra.com

Comment passer un type de données primitif par référence?

Comment passer un type primitif par référence en java? Par exemple, comment puis-je faire passer un int à une méthode modifiable?

43
Neuquino

Il n'y a aucun moyen de passer une primitive directement par référence en Java.

Une solution de contournement consiste à transmettre une référence à une instance d'une classe wrapper, qui contient ensuite la primitive en tant que champ membre. Une telle classe wrapper pourrait être extrêmement simple à écrire par vous-même:

public class IntRef { public int value; }

Mais que diriez-vous de certaines classes wrapper pré-construites, donc nous n'avons pas à écrire les nôtres? D'ACCORD:

Les classes Apache commons-lang Mutable *:
Avantages: Bonnes performances pour une utilisation avec un seul thread. Complétude.
Inconvénients: Introduit une dépendance de bibliothèque tierce. Aucun contrôle de concurrence intégré.
Classes représentatives: MutableBoolean , MutableByte , MutableDouble , MutableFloat , MutableInt , MutableLong , MutableObject , MutableShort .

Les classes Java.util.concurrent.atomic Atomic *:
Avantages: Partie de l'API standard Java (1.5+). Contrôles de concurrence intégrés.
Inconvénients: Petit impact sur les performances lorsqu'il est utilisé dans un paramètre à un seul thread. Prise en charge directe manquante pour certains types de données, par exemple il n'y a pas d'AtomicShort.
Classes représentatives: AtomicBoolean , AtomicInteger , AtomicLong , et AtomicReference .
Remarque: En tant qu'utilisateur ColinD le montre dans sa réponse , AtomicReference peut être utilisé pour approximer certaines des classes manquantes, par ex. AtomicShort.

Longueur 1 tableau primitif
réponse d'OscarRyz montre comment utiliser un tableau de longueur 1 pour "encapsuler" une valeur primitive.
Avantages: Rapide à écrire. Performant. Aucune bibliothèque tierce n'est nécessaire.
Inconvénients: Un peu sale. Aucun contrôle de concurrence intégré. Il en résulte un code qui ne se documente pas (clairement): le tableau dans la signature de la méthode est-il là pour que je puisse passer plusieurs valeurs? Ou est-ce ici comme échafaudage pour une émulation passe-par-référence?

Voir aussi
Les réponses à la question StackOverflow " champ booléen Mutable en Java ".

Mon avis
En Java, vous devez vous efforcer d'utiliser les approches ci-dessus avec parcimonie ou pas du tout. En C, il est courant d'utiliser la valeur de retour d'une fonction pour relayer un code d'état (SUCCESS/FAILURE), tandis que la sortie réelle d'une fonction est relayée via un ou plusieurs paramètres de sortie. En Java, il est préférable d'utiliser des exceptions au lieu de codes retour. Cela libère les valeurs de retour de méthode à utiliser pour transporter la sortie de méthode réelle - un modèle de conception que la plupart des programmeurs Java trouvent plus naturel que les paramètres externes).

73
Mike Clark

Rien dans Java est passé par référence. Tout est passé par valeur.

Edit: Les primitives et les types d'objets sont passés par valeur. Vous ne pouvez jamais modifier la valeur/référence transmise et vous attendre à ce que la valeur/référence d'origine change. Exemple:

String a;
int b;

doSomething(a, b);

...

public void doSomething(String myA, int myB) {
   // whatever I do to "myA" and "myB" here will never ever ever change
   // the "a" and "b"
}

La seule façon de contourner cet obstacle, qu'il s'agisse d'une primitive ou d'une référence, est de passer un objet conteneur ou d'utiliser la valeur de retour.

Avec un support:

private class MyStringHolder {
  String a;
  MyStringHolder(String a) {
    this.a = a;
  }
}

MyStringHolder holdA = new MyStringHolder("something");

public void doSomething(MyStringHolder holder) {
   // alter holder.a here and it changes.
}

Avec valeur de retour

int b = 42;
b = doSomething(b);

public int doSomething(int b) {
  return b + 1;
}
13
Martin Algesten

Passez plutôt un AtomicInteger, AtomicBoolean, etc. Il n'y en a pas pour chaque type primitif, mais vous pouvez utiliser, disons, un AtomicReference<Short> si nécessaire aussi.

Remarque: il devrait très rarement être nécessaire de faire quelque chose comme ça en Java. Lorsque vous voulez le faire, je vous recommande de repenser ce que vous essayez de faire et de voir si vous ne pouvez pas le faire d'une autre manière (en utilisant une méthode qui renvoie un int, disons ... quoi exactement la meilleure chose à faire est de varier d'une situation à l'autre).

13
ColinD

Ce n'est pas possible en Java, comme alternative, vous pouvez l'envelopper dans un tableau à un seul élément.

void demo() { 
    int [] a = { 0 };
    increment ( a ) 
}
void increment( int [] v ) { 
     v[0]++;
}

Mais il y a toujours de meilleures options.

10
OscarRyz

Tu ne peux pas. Mais vous pouvez renvoyer un entier qui est une valeur modifiée

int i = 0;
i = doSomething(i);

Si vous en passez plusieurs, vous pouvez créer un Data Transfer Object (une classe spécifiquement pour contenir un ensemble de variables qui peuvent être passées aux classes).

3
peter.murray.rust

Passez un objet qui a cette valeur en tant que champ.

2
Dan D.

Ce n'est pas possible en Java

1