Tutorial Java SCJP – #16 Constructori

Intr-o clasa se pot defini metode, dar exista un tip special de metode care sunt folosite pentru a rezolva o anumita problema, aceea de a construi obiecte. Constructori sunt metode speciale datorita rolului lor si pentru ca au o multime reguli privind declararea si utilizare.

 

Acest topic face parte dintr-un tutorial Java 6 SCJP accesibil prin Tutorial Java 6 – Continut.

De fiecare data cand este creat un obiect, este apelat un constructor. Pornind de la aceasta certitudine, în Java, fiecare clasa are cel putin un constructor , chiar daca programatorul nu a declarat în mod explicit unul.

Rolurile functiei constructor sunt:

  • Rolul principal – pentru a construi obiecte, in sensul de a aloca spatiu în Heap;
  • Rol secundar [optional] – pentru a initializa variabilele de instanta (atribute) cu valori default (amintiti-va, ca variabilele de instanta primesc valoarea implicita a tipului lor atunci cand obiectul este creat) sau cu valori date;

Avand în vedere clasa Carte si metoda main():

public class Carte {
    float pret;
    String titlu;
    String autor;

    public static void main(String[] args)
    {
        //construieste un obiect de tip Carte
        Carte c1 = new Carte();
    }
}

este clar ca in metoda main() este construit un obiect de tip Carte, ce este gestionat de referinta c1.

In aceasta situatie, unde este constructorul ? O regula în ceea ce priveste constructorii afirma ca, compilatorul va oferi un constructor implicit (unul cu zero argumente) daca nu exista declarati in mod explicit alti constructori. Forma constructorului implicit, generat de compilator, este:

    public Carte()
    {
        
    }

Reguli pentru a declara si apela constructori in Java

  • constructorii au acelasi nume (case-sensitive), ca si clasa parinte;
  • constructori nu au un tip de return (este logic, deoarece vor intoarce intotdeauna o referinta catre obiectul construit); ATENTIE pot fi definite metode cu acelasi nume ca si clasa, dar cu un tip de return care sunt metode comune si NU constructori:
public class Carte {
	//NU este un constructor - are tip returnat
    public void Carte(){
        System.out.println("O metoda simpla fara logica !");
    }
    public static void main(String[] args)
    {
        //construieste un obiect de tip Carte cu constructorul default
        Carte b1 = new Carte();
        b1.Carte();	//apel metoda simpla - NU constructor
    }
}
    //constructor fara argumente
    public Carte(){
        pret = 100;
        titlu = "Nimic";
    }
    //constructor cu 3 argumente
    public Carte(float Pret, String Titlu, String Autor){
        pret = Pret;
        titlu = Titlu;
        autor= Autor;
    }
    //constructor cu 2 argumente
    public Carte(String Titlu, String Autor){
        pret = 0;      //valoare default
        titlu = Titlu;
        autor= Autor;
    }
    //constructor cu numar variabil de argumente - var-args
    public Carte(float Pret, String ... nisteStrings){
        //procesare date
    }
  • constructorul implicit este unul cu zero-argumente;
  • daca nu se scrie ORICE tip de constructor, compilatorul va genera forma implicita;
  • daca se defineste cel putin un constructor (nu conteaza argumentele sale), compilatorul NU va genera forma implicita;
  • daca se defineste cel putin un constructor (cu parametri) si este nevoie de cel implicit, acesta trebuie definit in mod explicit; in caz contrar se obtine o eroare de compilare atunci cand aecsta este apelat:
public class Carte {
    float pret;
    String titlu;
    String autor;

    //constructor cu 2 argumente 
    public Carte(String Titlu, String Autor){
        pret = 0;      //valoare default
        titlu = Titlu;
        autor = Autor;
    }
    public static void main(String[] args){
        //construieste o Carte
		
		//cannot find symbol : constructor Carte()
        Carte b1 = new Carte();  //eroare compilare
                                
    }

}
    
public Carte(float Pret, String titlu, String Autor){
        this.pret = Pret;     //this este optional
        this.titlu = titlu;   //TREBUIE folosit this
        autor = Autor;            
    }
  • prima declaratie intr-un constructor este un apel la un alt constructor folosind this(), sau pentru un constructor din superclasa (clasa de baza daca aceasta este o subclasa) folosind super() (mai mult pe acest subiect, in articolul despre mostenire); daca nu utilizati nici this() sau super() , compilatorul va face implicit apelul catre super(), pentur a intelege cine este super(), trebuie sa cunoasteti conceptul de mostenire (in articolele urmatoare din acest tutorial):
    //constructor cu 2 argumente
    public Carte(String Titlu, String Autor){
	
	    //generat de compilator daca nu este apelat explicit
		
		//super();	
		
		//in acest exemplu apeleaza constructorul clasei Object
		//in Java, toate clasele sunt derivate implicit din Object
        
		pret = 0;      //valoare default
        titlu = Titlu;
        autor = Autor;
    }

    //constructor cu 3 argumente
    public Carte(float Pret, String Titlu, String Autor){
        //apel explicit al constructorului cu 2 argumente
        //TREBUIE sa fie prima instructiune
		//fara el, compilatorul apeleaza super();
							   
		this(Titlu,Autor);     
				
        pret = Pret;
    }
  • un constructor este apelat cu operatorul new sau folosind this() intr-un alt constructor; nu este permis apelul constructorilor folosind sintaxa aferenta pentru orice alta metoda:
        
		Carte myCarte = new Carte(23,"Dune","Frank Herbert");  //ok
        
        Carte(23,"Dune","Frank Herbert");         //eroare compilare
        myCarte.Carte(23,"Dune","Frank Herbert"); //eroare compilare
  • cand se apeleaza alti constructori cu this() evitati apeluri incrucisate (cross-calls) care pot genera recursivitate infinita si exceptie la executie de tip StackOverflowError (unele compilatoare pot identifica problema si pot genera o eroare de tip recursive constructor invocation): 
    
	public Carte(String Titlu, String Autor){
        this(0,Titlu,Autor);      //apeleaza constructorul cu 3 argumente
    }
    //constructor cu 3 argumente
    public Carte(float Pret, String Titlu, String Autor){
        this(Titlu,Autor);     //apeleaza constructorul cu 2 argumente
                               //TREBUIE sa fie prima instructiune
        pret = Pret;
    }
  • constructori au acces la metode si variabile statice – definite cu static;
  • clasele abstracte pot avea constructori;
  • atunci cand se supraincarca constructori (metode de definire cu acelasi nume, dar cu liste diferite de parametri), trebuie definiti cu liste diferite de parametri (ca numar sau ca tip);

 

Lucruri importante pentru examenul SCJP:

 

  • toate regulile de mai sus;
  • ATENTIE la shadowing atunci cand se utilizeaza constructori cu argumente (a se vedea Tutorial Java SCJP – #14.1 Ce inseamna sa ascunzi (shadow) o variabila);
  • ATENTIE la metodele simple (nicio logica sa faci asta, insa testul verifica acest lucru), care au tip returnat si care arata ca un constructor; acestea sunt doar metode comune si NU constructori (semn distinctiv este ca au un tip returnat); in Java este posibil sa se defineasca metode simple cu nume identic cu al clasei;
  • dupa ce ati inteles conceptul de mostenire si ierarhii de clase, ATENTIE la inlantuirea constructorilor – constructor chaining;

Un exemplu de intrebare specifica testului SCJP. Pentru secventa de cod urmatoare:

public class Carte {
    float pret;
    String titlu;
    String autor;

    public void Carte(){
        pret = 100;
        titlu = "Nimic";
        autor = "Anonim";
    }

    public Carte(String Titlu, String Autor){
        this();
        pret = 0;      //valoare default
        titlu = Titlu;
        autor = Autor;
    }

    public static void main(String[] args){
        Carte primaCarte = new Carte("Dune","Frank Herbert");
        Carte altaCarte = new Carte();
    }

}

vedeti probleme ?

Pune raspunsul tau in comentarii.

Acest topic face parte dintr-un tutorial Java 6 SCJP accesibil prin Tutorial Java 6 – Continut.