In Java können Klassen und Interfaces generisch sein.
Generisch heißt, dass Funktionalität unabhängig von einem Typ implementiert werden können.
Alle Klassen stellen immer die gleiche Funktionalität bereit, egal welchen Typ wir verwenden.
Egal ob wir Objekte vom Typ Human, Dog, String oder Integer in einer ArrayList abspeichern, wir haben immer die gleichen Methoden zur verfügung.
add, remove, size etc.
Egal ob wir Comparator oder Comparable Klassen vom Typ Human, Dog, String oder Integer erstellen, wir haben immer die gleichen Methoden zur verfügung.
Collections.sort
Will man in seiner Anwendung eine Liste von Menschen abspeichern ist der spezifische Typ bekannt.
Nach dem Klassennamen wird innerhalb von spitzen Klammern, der spezifische Typ angegeben.
public class Main {
public static void main(String[] args) {
ArrayList<Human> humans = new ArrayList<>();
}
}
public class HumanComp implements Comparator<Human> {
public int compare(Human h1, Human h2) {
// implementation details
}
}
Um eine generische Klasse zu erstellen, wird nach dem Klassennamen in spitzen Klammern der Typparameter angegeben.
public class Team<T> {
// implementierung der Klasse
}
public class Team<T> {
// implementierung der Klasse
}
public class Team<A> {
// implementierung der Klasse
}
public class Team<HANS> {
// implementierung der Klasse
}
public class Team<BLIBLABLUBB> {
// implementierung der Klasse
}
Der Bezeichner des Typparameters kann frei gewählt werden.
public class Team<T> {
// implementierung der Klasse
}
public class Team<T,U> {
// implementierung der Klasse
}
public class Team<T, U, V> {
// implementierung der Klasse
}
Es können mehrere Typparameter kommagetrennt angegeben werden.
public class Team<T> {
private String teamName;
private ArrayList<T> teamMembers = new ArrayList<>();
public Team(String teamName) {
this.teamName = teamName;
}
public String getTeamName() {
return this.teamName;
}
public void addMember(T member) {
this.teamMembers.add(member);
}
}
public class Main {
public static void main(String[] args) {
Team<FootballPlayer> scf = new Team<>("SC Freiburg");
Team<HockeyPlayer> wildwings = new Team<>("Wildwings");
scf.addMember(new FootballPlayer("Steffen");
scf.addMember(new HockeyPlayer("Mirco"); // fails
wildwings.addMember(new HockeyPlayer("Mirco");
}
}
public class Main {
public static int add(int a, int b) { // Parameter
return a + b;
}
public static void main(String[] args) {
int result = Main.add(1, 2); // Argumente
}
}
public class Team<T> { // Typparameter
public ArrayList<T> members; // Typargument
}
//...
Team<Human> humanTeam = new Team<>();// Typargument
//...
Um noch mehr Funktionalitäten in eine generische Klasse auszulagern ist es notwendig den Typ einzuschränken.
Mit extends und super können die möglichen Typen eingeschränkt werden.
public class Team<T extends Player> {
// Player und Subtypen von Player erlaubt
}
public class Team<T super Player> {
// Player und Supertypen von Player erlaubt
}
public class Player {}
public class BaseballPlayer extends Player {}
public class FootballPlayer extends Player {}
public class ExtremeFootballPlayer extends FootballPlayer {}
public class Team<T extends Player> {} //PBFE erlaubt
public class Team<T extends FootballPlayer> {} //FE erlaubt
public class Team<T super Player> {} // P erlaubt
public class Team<T super FootballPlayer> {} //PF erlaubt
Mit Hilfe der Optional Klasse kann man NullPointerExceptions einfach behandeln.
Was sind NullPointerExceptions?
public class Dog {
public String name;
public Dog(String name) {
this.name = name;
}
}
public class Main {
public static void main(String[] args) {
Dog doggo = new Dog(null);
doggo.name.equals("Bello"); // funktioniert nicht
}
}
public class Dog {
public Optional<String> name;
public Dog(String name) {
this.name = Optional.ofNullable(name);
}
}
Die Optional Klasse verpackt den echten Wert hinter Methoden.
Mithilfe von Methoden kann überprüft werden, ob ein Wert Null ist oder nicht.
public class Main {
public static void main(String[] args) {
Optional<String> name = Name.createName();
if(name.isPresent()) {
System.out.println(name.get());
}
if(name.isEmpty()) {
System.out.println("No Name");
}
}
}
public class Main {
public static void main(String[] args) {
Optional<String> name = Name.createName();
name.ifPresent((value) -> System.out.println(value));
name.ifPresentOrElse(
(value) -> System.out.println(value),
() -> System.out.println("No Name")
);
}
}
*NKR
Ein Record ist eine Datenklasse, deren Attribute nicht verändert werden können.
Eine Datenklasse hat somit finale Attribute und Getter.
public record Dog(String name, int age) {}
public class Main {
public static void main(String[] args) {
Dog bello = new Dog("Bello", 12);
String name = bello.name();
int age = bello.age();
}
}