MySQL Java JavaScript PHP Python HTML-CSS C-sharp

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.

← Lecția anterioară Lecția următoare →