MySQL Java JavaScript PHP Python HTML-CSS C-sharp

Limitările generalizărilor

Atunci când specificăm un parametru universal în cazul generalizărilor, implicit acesta poate reprezenta orice tip. Totuși, uneori este necesar ca parametrul să corespundă doar unui set limitat de tipuri. În acest caz, se folosesc limitările, care permit indicarea unei clase de bază la care trebuie să corespundă parametrul.

Pentru a seta o limitare, după parametrul universal se utilizează cuvântul „extends”, urmat de clasa de bază a limitării:

class Account{ }
class Transaction<T extends Account>{ }

De exemplu, în acest caz, pentru parametrul T din Transaction, limitarea este clasa Account. Astfel, în locul parametrului T putem transmite fie clasa Account, fie una dintre clasele ei derivare.

Să analizăm următorul program:

public class Program{
     
   public static void main(String[] args) {
         
       Account acc1 = new Account("1876", 4500);
       Account acc2 = new Account("3476", 1500);
             
       Transaction<Account> tran1 = new Transaction<Account>(acc1, acc2, 4000);
       tran1.execute();
       tran1 = new Transaction<Account>(acc1, acc2, 4000);
       tran1.execute();
   }
}
class Transaction<T extends Account>{
   
   private T from;     // de la ce cont se face transferul
   private T to;       // la ce cont se face transferul
   private int sum;    // suma transferului
   
   Transaction(T from, T to, int sum){
       this.from = from;
       this.to = to;
       this.sum = sum;
   }
   public void execute(){
       
       if (from.getSum() > sum)
       {
           from.setSum(from.getSum() - sum);
           to.setSum(to.getSum() + sum);
           System.out.printf("Account %s: %d \nAccount %s: %d \n",
               from.getId(), from.getSum(), to.getId(), to.getSum());
       }
       else{
           System.out.printf("Operation is invalid");
       }
   }
}
class Account{
   
   private String id;
   private int sum;
   
   Account(String id, int sum){
       this.id = id;
       this.sum = sum;
   }
   
   public String getId() { return id; }
   public int getSum() { return sum; }
   public void setSum(int sum) { this.sum = sum; }
}

În acest caz, clasa Transaction, care reprezintă o operațiune de transfer între două conturi, este tipizată cu parametrul T, având ca limitare clasa Account. La crearea unui obiect Transaction, în constructor se transmit două obiecte Account – cele două conturi între care trebuie realizat transferul și suma acestuia.

Este important de înțeles că, deoarece am stabilit o astfel de limitare, compilatorul va recunoaște obiectele de tip T ca obiecte de tip Account. În acest caz, putem apela metodele clasei Account asupra obiectelor de tip T. Dacă nu am fi definit această limitare, ar fi apărut o eroare:

class Transaction<T>{
   // conținutul restului codului
}

În acest caz, ar fi apărut o eroare.

Tipuri generice ca limitări

Și alte tipuri generice, care la rândul lor pot avea limitări, pot fi utilizate ca limitări:

public class Program{
     
   public static void main(String[] args) {
         
       Account<String> acc1 = new Account<String>("1876", 4500);
       Account<String> acc2 = new Account<String>("3476", 1500);
             
       Transaction<Account<String>> tran1 = new Transaction<Account<String>>(acc1, acc2, 4000);
       tran1.execute();
       tran1 = new Transaction<Account<String>>(acc1, acc2, 4000);
       tran1.execute();
   }
}
class Transaction<T extends Account<String>>{
   
   private T from;     // de la ce cont se face transferul
   private T to;       // la ce cont se face transferul
   private int sum;    // suma transferului
   
   Transaction(T from, T to, int sum){
       this.from = from;
       this.to = to;
       this.sum = sum;
   }
   public void execute(){
       
       if (from.getSum() > sum)
       {
           from.setSum(from.getSum() - sum);
           to.setSum(to.getSum() + sum);
           System.out.printf("Account %s: %d \nAccount %s: %d \n",
               from.getId(), from.getSum(), to.getId(), to.getSum());
       }
       else{
           System.out.printf("Operation is invalid");
       }
   }
}
class Account<T>{
   
   private T id;
   private int sum;
   
   Account(T id, int sum){
       this.id = id;
       this.sum = sum;
   }
   
   public T getId() { return id; }
   public int getSum() { return sum; }
   public void setSum(int sum) { this.sum = sum; }
}

În acest caz, limitarea pentru Transaction este tipul Account, care este tipizat cu String.

Interfețele ca limitări

Interfețele pot fi de asemenea utilizate ca limitări. În acest caz, tipul transmis pentru parametrul universal trebuie să implementeze interfața respectivă:

public class Program{
     
   public static void main(String[] args) {
         
       Account acc1 = new Account("1235rwr", 5000);
       Account acc2 = new Account("2373", 4300);
       Transaction<Account> tran1 = new Transaction<Account>(acc1, acc2, 1560);
       tran1.execute();
   }
}
interface Accountable{
   String getId();
   int getSum();
   void setSum(int sum);
}
class Account implements Accountable{
   
   private String id;
   private int sum;
   
   Account(String id, int sum){
       this.id = id;
       this.sum = sum;
   }
   
   public String getId() { return id; }
   public int getSum() { return sum; }
   public void setSum(int sum) { this.sum = sum; }
}
class Transaction<T extends Accountable>{
   
   private T from;     // de la ce cont se face transferul
   private T to;       // la ce cont se face transferul
   private int sum;    // suma transferului
   
   Transaction(T from, T to, int sum){
       this.from = from;
       this.to = to;
       this.sum = sum;
   }
   public void execute(){
       
       if (from.getSum() > sum)
       {
           from.setSum(from.getSum() - sum);
           to.setSum(to.getSum() + sum);
           System.out.printf("Account %s: %d \nAccount %s: %d \n",
               from.getId(), from.getSum(), to.getId(), to.getSum());
       }
       else{
           System.out.printf("Operation is invalid");
       }
   }
}

Limitări multiple

Putem, de asemenea, să setăm mai multe limitări simultan. De exemplu, să presupunem că clasa Transaction poate funcționa doar cu obiecte care implementează simultan interfața Accountable și sunt moștenite din clasa Person:

class Person{}
interface Accountable{}

class Transaction<T extends Person & Accountable>{}
← Lecția anterioară Lecția următoare →