Utilisation des outils de gestion des collections
La classe Collections fournit des méthodes statiques pour manipuler les collections. Elle est conçue avec un constructeur privé, garantissant qu'elle ne peut pas être instanciée. Toutes ses méthodes sont statiques, accessibles directement via le nom de la classe.
addAll(Collection<? super T> c, T... elements): Ajoute plusieurs éléments à une collection.shuffle(List<?> list): Mélange aléatoirement l'ordre des éléments dans une liste.sort(List<T> list): Trie les éléments selon l'ordre naturel (par exemple, ordre ASCII pour les chaînes).sort(List<T> list, Comparator<? super T> c): Trie les éléments selon une règle personnalisée définie par un comparateur.
Exemple d'utilisation du tri personnalisé
public class Demo02Collections {
public static void main(String[] args) {
ArrayList<Person> list = new ArrayList<>();
list.add(new Person("Liu Yan", 18));
list.add(new Person("Tao Ge", 16));
list.add(new Person("Jin Lian", 20));
Collections.sort(list, (p1, p2) -> p1.getAge() - p2.getAge());
System.out.println(list);
}
}
Implémentation de comparaison via l'interface Comparable
L'interface Comparable permet de définir un ordre naturel pour les objets. La méthode compareTo compare deux instances :
@Override
public int compareTo(Student o) {
return this.score - o.score; // Tri croissant par score
}
Introduction aux génériques
Les génériques permettent de spécifier un type de données au moment de la déclaration, évitant ainsi les conversions explicites et les erreurs à l'exécution.
Définition d'une liste générique
public class MyArrayList<E> {
private Object[] data = new Object[10];
private int size = 0;
public boolean add(E element) {
data[size++] = element;
return true;
}
public E get(int index) {
return (E) data[index];
}
}
Utilisation de méthodes génériques
public static <E> void addAll(ArrayList<E> list, E... elements) {
for (E e : elements) {
list.add(e);
}
}
Spécificités des types génériques
- Wildcard (?) : Permet d’accepter n’importe quel type inconnu.
- Limite supérieure (<? extends T>) : Accepte T ou ses sous-classes.
- Limite inférieure (<? super T>) : Accepte T ou ses superclasses.
Principe de suppression des doublons dans HashSet
HashSet utilise la méthode hashCode() pour calculer une valeur d’empreinte, puis equals() pour comparer les contenus. Deux objets sont considérés comme identiques si leurs empreintes sont égales ET leurs contenus sont identiques.
public class Test03 {
public static void main(String[] args) {
HashSet<Person> set = new HashSet<>();
set.add(new Person("Tao Ge", 16));
set.add(new Person("Jin Lian", 24));
set.add(new Person("Tao Ge", 16)); // Identique → non ajouté
System.out.println(set); // [Person{name='Tao Ge', age=16}, Person{name='Jin Lian', age=24}]
}
}
Structure interne de HashSet
Depuis Java 8, la structure interne de HashSet est une table hachée combinant :
- Un tableau
- Des chaînons (liste simplement liées)
- Des arbres rouge-noir pour améliorer les performances de recherche lorsque les chaînons deviennent trop longs.
Différences entre HashSet et LinkedHashSet
- HashSet : Ne préserve pas l'ordre d'insertion.
- LinkedHashSet : Maintient l'ordre d'insertion grâce à une double liste chaînée associée à la table hachée.
Calcul du code de hachage pour les chaînes
Le hachage d’une chaîne est calculé par une formule récursive :
h = 31 * h + (byte & 0xff)
Le facteur 31 est choisi car il s’agit d’un nombre premier, ce qui minimise les collisions de hachage.
Exemple de mélange de jeu de cartes (Poker)
Création d’un jeu de 54 cartes, mélange avec Collections.shuffle(), puis distribution aux joueurs et réservation des trois dernières cartes comme « fond ».
ArrayList<String> poker = new ArrayList<>();
// Génération des cartes par combinaison de couleurs et valeurs
for (String color : Arrays.asList("♠", "♥", "♣", "♦")) {
for (String value : Arrays.asList("2","3","4","5","6","7","8","9","10","J","Q","K","A")) {
poker.add(color + value);
}
}
poker.add("😊"); poker.add("☺");
Collections.shuffle(poker);
// Distribution
ArrayList<String> player1 = new ArrayList<>(), player2 = new ArrayList<>(),
player3 = new ArrayList<>(), bottom = new ArrayList<>();
for (int i = 0; i < poker.size(); i++) {
String card = poker.get(i);
if (i >= 51) bottom.add(card);
else if (i % 3 == 0) player1.add(card);
else if (i % 3 == 1) player2.add(card);
else player3.add(card);
}
System.out.println("Joueur 1: " + player1);
System.out.println("Joueur 2: " + player2);
System.out.println("Joueur 3: " + player3);
System.out.println("Fond: " + bottom);