This is an old revision of the document!
Î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.
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ă.
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(); }
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.
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ă.
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.
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.
O interfață poate extinde oricâte interfețe; acestea se numesc superinterfețe.
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; } }
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.
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.
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); } }
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.
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); } }