Moștenirea și generalizările
Clasele generice pot fi implicate în ierarhia de moștenire: pot fi fie moștenite, fie pot juca rolul de clase de bază. Să analizăm diferite situații.
Clasa de bază generică
Atunci când o clasă derivată moștenește o clasă generică, trebuie să specifice tipul în construcția clasei de bază:
class Account<T> {
private T _id;
T getId(){ return _id; }
Account(T id) {
_id = id;
}
}
class DepositAccount<T> extends Account<T> {
DepositAccount(T id){
super(id);
}
}
În constructorul clasei DepositAccount, se face referire la constructorul clasei de bază, unde sunt transmise datele de tip.
Exemple de utilizare a claselor:
DepositAccount<Integer> dAccount1 = new DepositAccount<>(20);
System.out.println(dAccount1.getId());
DepositAccount<String> dAccount2 = new DepositAccount<>("12345");
System.out.println(dAccount2.getId());
Clasa derivată poate adăuga și utiliza propriile sale parametri de tip:
class Account<T> {
private T _id;
T getId(){ return _id; }
Account(T id) {
_id = id;
}
}
class DepositAccount<T, S> extends Account<T> {
private S _name;
S getName(){ return _name; }
DepositAccount(T id, S name) {
super(id);
this._name = name;
}
}
Exemple de utilizare:
DepositAccount<Integer, String> dAccount1 = new DepositAccount<>(20, "Tom");
System.out.println(dAccount1.getId() + " : " + dAccount1.getName());
DepositAccount<String, Integer> dAccount2 = new DepositAccount<>("12345", 23456);
System.out.println(dAccount2.getId() + " : " + dAccount2.getName());
În altă situație, clasa derivată poate să nu fie deloc generică:
class Account<T> {
private T _id;
T getId(){ return _id; }
Account(T id) {
_id = id;
}
}
class DepositAccount extends Account<Integer> {
DepositAccount() {
super(5);
}
}
Aici, la moștenire, este specificat explicit tipul care va fi utilizat de clasa de bază, adică tipul Integer. Apoi, în constructorul clasei de bază, este transmisă o valoare de acest tip – în acest caz, numărul 5.
Exemplu de utilizare:
DepositAccount dAccount1 = new DepositAccount();
System.out.println(dAccount1.getId());
Clasa derivată generică
Poate apărea situația în care clasa de bază este o clasă obișnuită, fără generalizări. De exemplu:
class Account {
private String _name;
String getName(){ return _name; }
Account(String name) {
_name = name;
}
}
class DepositAccount<T> extends Account {
private T _id;
T getId(){ return _id; }
DepositAccount(String name, T id) {
super(name);
_id = id;
}
}
În acest caz, utilizarea construcțiilor clasei de bază în clasa derivată are loc ca de obicei.
Conversia tipurilor generice
Un obiect de un tip generic poate fi convertit într-un alt tip, dacă folosesc același tip de bază. Să analizăm conversia tipurilor pe baza următoarelor două clase generice:
class Account<T> {
private T _id;
T getId(){ return _id; }
Account(T id) {
_id = id;
}
}
class DepositAccount<T> extends Account<T> {
DepositAccount(T id) {
super(id);
}
}
Putem converti un obiect DepositAccount<Integer> în Account<Integer> sau DepositAccount<String> în Account<String>:
DepositAccount<Integer> depAccount = new DepositAccount<>(10);
Account<Integer> account = (Account<Integer>) depAccount;
System.out.println(account.getId());
Însă nu putem face același lucru cu obiecte de tipuri diferite. De exemplu, următorul cod nu va funcționa:
DepositAccount<Integer> depAccount = new DepositAccount<>(10);
Account<String> account = (Account<String>) depAccount;
Această încercare de conversie va produce o eroare, deoarece cele două tipuri generice nu sunt compatibile între ele.