1. Toutes les classes héritentObject
Toutes les classes en Java héritent implicitement de la Object
classe.
Nous analyserons ce qu'est l'héritage et son fonctionnement en Java dans la quête Java Core. Pour l'instant, nous allons considérer un fait simple qui en découle :
Un objet de n'importe quelle classe peut être assigné à une Object
variable. Exemple:
Code | Note |
---|---|
|
La o variable stocke une référence à un Scanner objet |
|
La o variable stocke une référence à un String objet |
|
La o variable stocke une référence à un Integer objet |
|
La o variable stocke une référence à un String objet |
C'est là que s'arrêtent les bonnes nouvelles. Le compilateur ne garde pas trace du type d'objet d'origine enregistré dans une Object
variable, vous ne pourrez donc pas appeler de méthodes sur l'objet enregistré autres que les méthodes de la Object
classe.
Si vous devez appeler les méthodes associées au type d'origine de l'objet, vous devez d'abord enregistrer une référence à celui-ci dans une variable du type correct, puis appeler les méthodes sur cette variable :
Code | Note |
---|---|
|
Le programme ne compilera pas. La Object classe n'a pas nextInt() de méthode. |
|
Cela fonctionnera. Ici, nous enregistrons une référence à un Scanner objet dans une Scanner variable à l'aide d'un opérateur de transtypage . |
Vous ne pouvez pas simplement assigner une Object
variable à une variable Scanner, même si la Object
variable stocke une référence à un Scanner
objet. Mais vous pouvez le faire si vous utilisez l' opérateur de transtypage , que vous connaissez déjà. Voici son aspect général :
Type name1 = (Type) name2;
Où name1
est le nom d'une Type
variable, et name2
est le nom d'une Object
variable qui stocke une référence à un Type
objet.
Transtypage
Si le type de la variable et le type de l'objet ne correspondent pas, alors un ClassCastException
sera lancé. Exemple:
Code | Note |
---|---|
|
Une erreur se produira lors de l'exécution : un ClassCastException sera renvoyé ici |
Il existe un moyen d'éviter cette erreur en Java : nous le faisons en vérifiant le type de l'objet stocké dans une variable :
name instanceof Type
L' instanceof
opérateur vérifie si la name
variable est un Type
objet.
Par exemple, recherchons une chaîne dans un tableau d'objets divers :
Code | Note |
---|---|
|
L'autoboxing convertira ces valeurs en Integer , String et Double , respectivement. Boucle sur le tableau d'objets Si l'objet est un String Enregistrer dans une String variable Afficher la variable à l'écran. |
2. Pourquoi les génériques sont apparus — collections
Revenons aux collections.
Dès que les développeurs Java ont créé la ArrayList
classe, ils ont voulu la rendre universelle, afin qu'elle puisse stocker n'importe quel type d'objet. Ils ont donc utilisé un tableau de Object
s pour stocker les éléments.
La force de cette approche est que vous pouvez ajouter un objet de n'importe quel type à la collection.
Bien sûr, il y a plusieurs faiblesses.
Inconvénient 1.
Il était toujours nécessaire d'écrire un opérateur de conversion de type lors de la récupération d'éléments d'une collection :
Code | Note |
---|---|
|
Créer une collection pour stocker les références aux Object objets Remplir la collection avec des nombres 10 , 20 , ... 100 ; Additionner les éléments de la collection Le typage est nécessaire |
Inconvénient 2.
Il n'y avait aucune garantie qu'une collection contienne un type spécifique d'élément
Code | Note |
---|---|
|
Créer une collection pour stocker des références à Object des objets Nous remplissons la collection avec des nombres représentés sous forme Double d'objets : 0.0 , 2.5 , 5.0 , ... Additionner les éléments de la collection Il y aura une erreur : a Double ne peut pas être transtypé en anInteger |
Les données peuvent être placées dans la collection n'importe où :
- dans une autre méthode
- dans un autre programme
- à partir d'un dossier
- sur le réseau
Inconvénient 3.
Les données de la collection peuvent être modifiées accidentellement.
Vous pouvez transmettre une collection remplie de vos données à une méthode. Cette méthode, écrite par un programmeur différent, ajoute ses données à votre collection.
Le nom de la collection n'indique pas clairement quels types de données peuvent y être stockés. Et même si vous donnez un nom clair à votre variable, une référence à celle-ci peut être transmise à une douzaine de méthodes, et ces méthodes ne sauront certainement rien du nom d'origine de la variable.
3. Génériques
En Java, tous ces problèmes sont éliminés par ce truc sympa appelé les génériques.
En Java, les génériques signifient la possibilité d'ajouter des paramètres de type aux types. Le résultat est un type composite complexe. La vue générale d'un tel type composite est la suivante :
ClassName<TypeParameter>
Il s'agit d'une classe générique. Et il peut être utilisé partout où vous utilisez normalement des cours.
Code | Description |
---|---|
|
Création de variables |
|
Création d'objets |
|
Création de tableaux |
Seules Integer
les variables peuvent être stockées dans une telle collection :
Code | Description |
---|---|
|
ArrayList collection avec Integer des éléments Ceci est autorisé Et cela fonctionnera également
Boîte automatique
Mais ce n'est pas autorisé : erreur de compilation |
Vous apprendrez à créer vos propres classes avec des paramètres de type dans la quête Java Collections. Pour l'instant, nous allons voir comment les utiliser et comment ils fonctionnent.
4. Comment fonctionnent les génériques
En fait, les génériques sont terriblement primitifs.
Le compilateur remplace simplement les types génériques par des types ordinaires. Mais lorsque des méthodes d'un type générique sont utilisées, le compilateur ajoute un opérateur de transtypage pour convertir les paramètres en paramètres de type :
Code | Ce que fait le compilateur |
---|---|
|
|
|
|
|
|
|
|
Supposons que nous ayons une méthode qui additionne les nombres dans une collection d'entiers :
Code | Ce que fait le compilateur |
---|---|
|
|
En d'autres termes, les génériques sont une sorte de sucre syntaxique, tout comme l'autoboxing, mais un peu plus. Avec l'autoboxing, le compilateur ajoute des méthodes pour convertir an int
en an Integer
et vice versa, et pour les génériques, il ajoute des opérateurs de transtypage.
Une fois que le compilateur a compilé vos classes génériques avec des paramètres de type, elles sont simplement converties en classes ordinaires et en opérateurs de transtypage. Les informations sur les arguments de type passés aux variables de types génériques sont perdues. Cet effet est également appelé effacement de type .
Parfois, les programmeurs écrivant des classes génériques (classes avec des paramètres de type) ont vraiment besoin des informations sur les types passés en arguments. Dans la quête Java Collections, vous apprendrez comment gérer cela et ce que cela implique.
5. Quelques faits sur les génériques
Voici quelques faits intéressants sur les génériques.
Les classes peuvent avoir plusieurs paramètres de type. Cela ressemble à ceci :
ClassName<TypeParameter1, TypeParameter2, TypeParameter3>
En fait, ce n'est pas vraiment surprenant. Partout où le compilateur peut ajouter un opérateur à convertir en un type, il peut ajouter plusieurs opérateurs de transtypage.
Exemples:
Code | Note |
---|---|
|
Le put premier paramètre de la méthode est un Integer , et le second est unString |
Les types génériques peuvent également être utilisés comme paramètres . Cela ressemble à ceci :
ClassName<TypeParameter<TypeParameterParameter>>
Supposons que nous voulions créer une liste qui stockera des listes de chaînes. Dans ce cas, nous obtiendrons quelque chose comme ceci :
// List of greetings
ArrayList<String> listHello = new ArrayList<String>();
listHello.add ("Hello");
listHello.add ("Hi");
// List of goodbyes
ArrayList<String> listBye = new ArrayList<String>();
listBye.add("Bye");
listBye.add ("Goodbye");
// List of lists
ArrayList<ArrayList<String>> lists = new ArrayList<ArrayList<String>>();
lists.add(listHello);
lists.add(listBye);
Les types génériques (types avec des paramètres de type) peuvent également être utilisés comme types de tableau. Cela ressemble à ceci :
ClassName<TypeParameter>[] array = new ClassName<TypeParameter>[size];
Il n'y a rien de magique ici : les crochets indiquent simplement le nom du type :
Code | Contrepartie non générique |
---|---|
|
|
|
|
|
|
GO TO FULL VERSION