Gebundene Typparameter
Teil des Abschnitts Objektorientierte Programmierung der Java-Journey von Coddy. Lektion 56 von 87.
Bisher können unsere generischen Typparameter jeden Typ akzeptieren. Aber was ist, wenn du sie einschränken musst?
Zum Beispiel sollte eine Methode, die die Summe von Zahlen berechnet, keine Zeichenketten akzeptieren. Mit begrenzten Typparametern kannst du einschränken, welche Typen mit deinen Generics verwendet werden können.
Verwende das Schlüsselwort extends, um eine obere Grenze für einen Typparameter festzulegen:
class NumberBox<T extends Number> {
private T value;
public NumberBox(T value) {
this.value = value;
}
public double getDoubleValue() {
return value.doubleValue(); // Kann Number-Methoden aufrufen!
}
}
NumberBox<Integer> intBox = new NumberBox<>(42);
NumberBox<Double> doubleBox = new NumberBox<>(3.14);
// NumberBox<String> strBox = new NumberBox<>("Hi"); // Kompilierfehler!Die Begrenzung T extends Number bedeutet, dass T Number oder eine beliebige seiner Unterklassen (Integer, Double usw.) sein muss. Dadurch kannst du außerdem auf dem Typparameter die in Number definierten Methoden aufrufen.
Du kannst mehrere Grenzen mit & angeben. Wenn eine Grenze eine Klasse ist, muss sie zuerst kommen:
class DataProcessor<T extends Number & Comparable<T>> {
public boolean isGreater(T a, T b) {
return a.compareTo(b) > 0;
}
}Hier muss T Number erweitern UND Comparable implementieren. Beschränkte Typparameter funktionieren auch mit generischen Methoden:
public static <T extends Comparable<T>> T findMax(T a, T b) {
return a.compareTo(b) > 0 ? a : b;
}
String result = findMax("apple", "banana"); // Gibt "banana" zurückBegrenzte Typparameter machen deine Generics leistungsfähiger, indem sie Typsicherheit gewährleisten und gleichzeitig den Zugriff auf bestimmte Methoden des gebundenen Typs ermöglichen.
Aufgabe
EinfachLass uns einen Statistikrechner erstellen, der nur mit numerischen Typen funktioniert! Du wirst begrenzte Typparameter verwenden, um sicherzustellen, dass dein Rechner nur Zahlen verarbeiten kann, und erhältst dabei Zugriff auf nützliche Methoden der Klasse Number.
Du wirst deinen Code auf drei Dateien verteilen:
NumberStats.java: Erstelle eine generische Klasse, die Statistiken für numerische Werte berechnet. Deine KlasseNumberStats<T extends Number>sollte zwei private Felder vom TypTspeichern:value1undvalue2. Füge einen Konstruktor hinzu, der beide Werte akzeptiert. Füge eine MethodegetSum()hinzu, die die Summe beider Werte alsdoublezurückgibt (verwende die von Number geerbte MethodedoubleValue()). Füge außerdem eine MethodegetAverage()hinzu, die den Durchschnitt der beiden Werte alsdoublezurückgibt.ComparableBox.java: Erstelle eine generische Klasse mit mehreren Schranken, die den größeren von zwei Werten finden kann. Deine KlasseComparableBox<T extends Number & Comparable<T>>sollte zwei private Felder vom TypTspeichern:firstundsecond. Füge einen Konstruktor hinzu, der beide Werte akzeptiert. Füge eine MethodegetMax()hinzu, die mithilfe voncompareTo()den größeren Wert zurückgibt. Füge außerdem eine MethodegetMaxAsDouble()hinzu, die den größeren Wert in einendoubleumwandelt.Main.java: Erwecke deine begrenzten Generics zum Leben! Du erhältst vier Eingaben: zwei Ganzzahlen und zwei Gleitkommazahlen.Erstelle zuerst ein
NumberStats<Integer>mit den beiden Ganzzahlwerten. Gib die Summe und den Durchschnitt aus:Integer sum: [sum] Integer average: [average]Erstelle als Nächstes ein
NumberStats<Double>mit den beiden Gleitkommazahlen. Gib die Summe und den Durchschnitt aus:Double sum: [sum] Double average: [average]Erstelle schließlich ein
ComparableBox<Integer>mit den beiden Ganzzahlwerten und gib Folgendes aus:Max integer: [max] Max as double: [maxAsDouble]
Du erhältst vier Eingaben in dieser Reihenfolge: erste Ganzzahl, zweite Ganzzahl, erste Gleitkommazahl, zweite Gleitkommazahl.
Beachte, wie die Schranke T extends Number es dir ermöglicht, doubleValue() für deinen generischen Typ aufzurufen. Das wäre mit einem unbegrenzten Typparameter nicht möglich. Und die mehreren Schranken in ComparableBox stellen sicher, dass du sowohl in einen double umwandeln als auch Werte vergleichen kannst!
Probier es selbst
import java.util.Scanner;
class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// Eingaben lesen
int int1 = scanner.nextInt();
int int2 = scanner.nextInt();
double double1 = scanner.nextDouble();
double double2 = scanner.nextDouble();
// TODO: Erstelle ein NumberStats<Integer> mit den beiden Integer-Werten
// Gib die Summe und den Durchschnitt im folgenden Format aus:
// Integer sum: [sum]
// Integer average: [average]
// TODO: Erstelle ein NumberStats<Double> mit den beiden Double-Werten
// Gib die Summe und den Durchschnitt im folgenden Format aus:
// Double sum: [sum]
// Double average: [average]
// TODO: Erstelle ein ComparableBox<Integer> mit den beiden Integer-Werten
// Gib das Maximum und das Maximum als Double im folgenden Format aus:
// Max integer: [max]
// Max as double: [maxAsDouble]
}
}
Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.
Alle Lektionen in Objektorientierte Programmierung
1Grundlagen der OOP
Externe DateienEinführung in die OOPKlassen vs. ObjekteDas Schlüsselwort thisMethodenFelder (Attribute)KonstruktormethodeÜberladen von KonstruktorenRückblick – Einfacher Taschenrechner4Vererbung
Grundlegende Vererbung (extends)Das Schlüsselwort superÜberschreiben von Methoden (@Override)KonstruktorverkettungDie Object-KlasseEinfach- und mehrstufige VererbungWarum keine Mehrfachvererbung von KlassenRückblick – Mitarbeiterhierarchie7Spezielle Methoden & Object-Klasse
toString()-Methodeequals() und hashCode()clone()-MethodecompareTo() und ComparableComparator-SchnittstelleRückblick – Benutzerdefinierte Sortierung2Zugriffsmodifikatoren & Kapselung
Übersicht der ZugriffsebenenGetter- und Setter-MethodenInformationsverbergungDas Schlüsselwort finalRückblick – Bankkontoverwaltung5Polymorphismus
Grundlagen der MethodenüberladungMethodenüberschreibung (Laufzeit)Upcasting und DowncastingDer instanceof-OperatorAbstrakte Klassen und MethodenRückblick – Formrechner8Fortgeschrittene OOP-Konzepte
Komposition vs. VererbungAggregation vs. KompositionInnere, verschachtelte & anonyme KlassenEnums und Enum-MethodenRecords (Java 16+)Versiegelte Klassen (Java 17+)11Entwurfsmuster Teil 1
Einführung in EntwurfsmusterSingleton-MusterFactory-MusterBuilder-MusterObserver-MusterStrategie-Muster14Abschließende Herausforderungen
E-Learning-PlattformBankingsystemEntwicklung einer SpielfigurFahrzeugvermietungsdienst3Klassen-Props & statische Member
Instanz- vs. statische VariablenStatische MethodenStatische BlöckeKonstanten (static final)Wiederholung – Counter & Utility6Schnittstellen & abstrakte Klassen
Einführung in InterfacesInterfaces implementierenMehrere Interfaces implementierenDefault & Static in InterfacesAbstrakte Klassen vs. InterfacesFunktionale InterfacesRückblick – Zahlungssystem9Generics
Einführung in GenericsGenerische KlassenGenerische MethodenGebundene TypparameterWildcards (?, extends, super)Rückblick – Generischer ContainerÜbe selbstständig: Online-Java-Compiler