This shows you the differences between two versions of the page.
|
poo:breviare:breviar-06 [2020/11/10 09:16] mihai.nan |
poo:breviare:breviar-06 [2025/11/08 12:34] (current) george.tudor1906 |
||
|---|---|---|---|
| Line 1: | Line 1: | ||
| ====== Breviar 6 ====== | ====== Breviar 6 ====== | ||
| + | === Clase abstracte și metode abstracte === | ||
| + | == Introducere == | ||
| + | |||
| + | În proiectarea unei aplicații este adesea necesar să reprezentăm, cu ajutorul claselor, concepte **abstracte**, care nu pot fi instanțiate și care servesc doar la dezvoltarea ulterioară a unor clase ce descriu obiecte concrete. | ||
| + | |||
| + | De exemplu, în pachetul **java.lang** există clasa abstractă **Number**, care modelează conceptul generic de „număr”. Într-un program nu avem însă nevoie de „numere generice”, ci de numere cu un anumit tip: întregi, reale etc. | ||
| + | Clasa **Number** servește ca superclasă pentru clasele concrete **Byte**, **Double**, **Float**, **Integer**, **Long** și **Short**, care implementează obiecte pentru descrierea numerelor de un anumit tip. | ||
| + | |||
| + | <note important> | ||
| + | O clasă abstractă **nu poate fi instanțiată**. În locul ei vom utiliza **subclasele sale** care **nu sunt abstracte**. | ||
| + | </note> | ||
| + | |||
| + | == Declararea claselor abstracte == | ||
| + | |||
| + | O clasă se declară ca fiind abstractă folosind cuvântul-cheie **abstract**. | ||
| + | O clasă abstractă poate avea modificatorul **public**, accesul implicit fiind la nivel de pachet. | ||
| + | Ea **nu poate** specifica modificatorul **final**, deoarece combinația `abstract final` este semnalată ca **eroare de compilare** (o clasă `final` nu poate fi extinsă, iar o clasă `abstract` trebuie extinsă). | ||
| + | |||
| + | O clasă abstractă poate conține aceleași elemente membre ca o clasă obișnuită, dar și **metode abstracte** – adică metode **fără implementare efectivă**. | ||
| + | |||
| + | <code java> | ||
| + | public abstract class Patrulater { | ||
| + | class Point { | ||
| + | int x, y; | ||
| + | public Point(int x, int y) { | ||
| + | this.x = x; | ||
| + | this.y = y; | ||
| + | } | ||
| + | } | ||
| + | |||
| + | Point p1, p2, p3, p4; | ||
| + | |||
| + | // Metode abstracte | ||
| + | abstract int calculPerimetru(); | ||
| + | abstract double calculArie(); | ||
| + | } | ||
| + | </code> | ||
| + | |||
| + | == Metode abstracte == | ||
| + | |||
| + | Spre deosebire de clasele obișnuite, care trebuie să furnizeze implementări pentru toate metodele declarate, o clasă abstractă poate conține **metode fără implementare**. | ||
| + | Astfel de metode se numesc **metode abstracte** și pot apărea **doar** în clase abstracte. | ||
| + | |||
| + | În declararea unei metode abstracte se folosește cuvântul-cheie **abstract**. | ||
| + | |||
| + | == Exemplu practic == | ||
| + | |||
| + | Paralelogramul, dreptunghiul, pătratul și rombul sunt figuri geometrice ce pot fi caracterizate prin patru puncte din plan. | ||
| + | Pentru fiecare astfel de figură există o formulă prin care îi putem determina **aria**, știind coordonatele celor patru puncte sau alte date suplimentare. | ||
| + | |||
| + | Prin urmare, clasele care modelează aceste figuri pot fi derivate dintr-o clasă abstractă **Patrulater**. | ||
| + | Deoarece pentru fiecare figură avem o formulă diferită de calcul al ariei, este normal ca **Patrulater** să conțină o metodă **calculArie()**. | ||
| + | |||
| + | Se pune însă problema implementării acestei metode în clasa de bază, deoarece fiecare patrulater concret are un mod propriu de calcul. | ||
| + | Într-o astfel de situație, varianta corectă este ca metoda **calculArie()** să fie declarată **abstractă**, fără implementare. | ||
| + | Implicit, clasa **Patrulater** devine una **abstractă**, deoarece conține o metodă abstractă. | ||
| + | |||
| + | == Observații == | ||
| + | |||
| + | <note important> | ||
| + | O clasă poate fi abstractă chiar dacă **nu conține** nicio metodă abstractă. | ||
| + | </note> | ||
| + | |||
| + | <note important> | ||
| + | Dacă o clasă conține **cel puțin o metodă abstractă**, atunci clasa trebuie **declarată abstractă**; în caz contrar, se semnalează o **eroare la compilare**. | ||
| + | </note> | ||
| + | |||
| + | <note warning> | ||
| + | O subclasă a unei clase abstracte trebuie să **implementeze toate metodele abstracte** ale superclasei sale. | ||
| + | Dacă nu o face, subclasa trebuie, la rândul ei, declarată **abstractă**. | ||
| + | Nu pot fi instanțiate clase care conțin metode neimplementate! | ||
| + | </note> | ||
| + | |||
| + | === Interfețe === | ||
| + | |||
| + | == Introducere == | ||
| + | |||
| + | Interfețele duc conceptul de clasă abstractă cu un pas înainte, prin eliminarea oricăror implementări de metode, punând în practică unul dintre conceptele programării orientate pe obiecte: separarea modelului unui obiect (**interfața**) de implementarea sa. | ||
| + | O interfață poate fi privită ca un protocol de comunicare între obiecte. | ||
| + | |||
| + | == Definiție și comportament impus == | ||
| + | |||
| + | O interfață Java definește un set de metode, dar nu specifică nicio implementare pentru ele. | ||
| + | O clasă care implementează o interfață trebuie, obligatoriu, să specifice implementări pentru **toate** metodele interfeței, supunându-se, așadar, unui anumit comportament. | ||
| + | |||
| + | <note important> | ||
| + | O interfață este o **colecție** de metode fără implementare și **declarații de constante**. | ||
| + | </note> | ||
| + | |||
| + | == Acces și modificatori == | ||
| + | |||
| + | <note tip> | ||
| + | O interfață poate avea un singur modificator de acces, iar acesta este **public**. | ||
| + | O interfață publică este accesibilă tuturor claselor, indiferent de pachetul din care fac parte; în lipsa lui, nivelul implicit de acces este la nivelul pachetului în care se află interfața. | ||
| + | </note> | ||
| + | |||
| + | == Extinderea interfețelor == | ||
| + | |||
| + | O interfață poate extinde oricâte interfețe; acestea se numesc **superinterfețe**. | ||
| + | |||
| + | == Cod sursă Java == | ||
| + | |||
| + | <code java> | ||
| + | interface Inf1 extends Comparable { | ||
| + | public void method1(); | ||
| + | } | ||
| + | |||
| + | interface Inf2 extends Inf1 { | ||
| + | public void method2(); | ||
| + | } | ||
| + | |||
| + | public class Test implements Inf2 { | ||
| + | public void method2() { | ||
| + | // Metoda din interfața Inf2 | ||
| + | } | ||
| + | |||
| + | public void method1() { | ||
| + | // Metoda din interfața Inf1 | ||
| + | } | ||
| + | |||
| + | public int compareTo(Object o) { | ||
| + | // Metoda din interfața Comparable | ||
| + | return 0; | ||
| + | } | ||
| + | } | ||
| + | </code> | ||
| + | |||
| + | === Compararea elementelor === | ||
| + | |||
| + | == Introducere == | ||
| + | |||
| + | Să presupunem că avem o listă, de tip **ArrayList**, cu elemente de tip **Student** și dorim să sortăm elementele din această listă după **media anilor**, presupunând că **Student** este o clasă ce conține printre membrii săi o variabilă ce reține media anilor. | ||
| + | |||
| + | Pentru realizarea acestui lucru există două posibilități, ce vor fi detaliate în continuare, folosind **Comparable** și **Comparator**. | ||
| + | |||
| + | == Interfața Comparable == | ||
| + | |||
| + | Pentru a putea compara direct o instanță a unui tip (clasă definită de utilizator) cu o altă instanță, este necesar ca tipul respectiv să implementeze interfața **Comparable**. | ||
| + | Această interfață conține o singură metodă, care returnează: | ||
| + | * un număr pozitiv – dacă instanța curentă este **mai mare** decât cea primită ca parametru; | ||
| + | * 0 – dacă instanțele sunt **egale**; | ||
| + | * un număr negativ – dacă instanța curentă este **mai mică** decât cea primită ca parametru. | ||
| + | |||
| + | <code java> | ||
| + | class Student implements Comparable { | ||
| + | private String nume; | ||
| + | private double medie; | ||
| + | |||
| + | public Student(String nume, double medie) { | ||
| + | this.nume = nume; | ||
| + | this.medie = medie; | ||
| + | } | ||
| + | |||
| + | @Override | ||
| + | public int compareTo(Object o) { | ||
| + | Student obj = (Student) o; | ||
| + | return (int)(this.medie - obj.medie); | ||
| + | } | ||
| + | |||
| + | public String toString() { | ||
| + | String result = nume + " " + medie; | ||
| + | return result; | ||
| + | } | ||
| + | |||
| + | public static void main(String args[]) { | ||
| + | Vector v = new Vector(); | ||
| + | v.add(new Student("Popescu", 10)); | ||
| + | v.add(new Student("Ionescu", 9.75)); | ||
| + | v.add(new Student("Popa", 9.80)); | ||
| + | Collections.sort(v); | ||
| + | System.out.println(v); | ||
| + | } | ||
| + | } | ||
| + | </code> | ||
| + | |||
| + | == Interfața Comparator == | ||
| + | |||
| + | Interfața **Comparator** oferă o altă modalitate de comparare, separând logica de comparație de clasa comparată. | ||
| + | Aceasta definește metoda **compare(Object o1, Object o2)**, care returnează un număr pozitiv, zero sau negativ în funcție de ordinea dorită între cele două obiecte. | ||
| + | |||
| + | <code java> | ||
| + | class StudentComparator implements Comparator { | ||
| + | @Override | ||
| + | public int compare(Object o1, Object o2) { | ||
| + | Student s1 = (Student) o1; | ||
| + | Student s2 = (Student) o2; | ||
| + | |||
| + | if(s1.getMedie() > s2.getMedie()) { | ||
| + | return 1; | ||
| + | } else if(s1.getMedie() == s2.getMedie()) { | ||
| + | return 0; | ||
| + | } else { | ||
| + | return -1; | ||
| + | } | ||
| + | } | ||
| + | } | ||
| + | |||
| + | class Student { | ||
| + | private String nume; | ||
| + | private double medie; | ||
| + | |||
| + | public Student(String nume, double medie) { | ||
| + | this.nume = nume; | ||
| + | this.medie = medie; | ||
| + | } | ||
| + | |||
| + | public String toString() { | ||
| + | String result = nume + " " + medie; | ||
| + | return result; | ||
| + | } | ||
| + | |||
| + | public double getMedie() { | ||
| + | return this.medie; | ||
| + | } | ||
| + | |||
| + | public static void main(String args[]) { | ||
| + | Vector v = new Vector(); | ||
| + | v.add(new Student("Popescu", 10)); | ||
| + | v.add(new Student("Ionescu", 9.75)); | ||
| + | v.add(new Student("Popa", 9.80)); | ||
| + | Collections.sort(v, new StudentComparator()); | ||
| + | System.out.println(v); | ||
| + | } | ||
| + | } | ||
| + | </code> | ||
| - | <HTML> | ||
| - | <iframe src="https://docs.google.com/file/d/1QdEIAyr8Ts4vwuizEgLORuLdRMB8iOK8/preview" width="640" height="720"></iframe> | ||
| - | | ||
| - | </HTML> | ||