Java Language Références d'objet comme paramètres de méthode


Exemple

Cette rubrique explique le concept d'une référence d'objet ; Il s'adresse aux personnes qui découvrent la programmation en Java. Vous devriez déjà être familiarisé avec certains termes et significations: définition de classe, méthode principale, instance d'objet, et appel de méthodes "sur" un objet, et transmission de paramètres aux méthodes.

public class Person {

  private String name;

  public void setName(String name) { this.name = name; }

  public String getName() { return name; }

  public static void main(String [] arguments) {
    Person person = new Person();
    person.setName("Bob");

    int i = 5;
    setPersonName(person, i);

    System.out.println(person.getName() + " " + i);
  }

  private static void setPersonName(Person person, int num) {
    person.setName("Linda");
    num = 99;
  }
}

Pour être pleinement compétent en programmation Java, vous devriez pouvoir expliquer cet exemple à quelqu'un d’autre part. Ses concepts sont fondamentaux pour comprendre le fonctionnement de Java.

Comme vous pouvez le voir, nous avons une main qui instancie un objet à la person variable et appelle une méthode pour définir le champ de name de cet objet sur "Bob" . Ensuite, il appelle une autre méthode et transmet la person comme l'un des deux paramètres; l'autre paramètre est une variable entière, définie sur 5.

La méthode appelée définit la valeur du name sur l'objet passé à "Linda" et définit la variable entière passée à 99, puis renvoie.

Alors qu'est-ce qui serait imprimé?

Linda 5

Alors, pourquoi le changement apporté à la person prend-il effet en main , mais le changement apporté à l'entier ne le fait pas?

Lorsque l'appel est effectué, la méthode principale transmet une référence d'objet à person à la méthode setPersonName ; Toute modification setAnotherName par setAnotherName à cet objet fait partie de cet objet. Par conséquent, ces modifications font toujours partie de cet objet lors du retour de la méthode.

Une autre façon de dire la même chose: la person pointe vers un objet (stocké sur le tas, si cela vous intéresse). Toute modification apportée par la méthode à cet objet est effectuée "sur cet objet" et n'est pas affectée par le fait que la méthode effectuant la modification est toujours active ou a été renvoyée. Lorsque la méthode retourne, toutes les modifications apportées à l'objet sont toujours stockées sur cet objet.

Contrastez ceci avec le nombre entier qui est passé. Comme il s'agit d'une primitive int (et non d'une instance d'objet Integer), elle est transmise "par valeur", ce qui signifie que sa valeur est fournie à la méthode et non par un entier. La méthode peut la changer pour la méthode. propres fins, mais cela n'affecte pas la variable utilisée lors de l'appel de la méthode.

En Java, toutes les primitives sont transmises par valeur. Les objets sont passés par référence, ce qui signifie qu'un pointeur sur l'objet est transmis en tant que paramètre à toutes les méthodes qui les prennent.

Une chose moins évidente: cela ne permet pas à une méthode appelée de créer un nouvel objet et de le retourner comme paramètre. La seule manière pour une méthode de renvoyer un objet créé, directement ou indirectement, par l'appel de méthode est la valeur renvoyée par la méthode. Voyons d'abord comment cela ne fonctionnerait pas, et ensuite comment cela fonctionnerait.

Ajoutons une autre méthode à notre petit exemple ici:

private static void getAnotherObjectNot(Person person) {
  person = new Person();
  person.setName("George");
}

Et, de retour dans la main , au- dessous de l'appel à setAnotherName , nous allons mettre un appel à cette méthode et un autre appel println:

getAnotherObjectNot(person);
System.out.println(person.getName());

Maintenant, le programme imprimera:

Linda 5
Linda

Qu'est-il arrivé à l'objet qui avait George? Eh bien, le paramètre qui a été transmis était un pointeur sur Linda; Lorsque la méthode getAnotherObjectNot créé un nouvel objet, elle a remplacé la référence à l'objet Linda par une référence à l'objet George. L'objet Linda existe toujours (sur le tas), la méthode main peut toujours y accéder, mais la méthode getAnotherObjectNot ne pourra rien faire après, car elle n'y fait aucune référence. Il semblerait que l'auteur du code ait voulu que la méthode crée un nouvel objet et le renvoie, mais si c'est le cas, cela n'a pas fonctionné.

Si c'est ce que l'auteur voulait faire, il devrait renvoyer l'objet nouvellement créé depuis la méthode, quelque chose comme ceci:

private static Person getAnotherObject() {
  Person person = new Person();
  person.setName("Mary");
  return person;
}

Alors appelez comme ceci:

Person mary;
mary = getAnotherObject();
System.out.println(mary.getName());

Et la totalité du programme serait désormais:

Linda 5
Linda
Mary

Voici le programme complet, avec les deux ajouts suivants:

public class Person {
  private String name;

  public void setName(String name) { this.name = name; }
  public String getName() { return name; }

  public static void main(String [] arguments) {
    Person person = new Person();
    person.setName("Bob");

    int i = 5;
    setPersonName(person, i);
    System.out.println(person.getName() + " " + i);
    
    getAnotherObjectNot(person);
    System.out.println(person.getName());
    
    Person person;
    person = getAnotherObject();
    System.out.println(person.getName());
  }
  
  private static void setPersonName(Person person, int num) {
    person.setName("Linda");
    num = 99;
  }
  
  private static void getAnotherObjectNot(Person person) {
    person = new Person();
    person.setMyName("George");
  }
  
  private static person getAnotherObject() {
    Person person = new Person();
    person.setMyName("Mary");
    return person;
  }
}