Caratteri jolly (?, extends, super)
Fa parte della sezione Programmazione orientata agli oggetti del percorso Java di Coddy. Lezione 57 di 87.
I parametri di tipo limitati restringono i tipi generici a tipi specifici, ma cosa succede quando lavori con tipi generici esistenti e non conosci, o non ti interessa, il parametro di tipo esatto? È qui che entrano in gioco i wildcard.
Il wildcard illimitato ? rappresenta un tipo sconosciuto. È utile quando vuoi accettare qualsiasi tipo parametrizzato:
public static void printList(List<?> list) {
for (Object item : list) {
System.out.println(item);
}
}
printList(new ArrayList<String>()); // Funziona
printList(new ArrayList<Integer>()); // FunzionaIl carattere jolly con limite superiore ? extends Type accetta il tipo specificato o una qualsiasi delle sue sottoclassi. Usalo quando devi leggere da una struttura generica:
public static double sumNumbers(List<? extends Number> numbers) {
double sum = 0;
for (Number n : numbers) {
sum += n.doubleValue();
}
return sum;
}
sumNumbers(Arrays.asList(1, 2, 3)); // List di Integer
sumNumbers(Arrays.asList(1.5, 2.5)); // List di DoubleIl wildcard con limite inferiore ? super Type accetta il tipo specificato o una qualsiasi delle sue superclassi. Usalo quando devi scrivere in una struttura generica:
public static void addIntegers(List<? super Integer> list) {
list.add(1);
list.add(2);
}
List<Number> numbers = new ArrayList<>();
addIntegers(numbers); // Funziona: Number è un supertipo di IntegerUna linea guida utile: usa extends quando leggi soltanto (produttore), usa super quando scrivi soltanto (consumatore). Questo è noto come principio PECS: Producer Extends, Consumer Super.
Sfida
FacileCostruiamo un sistema di alimentazione dello zoo che dimostri tutti e tre i tipi di caratteri jolly! Creerai una gerarchia di animali e alimenti, poi scriverai metodi di utilità che usano caratteri jolly senza limiti, con limite superiore e con limite inferiore per gestire diversi scenari di alimentazione.
Organizzerai il codice in quattro file:
Food.java: Crea una semplice gerarchia di classi per gli alimenti. Inizia con una classe baseFoodche ha un campo privatoname(String), un costruttore per inizializzarlo e un metodogetName(). Poi crea due sottoclassi nello stesso file:Meatestende Food (il costruttore chiamasuper(name)) eVegetableestende Food (stesso schema).Animal.java: Crea una classe baseAnimalcon un campo privatospecies(String), un costruttore e un metodogetSpecies(). Crea due sottoclassi:CarnivoreeHerbivore, ognuna delle quali estende Animal e chiama il costruttore della classe genitore.ZooFeeder.java: È qui che i caratteri jolly danno il meglio! Crea una classe di utilità con tre metodi statici:printInventory(List<?> items)- Usa un carattere jolly senza limiti per stampare qualsiasi lista. Scorri la lista e stampa ogni elemento usandotoString(), uno per riga.calculateTotalFood(List<? extends Food> foods)- Usa un carattere jolly con limite superiore per leggere da una lista di qualsiasi tipo di Food. Restituisci il conteggio degli elementi comeint. Questo dimostra la lettura da un produttore.addMeatToStock(List<? super Meat> stock, String meatName)- Usa un carattere jolly con limite inferiore per scrivere in una lista che può contenere Meat. Crea un nuovo oggettoMeatcon il nome specificato e aggiungilo alle scorte. Questo dimostra la scrittura in un consumatore.Main.java: Metti insieme il tuo sistema di alimentazione dello zoo! Riceverai due input: un nome di carne (String) e un nome di verdura (String).Per prima cosa, crea un
ArrayList<Food>e aggiungi un oggettoMeatcon il nome della carne e un oggettoVegetablecon il nome della verdura. StampaFood inventory:, poi chiamaprintInventorycon questa lista.Poi, stampa una riga vuota e quindi stampa
Total food items: [count]usandocalculateTotalFoodsulla tua lista di alimenti.Infine, crea un nuovo
ArrayList<Food>chiamatomeatStock. Stampa una riga vuota e poiAdding to meat stock.... ChiamaaddMeatToStockcon questa lista e la stringa"Beef". Poi stampaMeat stock after adding:e chiamaprintInventorysulle scorte di carne.
Riceverai due input nell'ordine seguente: un nome di carne e un nome di verdura.
Sovrascrivi toString() nella tua classe Food affinché restituisca il nome dell'alimento, così la stampa funziona correttamente. Nota come ogni tipo di carattere jolly abbia uno scopo diverso: ? per la massima flessibilità quando devi solo leggere come Object, ? extends quando leggi tipi specifici e ? super quando scrivi in una collezione!
Provalo tu
import java.util.Scanner;
import java.util.ArrayList;
import java.util.List;
class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
String meatName = scanner.nextLine();
String vegetableName = scanner.nextLine();
// TODO: Crea un ArrayList<Food> e aggiungi oggetti Meat e Vegetable
// TODO: Stampa "Food inventory:", poi chiama printInventory
// TODO: Stampa una riga vuota, poi "Total food items: [count]" usando calculateTotalFood
// TODO: Crea un nuovo ArrayList<Food> chiamato meatStock
// TODO: Stampa una riga vuota, poi "Adding to meat stock..."
// TODO: Chiama addMeatToStock con meatStock e "Beef"
// TODO: Stampa "Meat stock after adding:", poi chiama printInventory su meatStock
}
}
Questa lezione include un breve quiz. Inizia la lezione per rispondere e tenere traccia dei tuoi progressi.
Tutte le lezioni di Programmazione orientata agli oggetti
1Fondamenti della programmazione a oggetti
File esterniIntroduzione alla programmazione a oggettiClassi e oggettiLa parola chiave thisMetodiCampi (attributi)Metodo costruttoreSovraccarico dei costruttoriRipasso - Calcolatrice semplice4Ereditarietà
Ereditarietà di base (extends)La parola chiave superSovrascrittura dei metodi (@Override)Concatenamento dei costruttoriLa classe ObjectEreditarietà singola e multilivelloPerché non esiste l'ereditarietà multipla delle classiRiepilogo: gerarchia dei dipendenti7Metodi speciali e classe Object
Metodo toString()equals() e hashCode()Metodo clone()compareTo() e ComparableInterfaccia ComparatorRiepilogo - Ordinamento personalizzato2Modificatori di accesso e incapsulamento
Panoramica dei livelli di accessoMetodi getter e setterNascondimento delle informazioniLa parola chiave finalRiepilogo - Gestore di conti bancari5Polimorfismo
Nozioni di base sull'overloading dei metodiOverride dei metodi (a runtime)Upcasting e downcastingL'operatore instanceofClassi e metodi astrattiRiepilogo - Calcolatore di forme8Concetti avanzati di OOP
Composizione vs ereditarietàAggregazione vs composizioneClassi interne, annidate e anonimeEnum e metodi degli EnumRecord (Java 16+)Classi sealed (Java 17+)11Modelli di progettazione Parte 1
Introduzione ai modelli di progettazionePattern SingletonPattern FactoryPattern BuilderPattern ObserverPattern Strategy3Proprietà di classe e membri statici
Variabili di istanza e staticheMetodi staticiBlocchi staticiCostanti (static final)Riepilogo - Contatore e utility6Interfacce e classi astratte
Introduzione alle interfacceImplementazione delle interfacceImplementazione di più interfacceMetodi default e static nelle interfacceClassi astratte e interfacce a confrontoInterfacce funzionaliRiepilogo: sistema di pagamento9Tipi generici
Introduzione ai tipi genericiClassi genericheMetodi genericiParametri di tipo con limitiCaratteri jolly (?, extends, super)Riepilogo - Contenitore generico12Modelli di progettazione – Parte 2
Pattern CommandPattern AdapterPattern DecoratorPattern Template MethodPattern StatePattern CompositePattern IteratorEsercitati da solo: Compilatore Java online