1. Toutes les classes héritentObject

Toutes les classes en Java héritent implicitement de la Objectclasse.

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 Objectvariable. Exemple:

Code Note
Object o = new Scanner(System.in);
La ovariable stocke une référence à un Scannerobjet
Object o = new String();
La ovariable stocke une référence à un Stringobjet
Object o = new Integer(15);
La ovariable stocke une référence à un Integerobjet
Object o = "Hello";
La ovariable stocke une référence à un Stringobjet

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 Objectvariable, vous ne pourrez donc pas appeler de méthodes sur l'objet enregistré autres que les méthodes de la Objectclasse.

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
Object o = new Scanner(System.in);
int x = o.nextInt();
Le programme ne compilera pas. La Objectclasse n'a pas nextInt()de méthode.
Object o = new Scanner(System.in);

Scanner console = (Scanner) o;

int x = console.nextInt();
Cela fonctionnera.

Ici, nous enregistrons une référence à un Scannerobjet dans une Scannervariable à l'aide d'un opérateur de transtypage .

Vous ne pouvez pas simplement assigner une Objectvariable à une variable Scanner, même si la Objectvariable stocke une référence à un Scannerobjet. 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;

name1est le nom d'une Typevariable, et name2est le nom d'une Objectvariable qui stocke une référence à un Typeobjet.

Transtypage

Si le type de la variable et le type de l'objet ne correspondent pas, alors un ClassCastExceptionsera lancé. Exemple:

Code Note
Object o = new Integer(5);
String s = (String) o;
Une erreur se produira lors de l'exécution :
un ClassCastExceptionsera 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' instanceofopérateur vérifie si la namevariable est un Typeobjet.

Par exemple, recherchons une chaîne dans un tableau d'objets divers :

Code Note
Object[] objects = {10, "Hello", 3.14};

for (int i = 0; i < objects.length; i++)
{
   if (objects[i] instanceof String)
   {
      String s = (String) objects[i];
      System.out.println(s);
   }
}
L'autoboxing convertira ces valeurs en Integer, Stringet Double, respectivement.

Boucle sur le tableau d'objets

Si l'objet est un String

Enregistrer dans une Stringvariable
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 ArrayListclasse, ils ont voulu la rendre universelle, afin qu'elle puisse stocker n'importe quel type d'objet. Ils ont donc utilisé un tableau de Objects 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
ArrayList numbers = new ArrayList();


for (int i = 0; i < 10; i++)
   numbers.add(i * 10);


int sum = 0;
for (int i = 0; i < 10; i++)
{
   sum = sum + (Integer) numbers.get(i);
}
Créer une collection pour stocker les références aux Objectobjets

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
ArrayList numbers = new ArrayList();


for (int i = 0; i < 10; i++)
   numbers.add(i * 2.5);


int sum = 0;
for (int i = 0; i < 10; i++)
{
   sum = sum + (Integer) numbers.get(i);
}
Créer une collection pour stocker des références à Objectdes objets

Nous remplissons la collection avec des nombres représentés sous forme Doubled'objets :
0.0, 2.5, 5.0, ...


Additionner les éléments de la collection


Il y aura une erreur : a Doublene 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

Génériques en Java

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
ArrayList<Integer> list;
Création de variables
list = new ArrayList<Integer> ();
Création d'objets
ArrayList<Integer>[] array;
Création de tableaux

Seules Integerles variables peuvent être stockées dans une telle collection :

Code Description
ArrayList<Integer> list = new ArrayList<Integer>();
list.add(new Integer(1));
list.add(2);
list.add("Hello");
ArrayListcollection avec Integerdes é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
ArrayList<Integer> list = new ArrayList<Integer>();
ArrayList list = new ArrayList();
list.add(1);
list.add( (Integer) 1 );
int x = list.get(0);
int x = (Integer) list.get(0);
list.set(0, 10);
list.set(0, (Integer) 10);

Supposons que nous ayons une méthode qui additionne les nombres dans une collection d'entiers :

Code Ce que fait le compilateur
public int sum(ArrayList<Integer> numbers)
{
   int result = 0;

   for (int i = 0; i < numbers.size(); i++)
      result = result + numbers.get(i);

   return result;
}
public int sum(ArrayList numbers)
{
   int result = 0;

   for (int i = 0; i < numbers.size(); i++)
      result = result + (Integer) numbers.get(i);

   return result;
}

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 inten an Integeret 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
HashMap<Integer, String> map = new HashMap<Integer, String>();
map.put(7, "Hello");
map.put(-15, "Hello");
Le putpremier 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
ArrayList<String>[] list = new ArrayList<String>[10];
StringArrayList[] list = new StringArrayList[10];
ArrayList<Integer>[] list = new ArrayList<Integer>[10];
IntegerArrayList[] list = new IntegerArrayList[10];
ArrayList<Scanner>[] list = new ArrayList<Scanner>[10];
ScannerArrayList[] list = new ScannerArrayList[10];