JavaRush /Blog Java /Random-FR /Expansion et contraction des types de référence

Expansion et contraction des types de référence

Publié dans le groupe Random-FR
Bonjour! Dans l'une des conférences précédentes, nous avons discuté du casting de types primitifs. Rappelons brièvement de quoi nous parlions. Expansion et contraction des types de référence - 1Nous avons représenté les types primitifs (dans ce cas, numériques) comme des poupées gigognes en fonction de la quantité de mémoire qu'elles occupent. Comme vous vous en souvenez, placer une poupée gigogne plus petite dans une poupée plus grande sera simple à la fois dans la vie réelle et en programmation Java.
public class Main {
   public static void main(String[] args) {
        short smallNumber = 100;
        int bigNumber =  smallNumber;
        System.out.println(bigNumber);
   }
}
Ceci est un exemple de conversion automatique, ou extension . Cela se produit tout seul, il n’est donc pas nécessaire d’écrire du code supplémentaire. En fin de compte, nous ne faisons rien d’inhabituel : nous mettons simplement une poupée gigogne plus petite dans une poupée gigogne plus grande. C’est une autre affaire si nous essayons de faire le contraire et de mettre une grande poupée matriochka dans une plus petite. Cela ne peut pas être fait dans la vie, mais dans la programmation, cela peut être fait. Mais il y a une mise en garde. Si nous essayons de mettre une valeur intdans une variable short, cela ne fonctionnera pas aussi facilement. Après tout, seuls 16 bits d'information peuvent tenir dans une variable short, mais la valeur intprend 32 bits ! En conséquence, la valeur transmise sera faussée. Le compilateur nous donnera une erreur (« mec, tu fais quelque chose de suspect ! »), mais si nous spécifions explicitement vers quel type nous convertissons notre valeur, il effectuera toujours une telle opération.
public class Main {

   public static void main(String[] args) {

       int bigNumber = 10000000;

       bigNumber = (short) bigNumber;

       System.out.println(bigNumber);

   }

}
Dans l’exemple ci-dessus, c’est exactement ce que nous avons fait. L'opération a été terminée, mais comme shortseuls 16 des 32 bits rentrent dans la variable, la valeur finale a été déformée et nous avons donc reçu le nombre -27008 . Cette opération est appelée conversion explicite, ou rétrécissement .

Exemples d'extension et de contraction de types de référence

Nous allons maintenant parler des mêmes opérations, mais applicables non pas aux types primitifs, mais aux objets et variables de référence ! Comment ça marche en Java ? Assez simple en fait. Il existe des objets qui ne sont pas liés les uns aux autres. Il serait logique de supposer qu’ils ne peuvent pas être convertis les uns aux autres, ni explicitement ni automatiquement :
public class Cat {
}

public class Dog {
}

public class Main {

   public static void main(String[] args) {

       Cat cat = new Dog();//error!

   }

}
Ici, nous obtiendrons bien sûr une erreur. Les classes ne Catsont Dogpas liées les unes aux autres, et nous n'avons pas écrit de « convertisseur » de l'une à l'autre. Il est logique que nous ne puissions pas faire cela : le compilateur n’a aucune idée de comment convertir ces objets entre eux. C’est une autre affaire si les objets sont connectés les uns aux autres ! Comment? Tout d’abord, utiliser l’héritage. Essayons de créer un petit système de classes avec héritage. Nous aurons une classe générale représentant les animaux :
public class Animal {

   public void introduce() {

       System.out.println("i'm Animal");
   }
}
Les animaux, comme vous le savez, sont domestiques et sauvages :
public class WildAnimal extends Animal {

   public void introduce() {

       System.out.println("i'm WildAnimal");
   }
}

public class Pet extends Animal {

   public void introduce() {

       System.out.println("i'm Pet");
   }
}
Par exemple, prenons les chiens - un chien domestique et un coyote :
public class Dog extends Pet {

   public void introduce() {

       System.out.println("i'm Dog");
   }
}





public class Coyote extends WildAnimal {

   public void introduce() {

       System.out.println("i'm Coyote");
   }
}
Nos classes sont volontairement les plus primitives pour les rendre plus faciles à percevoir. Nous n’avons pas vraiment besoin de champs ici, et une seule méthode suffit. Essayons d'exécuter le code suivant :
public class Main {

   public static void main(String[] args) {

       Animal animal = new Pet();
       animal.introduce();
   }
}
Selon vous, qu'est-ce qui sera envoyé à la console ? introduceLa classe Petou la méthode de classe fonctionnera-t-elle Animal? Essayez de justifier votre réponse avant de poursuivre la lecture. Et voici le résultat! je m'appelle Pet. Pourquoi la réponse s'est-elle révélée ainsi ? C'est simple. Nous avons une variable parent et un objet enfant. En écrivant:
Animal animal = new Pet();
Nous avons étendu un type référencePet et stocké son objet dans une variable Animal. Comme pour les types primitifs, l’extension des types référence en Java se fait automatiquement. Il n'est pas nécessaire d'écrire du code supplémentaire pour cela. Nous avons maintenant un objet enfant attaché à la référence parent, et par conséquent nous voyons que la méthode est appelée sur la classe enfant. Si vous ne comprenez toujours pas pourquoi ce code fonctionne, réécrivez-le dans un langage simple :
Животное животное = new ДомашнееЖивотное();
Il n'y a aucun problème avec ça, n'est-ce pas ? Imaginez que c'est la vraie vie, et que le lien dans ce cas est une simple étiquette en papier qui dit « Animal ». Si vous prenez un tel morceau de papier et l'attachez au collier de n'importe quel animal, tout ira bien. Tout animal de compagnie reste un animal ! Le processus inverse, c'est-à-dire descendre dans l'arbre d'héritage jusqu'aux héritiers, est un rétrécissement :
public class Main {

   public static void main(String[] args) {

       WildAnimal wildAnimal = new Coyote();

       Coyote coyote = (Coyote) wildAnimal;

       coyote.introduce();
   }
}
Comme vous pouvez le voir, nous indiquons ici explicitement dans quelle classe nous voulons caster notre objet. Auparavant, nous avions une variable WildAnimal, et maintenant Coyote, qui descend dans l'arbre d'héritage. Il est logique que le compilateur ne saute pas une telle opération sans indication explicite, mais si vous spécifiez le type entre parenthèses, tout fonctionnera. Expansion et contraction des types de référence - 2 Regardons un autre exemple, plus intéressant :
public class Main {

   public static void main(String[] args) {

       Pet pet = new Animal();//error!
   }
}
Le compilateur renvoie une erreur ! Quelle est la raison? Le fait est que vous essayez d'attribuer un objet parent à une variable enfant. En d'autres termes, vous voulez faire ceci :
ДомашнееЖивотное домашнееЖивотное = new Животное();
Mais peut-être que si nous indiquons explicitement le type vers lequel nous essayons de convertir, nous réussirons ? Les chiffres semblent fonctionner, essayons ! :)
public class Main {

   public static void main(String[] args) {

       Pet pet = (Pet) new Animal();
   }
}
Exception dans le fil de discussion "main" java.lang.ClassCastException : l'animal ne peut pas être converti en animal de compagnie. Erreur ! Le compilateur ne s'est pas plaint cette fois, mais nous avons finalement reçu une exception. Nous connaissons déjà la raison : nous essayons d'attribuer un objet parent à une variable enfant. Pourquoi, en fait, cela ne peut-il pas être fait ? Parce que tous les animaux ne sont pas des animaux de compagnie. Vous avez créé un objet Animalet essayez de l'affecter à une variable Pet. Mais, par exemple, un coyote est aussi Animal, mais ce n’est pas Petun animal domestique. Autrement dit, lorsque vous écrivez :
Pet pet = (Pet) new Animal();
new Animal()N’importe quel animal peut être là , et il n’est pas nécessaire qu’il soit domestique ! Naturellement, votre variable Pet petne convient que pour stocker des animaux de compagnie (et leurs descendants), et pas pour tout le monde. Par conséquent, pour de tels cas, une exception spéciale a été créée en Java - ClassCastExceptionune erreur lors de la conversion des classes. Répétons-le pour que ce soit plus clair. Une variable parent (référence) peut pointer vers un objet d'une classe descendante :
public class Main {

   public static void main(String[] args) {

       Pet pet =  new Pet();
       Animal animal = pet;

       Pet pet2 = (Pet) animal;
       pet2.introduce();
   }
}
Par exemple, nous n’aurons aucun problème ici. Nous avons un objet Petqui est pointé par un lien Pet. Puis un nouveau lien a commencé à pointer vers le même objet Animal. Après quoi nous effectuons la conversion animalen Pet. Au fait, pourquoi avons-nous fait cela ? La dernière fois, nous avons eu une exception ! Parce que cette fois notre objet original est Pet pet!
Pet pet =  new Pet();
Et dans l'exemple précédent c'était un objet Animal:
Pet pet = (Pet) new Animal();
Une variable descendante ne peut pas se voir attribuer un objet ancêtre. Au contraire, vous pouvez le faire.
Commentaires
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION