vineri, 22 martie 2024

Interfețe în limbajul Java

 

O interfață  este o colecție de metode și date membre publice. Metodele într-o interfață sunt abstracte, adică este prezentă doar semnătura metodelor, implementarea acestora fiind realizată de clasa care va folosi interfață dată.

Sintaxa:

[public] interface NumeInterfata

                    [extends ListaInterfete]

{

     // declarații de membri de interfață

}

De exemplu:

interface Animal {
    void maninca();
    void doarme();
}

Reguli de lucru cu interfețele în Java

  1. Numele interfeței nu coincide cu numele altei clase sau interfeţe din acelaşi pachet.
  2. Dacă declarația unei interfeţe conţine clauza extends atunci interfața va moșteni toate metodele şi constantele interfețelor enumerate în <ListaInterfete>, care se numesc superinterfeţe.
  3. Nu există o superinterfaţă generală cum este clasa Object pentru superclase.
  4. Corpul unei metode într-o interfață este ;, dar începând cu Java 8, în interfață pot fi metode static și default.
  5. Toți membri interfeței sunt considerați implicit public, dar dacă modificatorul public este specificat atunci sunt accesibili şi înafara pachetului.
  6. Deoarece variabilele unei interfeţe sunt considerate constante acestea trebuie să fie inițializate altfel se va produce eroare de compilare.
  7. Metode cu aceeași semnătură, dar tip de return diferit nu pot fi folosite în interfeţe.
  8. Variabilele unei interfeţe sunt considerate implicit public, static şi final. Chiar dacă veți omite aceste cuvinte rezervate vor fi adăugate în mod automat de compilatorul Java la faza de compilare, în fișierul *.class.
  9. E posibil ca o clasă să folosească variabilele cu același nume dintr-o altă interfață, în acest caz la accesarea acestora trebuie de respectat sintaxa:  numeInterfata.numeVariabila
  10. La declararea unei metode nu este permisă apariția tuturor modificatorilor de acces, doar public sau abstract.
  11. Dacă o clasă implementează 2 interfețe ce au metodă cu același nume este de ajuns să implementăm o singură metodă.
  12. Nu este binevenit de a folosi metode cu același nume într-o interfață sau mai multe interfeţe să conțină metode cu acelaşi nume.
  13. Interfețele nu au câmpuri și nici constructori. Nu pot fi insanțiate, și nu pot păstra starea obiectelor.

Pentru ca o clasă să implementeze o interfață trebuie să respecte sintaxa :

class numeClasa implements Interfata1,...,InterfataN { ...

}

De exemplu:

class Cal implements Animal{
    void manica(){...}
    void doarme(){...}
}

O clasă poate implementa orice număr de interfețe. Clasa ce implementează interfața trebuie obligatoriu să conțină cod pentru toate metodele interfeței, din acest motiv o interfață implementată într-o clasă nu trebuie modificată, dacă modificăm interfața obligatoriu modificăm şi codul sursă al clasei ce o implementează.
interface A {
// membrii interfeței A
}

interface B {
// membrii interfeței B
}

class C implements A, B {
// implementarea metodelor abstracte din A
// implementarea metodelor abstracte din B
}

O interfață poate extinde altă interfață:

interface A {
// membrii interfeței A
}
interface B extends A {
// membrii interfeței B
}
class C implements B {
// implementarea metodelor abstracte din A
// implementarea metodelor abstracte din B
}

Chiar poate extinde mai multe interfețe: 

interface A {
// membrii interfeței A
}
interface B {
// membrii interfeței B
}
interface C extends A, B {
// membrii interfeței C
}
class D implements C {
// implementarea metodelor abstracte din A
// implementarea metodelor abstracte din B
// implementarea metodelor abstracte din C
}


Clasa ce implementează o interfață poate avea şi metode specifice ei, nu doar metodele interfeței.
O interfață poate extinde o altă interfață, dar nu o poate implementa.

Rețineți! 

Exemplul_1: 

interface Poligon {

    void getAria(int ... laturi);

}

class Dreptunghi implements Poligon {

 public void getAria(int ... laturi) {

 if (laturi.length==2)

  System.out.println("Aria dreptunghiului este " + (laturi[0] * laturi[1]));

}}

class Patrat implements Poligon {

 public void getAria(int ... laturi) {

  if (laturi.length==1) System.out.println("Aria patratului este "+(Math.pow(laturi[0], 2)));

}

}

class Main {

    public static void main(String[] args) {

    Dreptunghi r1 = new Dreptunghi ();

      r1.getAria(5, 6);

      Patrat p1 = new Patrat();

      p1.getAria(5);

    }

}

În Java nu poate fi implementată moștenirea multiplă la nivel de stare, dar interfețele permit realizarea moștenirii multiple la nivel de comportament. 

Exemplul_2: 

interface Masina{

  int  viteza=90;

  public void distanta();

}

interface Autobus{

  int distanta=100;

  public void viteza();

}

class Vehicul  implements Masina,Autobus {

  public void distanta(){

   int  distanta=viteza*100;

   System.out.println("Distanta parcursa este "+distanta);

  }

  public void viteza(){

   int viteza=distanta/100;

   System.out.println("Viteza = "+viteza);

   }

}

class DemoVehicule{

 public static void main(String args[]){

  System.out.println("Vehicul");

  Vehicul v1=new Vehicul();

  v1.distanta();

  v1.viteza();

}}


Exemplu: 

interface Interfata_1{ public void metoda_1();

}

interface Interfata_2 extends Interfata_1 { public void metoda_2();

}

class DemoInterfete implements Interfata_2{

    public void metoda_1(){

     System.out.println("Aici metoda 1");

    }

    public void metoda_2(){

     System.out.println("Aici metoda 2");

    }

    public static void main(String args[]){

    DemoInterfete obj = new DemoInterfete();

     obj.metoda_2();

    }}

Notă! Interfețele nu pot fi instanțiate însă putem crea variabile referință de tip interfață. De exemplu, dacă în metoda main() în exemplul de mai sus vom folosi construcția:

public static void main(String args[]){

    Interfata_2 obj = new DemoInterfete();

     obj.metoda_2();

}

Aceasta este validă, iar programul va afișa același rezultat. Vor putea fi apelate pentru obiectul obj acele metode din Interfata_2 care au implementare în clasa dată. Variabilele referință de tip interfață se folosesc doar urmate de instanţierea clasei ce implementează interfața la care face referință variabila. 

Pentru a distinge corect între utilizarea claselor abstracte sau interfețe luați în considerare următoarele aspecte:

  1. Dacă aveți nevoie să descrieți doar comportamentul obiectelor, nu și starea acestora utilizați interfețe. În caz contrar clase abstracte, deoarece clasele abstracte includ atât starea cât și comportamentul obiectelor. O interfață descrie doar comportamentul.
  2. Dacă aveți nevoie să specificați un comportament comun pentru mai multe clase care fac parte din ierarhii diferite utilizați interfețe. De exemplu clasele Om și Masina, nu au nimic comun, fac parte din ierarhii diferite, dar au comun faptul că se deplasează: omul cu picioarele, iar mașina cu ajutorul componentelor tehnice.  Deci, o clasă abstractă conectează clase care sunt foarte strâns legate. În timp ce interfața poate fi implementată de clase care nu au absolut nimic în comun.
  3. Java suportă moștenirea de stare, la nivel de clasă, și moștenire de comportament, la nivel de interfață. Clasele pot implementa orice număr de interfețe, dar pot moșteni o singură clasă. Deci dacă doriți să implementați moștenirea de stare, unde o clasă derivată (subclasă) primește atât comportamentul (metodele) cât și starea (atributele) din clasa de bază (superclasă), utilizați clase sau clase abstracte. Dar dacă doriți să specificați un contract sau specificații de comportament, fără a furniza o implementare implicită atunci utilizați interfețele.  

👌 Analizează și discută!  
  1. Explicați conceptul de interfață în Java și modul în care este utilizată pentru a defini comportamente standard și contracte pentru clasele care o implementează.
  2. Comparați clasele abstracte și interfețele în ceea ce privește caracteristicile, utilizările și restricțiile lor în Java.
  3. Argumentați beneficiile și avantajele utilizării interfețelor în comparație cu clasele abstracte în diverse scenarii de proiectare și dezvoltare a software-ului.
  4. Care este diferența între o interfață și o clasă abstractă în ceea ce privește implementarea metodelor? 



Vă doresc o zi deosebit de frumoasă! ❤️

miercuri, 18 septembrie 2019

Prelucrarea tablourilor în Java

Dacă răsfoiți această postare înseamnă că doriți să studiați care este modalitatea de lucru cu masivele în Java. Vă doresc succes și sper că această postare o să vă fie utilă! 

Ce sunt vectorii?
Un vector, tablou sau array reprezintă un container pentru un număr de elemente de același tip, fiecare element fiind indexat de un număr. În limbajul Java vectorii sunt obiecte, tipul acestora fiind referință.
Vectorii sunt de 2 tipuri:
ü  cu lungime fixă – dimensiunea  vectorului este stabilită la crearea acestuia și nu poate fi modificată ulterior. Pentru ei nu există o clasă care se instanţiază  pentru a obține un obiect vector.
ü  cu lungime variabilă – dimensiunea vectorului poate fi modificată pe parcursul rulării programului. Pentru ei există clase Java predefinite ce pot fi instanțiate (de ex.  java.util.Vector, java.util.Arrays, ș.a).
Iată structura unui vector:

După cum observați în figura de mai sus, fiecărui element dintr-un vector îi corespunde un index numeric, cu ajutorul căruia poate fi accesat. Numerotarea elementelor începe întotdeauna de la 0, ceea ce înseamnă că, de exemplu, cel de-al nouălea element va fi accesat de indexul 8.

Cum se folosesc vectorii?
Pentru a folosi un vector este necesar să:
1    .  declarați o variabilă de tip vector care permite referirea la un obiect vector;
2    .  construiți obiectul vector specificându-i dimensiunea, adică numărul de elemente ce îl poate stoca;
3    .  accesați elementele vectorului cu ajutorul variabilei de tip vector cu scopul de a le atribui valori sau a obține valorile acestora.

Cum se declară variabila de tip vector?
Variabila de tip vector se declară în felul următor:       tip [] nume;
unde 
-        tip indică tipul de date al elementelor conținute de vector;
-        parantezele pătrate sunt simboluri speciale ce indică ca variabila respectivă este un vector;
-        nume  fiind identificatorul variabilei vectorului;
Ca şi în cazul altor tipuri de variabile, declararea nu creează de fapt un vector, dar pur şi simplu anunță compilatorul că variabila respectivă va deține un vector de tipul specificat. Deci, la această etapă vectorul nu poate fi utilizat.
Exemple:
          byte[] anArrayOfBytes;
short[] anArrayOfShorts;
double[] anArrayOfDoubles;
boolean[] anArrayOfBooleans;
char[] anArrayOfChars;
String[] anArrayOfStrings;
Cum se crează un vector?
Un vector poate fi creat utilizând operatorul new printr-o construcție de forma:

new tip_vector [dimensiune]; 
unde, tip_vector reprezintă tipul elementelor stocate în vector, iar dimensiune este o expresie de tip întreg pozitivă ce semnifică numărul de elemente ce se vor stoca în vector.
Întreaga construcție va crea un vector de tip tip_vector cu o dimensiune de dimensiune elemente indexate de la 0 la dimensiune-1.
Dacă această instrucțiune ar lipsi, compilatorul ar afișa o eroare asemănătoare celei mai jos și execuția programului ar eșua:    Variable anArray may not have been initialized.
De exemplu:
int [] a;             // se declară variabila a ce conţine referință către un vector cu elemente întregi
a = new int[5];     // se crează un vector cu 5 elemente întregi de același tip cu variabila a 
Cum accesăm elementele unui vector?
Fiecare element distinct din vector poate fi accesat ca o variabilă separată printr-o construcție de forma:
nume [index]
unde nume reprezintă numele vectorului ce stochează elementele, iar index este o expresie de tip întreg strict pozitivă ce semnifică poziția elementului care doriți să îl accesați din vectorul dat. Dacă vectorul conține n elemente atunci index trebuie să fie cuprins în intervalul  [0, n-1], în caz contrar o excepție de execuție va fi semnalată.
De exemplu:
int [] a;                // se declară variabila a ce conţine referință către un vector cu elemente întregi
a = new int[5];     // se crează un vector cu 5 elemente întregi de același tip cu variabila a
a[0] = 23;               // primului element din vector i se atribuie valoarea 23
a[4] = 10;             // ultimului element din vector i se atribuie valoarea 10
a[5] = 9;              // excepție generată! Indexul nu se află în diapazonul [0,4]
Alternativ, poate fi creat și inițializat un vector în felul următor:
int[] anArray = {100, 200, 300, 400, 500, 600, 700, 800, 900, 1000};
În acest caz, lungimea vectorului este determinată de numărul de valori furnizate între acolade.

Cum se determină dimensiunea unui vector ?
Fiecare vector conține, pe lîngă elemente, o variabilă de instanță publică ce nu poate fi modificată numită length ce stochează numărul de elemente în vector. Prin urmare accesând această variabilă putem obține lungimea unui vector.
Exemplu:
double[] v;
v = new double[5];
System.out.println(v.length);      // se va afișa valoarea 5

Ce este o matrice?
O matrice este o colecție de elemente de același tip, organizate în formă de tabel în care fiecare element este indexat de o pereche de numere ce identifică numărul de rând și numărul de coloană la intersecția cărora se află elementul.
În Java o matrice este formată din mai mulți vectori fiecare reprezentând cîte un rând din matrice și mai este numită vector de vectori.

Cum se declară o matrice?
O matrice se declară în felul următor (asemănător ca la vectori):
int[][] m; // declarația unui vector de vectori

Cum se crează o matrice?
Înainte de a folosi o matrice aceasta trebuie creată, la fel ca vectorii. De exemplu, următoarele doua secvențe de creare a unei matrici sunt echivalente:
m = new int[3][]; //se crează un vector ce va conține 3 elemente, fiecare conținând
                                           // cîte o referință la un rând din matrice.
m[0] = new int[5]; // se crează un rândul 0 din matrice (5 coloane)
m[1] = new int[5]; // se crează un rândul 1 din matrice (5 coloane)
m[2] = new int[5]; // se crează un rândul 2 din matrice (5 coloane)

                                                                                    <=>                                  
m = new int [3][5];
Rețineți faptul că, dacă utilizați cea dea doua modalitate forțați toate rândurile să conțină 5 coloane, pe când folosind prima modalitate rândurile pot avea număr de coloane diferit.
Observați în exemplul următor: 
Cum se accesează elementele unei matrici?
Pentru a accesa un element este necesar de a specifica indicele de rând și coloană la intersecția căruia se află elementul folosind construcția:

variabila_matrice[indice_rînd][indice_coloană]
Exemplu:
int[][] m = new int [3][5];
m[1][2] = 39; // se atribuie elementului din rândul 1 coloana 2 valoarea 39
m[0][0] = 44;  // se atribuie elementului din rândul 0 coloana 0 valoarea 44
System.out.println(m[1][2]); // se accesează elementul din rândul 1 coloana 2, se afișează 39

Cum depistați dimensiunea unei matrici?
Folosind variabila length,  aveți posibilitatea de a obține numărul de rânduri și coloane a matricei. Fie ca m este o referință către o matrice, atunci:
  ü  m.length denotă numărul de rânduri
  ü  m[i].length denotă numărul de coloane a rândului i din matricea m.
Rețineți faptul că, dacă toate rândurile au același număr de coloane puteți folosi expresia m[i].length.
De exemplu:
double[][] v;
v = new double[15][20];
System.out.println(v.length); // afișează 15
System.out.println(v[0].length); // afișează 20

Cum parcurgem elementele unei matrici?

public class Parcurgere {
 public static void main(String[] args) {
  int [][] m = new int[2][2];
   m[0][0] = 2; m[0][1] = 4;
   m[1][0] = 3; m[1][1] = 5;
  for (int i = 0; i < m.length; i++) {
   for (int j = 0; j < m[0].length; j++)
      System.out.print(m[i][j] + " "); 
  System.out.println();
  }
}}

public class parcurgere1 {
 public static void main(String[] args) {
  int [][] m = { {2,4},
                  {3,5} };
  for (int i = 0; i < m.length; i++) {
   for (int j = 0; j < m[0].length; j++)
      System.out.print(m[i][j] + " "); 
  System.out.println();
  }}}