luni, 2 august 2010

Despre autoboxing

 Începând cu Java 1.5 s-a introdus autoboxing-ul, adică o conversie automată de tip, dintr-o variabilă primitivă, către tipul wrapper corespunzător, sau invers. Folosirea lui este simplă, dacă au fost înțelese bine limitările și riscurile.

package work;
public class Autoboxing {
    public static void main (String [] args){
        //int si Integer raman totusi doua clase diferite:
        System.out.println(int.class);
        System.out.println(Integer.class);
       
        //atentie la overloading!
        metoda(2);
        metoda(Integer.valueOf(2));
        metoda((Integer)3);
       
        Integer i1 = 3, i2 = null;
//compilatorul poate permite "i1 + i2" chiar daca i2 este null
        System.out.println(i1 + i2);
    }  

    public static void metoda(Integer i){
        System.out.println("metoda(Integer i) !");
    }

    public static void metoda(int i){
        System.out.println("metoda(int i) !");
    }
}

miercuri, 21 iulie 2010

Atenție la numele variabilelor

Ce poate provoca mai multă confuzie decât refolosirea unor nume de variabile ? Studiați exemplul următor și vă veți convinge.
/**
 * Ce se afiseaza la consola prin rularea functiei main() ?
 * Explicati ce se intampla la fiecare pas.
 * Ce concluzii trageti?
 */
package work;
class ClasaExterna {
    private int i;
   
    class ClasaInterna1 {       
        ClasaInterna1(int i){   
            i = i;
        }
    }   
    class ClasaInterna2 {
        ClasaInterna2(int j){
            i = j;
        }   
    }   
    class ClasaInterna3 {
        private int i;       
        ClasaInterna3(int k){
            i = k;
            this.i = k;
        }
    }
       
    public int getI(){
        return i;
    }   
}

public class TestClaseInterne1{
    public static void main (String [] args){
        ClasaExterna ce = new ClasaExterna();
        ce.new ClasaInterna1(3);
        System.out.println(ce.getI());

        ce.new ClasaInterna2(4);
        System.out.println(ce.getI());

        ce.new ClasaInterna3(5);
        System.out.println(ce.getI());
    }
}

marți, 20 iulie 2010

Clase locale

Se poate declara o clasă în interiorul unei metode? Dacă da, cum se folosește o astfel de clasă  ?

/**
 * Ce erori apar la compilarea codului urmator ?
 * Ce trebuie modificat pentru a se putea compila?
 */
package work;
public class TestClasaInMetoda {
    private static String str1 = "xyz";
    private String str2 = "123";
    
    public void oMetoda (String str){
        String str3 = "blabla";
        
        class ClasaInMetoda{
            private String str4 = str1;
            private static String str5 = str2;
            private String str6 = str3;
            private String str7 = str;

            ClasaInMetoda(){
                System.out.print(str4+" "+str5+" "+str6+"  "+str7);
            }           
        }
        
        new ClasaInMetoda();
    }
    
    public static void main (String [] args){
        new TestClasaInMetoda().oMetoda("a");
    }
}

luni, 19 iulie 2010

Semnificația lui "protected"

Vă lansez o provocare.  Răspundeți la întrebarea: pentru ce se folosește modificatorul de acces "protected" ? Gândiți-vă la situații unde el este mai oportun decât ceilalți modificatori (public, private sau default). Dacă nu vă descurcați cu răspunsul, sunteți încurajați să consultați documentația oficială sau diverse tutoriale.
După ce ați răspuns și ați găsit exemple, priviți codul următor:

/**
  * Codul de mai jos se compileaza?
 * De ce s-ar putea dori o metoda "protected final" ?
 */
package work;
public class ClasaCuMetoda_ProtectedFinal {
    protected final void metoda(){
        //niste cod
    }
}

vineri, 16 iulie 2010

Regulă încălcată ?

/**
 * Cum de este posibila suprascrierea unei metode finale ?
 * La ce bun o metoda "private final" ? (justificati cu exemplu)
 */
package work;
class ClasaUnu {
    private final void metodaFinala(){
        System.out.println("metodaFinala() din ClasaUnu");
    }  
}

class ClasaDoi extends ClasaUnu {
    public final void metodaFinala(){
        System.out.println("metodaFinala() din ClasaDoi");
    }
}

joi, 15 iulie 2010

Ce poate conține o interfață (2)

/**
 * Ce se poate pune intr-o interfata?
 * (este important sa aveti imaginatie bogata)
 * Cum s-ar putea folosi aceasta "facilitate" de limbaj ?
 */
package work;
public interface InterfataCuprinzatoare{
//mai intai, chestii standard
    int i=5; // implicit, este si "public static final"
    public void metodaBuna(Object... parametri);
//  public static void metStatica(){};//nu metode statice
//  public InterfataCuprinzatoare(){};//nu constructori

//si acum incepem sa improvizam   
    public InterfataCuprinzatoare obiect = null;
    static enum Enum1 {VAL1("valoare 1"), VAL2("valoare 2");
        Enum1 (String nume){
            this.nume = nume;
        }
        private String nume;
        public String toString(){
            return this.nume;
        }
    }   
    enum Enum2 implements InterfataCuprinzatoare{V1, V2, V3;
        public void metodaBuna(Object... parametri) {
            System.out.println(parametri);           
        }
    }   
    static class Cls1{
        private String nume;       
        public Cls1(){
            System.out.println("Un nou obiect Cls1");
        }       
        Cls1(String nume){
            this();
            this.nume = nume;
        }       
    }
    abstract class Cls2{
        abstract double calcul(double d1, double d2);
    }
    final class Cls3{
        static{
            System.out.println("bloc static din clasa finala Cls3 din interfata InterfataCuprinzatoare");
        }
    }   
    class Cls4 extends Cls2 {
        double calcul(double d1, double d2) {
            return d1+d2;
        }
    }   
    class Cls5 implements InterfataCuprinzatoare{
        public void metodaBuna(Object... parametri) {
            //niste cod
        }
    }   
    interface Int1{
        char met1();
    }
    interface Int2 extends InterfataCuprinzatoare{}
   
    //etc...
}

miercuri, 14 iulie 2010

Ce poate conține o interfață (1)

Pentru că astăzi este Ziua Națională a Franței, tema pe care v-o propun nu este foarte complexă, pentru a vă lăsa timp să urmăriți in liniște petrecerea cu focuri de artificii ce va avea loc diseară.

/**
 * De ce credeti ca o interfata nu poate declara metode statice?
 * (aveti mai jos un exemplu)
 */
package work;
interface Interfata{
    public static void metoda1(int i);
}

marți, 13 iulie 2010

Extinderea interfețelor

In lumea claselor Java nu există moștenire multipla. Orice clasă are exact un singur părinte direct (exceptând clasa Object, aflată în vârful ierarhiei). Oare la fel stau lucrurile și in cazul interfețelor ? Veți afla în doar câteva momente.
/**
 * Studiati codul de mai jos.
 * Cum este posibil sa existe "mostenire multipla" si "mostenire
 * redundanta" ?
 * Cum este posibil sa se suprascrie o variabila finala ?
 * De ce nu se compileaza clasa TestMostenireInterfete2 ?
 * Ce ati putea schimba pentru a permite compilarea ei ?
 */
package work;
interface I1{
    public static final String s = "i1";
    public void met1();
}
interface I2{
    public void met1();
    public void met2();
}
interface I3 extends I1, I2{
    public static final String s = "i3";//suprascriere camp final ?!

    public void met1(); //suprascriere ?
    public void met1(String s); //supraincarcare ?
    public void met3();
}
interface I4 extends I1, I2, I3{} //asta le intrece pe toate !

class TestMostenireInterfete1 implements I3 {
    public void met1() {
        System.out.println(s);
    }
    public void met1(String s) {}
    public void met3() {}
    public void met2() {}
}

class TestMostenireInterfete2 implements I1, I3 {
    public void met1() {
        System.out.println(s);
    }
    public void met1(String s) {}
    public void met3() {}
    public void met2() {}
}

luni, 12 iulie 2010

Din capcanele polimorfismului (3)

Când vorbim despre polimorfism in Java, de obicei ne referim la metode. Oare lucrurile se petrec la fel și in cazul variabilelor ? Putem vorbi de overriding, sau de dynamic binding ? (overloading-ul variabilelor nu poate exista, puteți verifica simplu de tot).

/**
 * Analizati codul din Clasa1 si Clasa2. Ce observati la
 * variabilele i3 si i5 ?
 * Rulati metoda Polimorfism3.main(). Retineti si interpretati
 * afisajul din consola.
 * Incercati sa decomentati ultimele linii din main(). Ce eroare
 * ar aparea ? De ce ?
 * Decomentati metodele din Clasa2 (exceptand getI5() care
 * genereaza eroare de  compilare) si rulati din nou main().
 * Comparati rezultatele cu rularea anterioara.
 * Concluzie: exista overriding si dynamic binding in cazul
 * variabilelor statice si nestatice ?
*/
package test;
import work.Clasa1;
import work.Clasa2;
public class Polimorfism3 {
    public static void main (String [] args){
        Clasa1 a = new Clasa2();//referinta Clasa1, obiect Clasa2
        System.out.println(a.getI1()+" "+a.getI2()+" "+ a.getI3()
                           +" "+a.i3+" "+a.getI4()+" "+a.i4);
        test1(a); test2(a);      
        Clasa2 b = new Clasa2();//referinta Clasa2, obiect Clasa2
        test1(b); test2(b);
//      System.out.println(b.getI1()+" "+b.getI2()+" "+ b.getI3()
//                         +" "+b.i3+" "+b.getI4()+" "+b.i4);
    }
   
    public static void test1(Clasa1 obj){
        System.out.println(obj.i5);
    }
    public static void test2(Clasa1 obj){
        System.out.println(obj.getI5());
    }
}

package work;
public class Clasa1 {
    private static int i1 = 1;
    private int i2 = 2;
    public static int i3 = 3;    //vizibilitate maxima ("public")
    public int i4 = 4;
    public int i5 = 5;           //tip: int
   
    public int getI1(){
        return i1;
    }
    public int getI2(){
        return i2;
    }
    public int getI3(){
        return i3;
    }
    public int getI4(){
        return i4;
    }
    public int getI5(){
        return i5;
    }
}

package work;
public class Clasa2 extends Clasa1 {
  //definim variabile cu acelasi nume ca cele din Clasa1:
    private static int i1 = 6;
    private int i2 = 7;
    int i3 = 8; //nu mai este nici public nici static !
    public int i4 = 9;
    public String i5 = "string: 10"; //schimbare de tip !

//  public int getI1(){
//      return i1;
//  }
//  public int getI2(){
//      return i2;
//  }
//  public int getI3(){
//      return i3;
//  }
//  public int getI4(){
//      return i4;
//  }
//  public String getI5(){
//      return i5;
//  }
}

vineri, 9 iulie 2010

Din capcanele polimorfismului (2)

/**
 * Scurta demonstratie despre folosirea operatorului "instanceof"
 * De ce penultima linie nu se compileaza? dar ultima de ce se
 * compileaza ?
 * Ce se afiseaza la consola cand rulati main()? (dupa stergerea
 * sau comentarea liniei cu eroare)
 */
public class Polimorfism {
    public static void main (String [] args){
        ClasaC obiectC = new ClasaC();
        Object ob = new Object();
        System.out.println(obiectC instanceof ClasaA);
        System.out.println(obiectC instanceof ClasaB);
        System.out.println(obiectC instanceof ClasaC);
        System.out.println(obiectC instanceof Object);
        System.out.println(obiectC instanceof InterfataA);
        System.out.println(obiectC instanceof InterfataB);
//linia urmatoare nu se compileaza:
        System.out.println(obiectC instanceof Polimorfism); 
// dar linia de mai jos se compileaza !?
        System.out.println(ob instanceof Polimorfism);    
    }
}

class ClasaA{}

class ClasaB extends ClasaA {}

interface InterfataA {}

interface InterfataB extends InterfataA {}

class ClasaC extends ClasaB implements InterfataB {}
 

joi, 8 iulie 2010

Din capcanele polimorfismului (1)

Cuvântul "polimorfism" provine din limba greacă și înseamnă "având mai multe forme". In limbajul Java, polimorfismul are 3 aspecte: supraîncărcare (overloading), suprascriere (overriding) și legare dinamică (dynamic binding). Deoarece acest blog nu se vrea a fi un curs teoretic, definițiile celor 3 aspecte le puteți citi direct din documentația Sun. Subliniez totuși faptul ca cele trei tipuri de polimorfism nu pot fi complet separate, adesea întâlnindu-se toate 3 laolaltă. In continuare vă prezint un exemplu care ilustrează două caracteristici importante ale suprascrierii (dar pentru a răspunde la întrebări, e necesar să înțelegeți și legarea dinamică - exact ce spuneam mai sus despre interdependența aspectelor).

/**
 * De ce nu se compileaza metoda1 si metoda2 din clasa Clasa02 ?
 * (la metoda2(), nu clasa anonima new Object(){... e problema)
 * Ce probleme ar putea aparea daca limbajul Java ar permite 
 * compilarea codului respectiv ? 
 * Scrieti un program care sa justifice raspunsul la ultima
 * intrebare.
 *  (indiciu: folositi polimorfism de tip dynamic binding)
 */
class Clasa01 {
    public int metoda1(int i1, int i2, boolean b){
        if (b){
            return i1 * i2;
        }else{
            return i1 - i2;
        }
    }  
    protected String metoda2(String s){
        return s + " etc";
    }
}

class Clasa02 extends Clasa01 {
    int metoda1(int a, int b, boolean c){
        return (1 + super.metoda1(a, b, c));
    }   
    public Object metoda2(String s){
        final String str = s;
        return new Object(){
            public String toString(){
                return str;
            }
        };
    }  
}

Întârzierea implementării

In general, o clasă care implementează o interfață trebuie să concretizeze toate metodele interfeței. Există o excepție, prezentată in exemplul de mai jos.

/**
 * De ce nu se compileaza programul urmator?

 * Adaugati codul necesar pentru ca programul sa se compileze.
 * Nu aveti voie sa modificati tipul claselor.
 * (indiciu: exista doua solutii posibile; care dintre ele 
 * credeti ca este mai buna, si de ce ? )
*/
interface Interfata {
    public void metodaOarecare(Object... argumente);
}

abstract class ClasaAbstracta implements Interfata {
    // se poate adauga cod aici
}

class ClasaConcreta extends ClasaAbstracta {
    // se poate adauga cod aici
}

miercuri, 7 iulie 2010

Conflict de interfețe

Dezvoltarea programelor Java este însoțită uneori de surprize neplăcute. Iată mai jos un exemplu: (se presupune că cele 2 interfețe deja există și nu pot fi modificate, iar noi vrem să scriem o clasă care le implementează pe amândouă).

/**
 * Puteti face clasa de mai jos sa se compileze?
 *  (aveti voie sa adaugati cod, dar nu sa modificati codul deja
 *   existent)
 */
public class ConflictDeInterfete implements Interfata1, Interfata2{
    // ce trebuie scris aici ?
}

interface Interfata1 {
    public void metoda1(String arg1);
}

interface Interfata2 {
    public int metoda1(String arg1);
    public long metoda2(int arg1, int arg2);   
}

Restricție la extinderea claselor

Toată lumea știe că o clasă având modificatorul final nu poate fi extinsă. De asemenea, o clasă având toți constructorii private nu poate fi nici ea extinsă. Dar oare acestea sunt singurele cazuri posibile ?

/**
 * De ce nu compileaza codul de mai jos?
 * Ce probleme ar putea aparea daca limbajul Java ar permite
 * compilarea acestui cod? 
 */
class Clasa1 extends Clasa3{
}

class Clasa2 extends Clasa1{
}

class Clasa3 extends Clasa2{
}

marți, 6 iulie 2010

Tot despre constructori (2)

Dacă am exemplificat funcționarea apelului super(), nu putem să trecem cu vederea apelul sau "geamăn": this().

/**
 * Copiati programul de mai jos in editor si rulati-l.
 * Deci cum functioneaza instructiunea this() ?
 * Decomentati apelul new Clasa002(); si rulati din nou. 

 * Ce se intampla si de ce ?
 * Decomentati instructiunea this(); din constructorul

 * Clasa002(). Ce eroare apare ?
 */
public class TestThisInConstructori {
    public static void main (String [] args){
        new Clasa001();
        System.out.println("----");
        new Clasa001("un id");
        System.out.println("----");
//        new Clasa002();
    }
}
class Clasa001 {
    private String id;
   
    Clasa001(){
        this (null);
        System.out.println("Clasa001: constructor fara parametri");
    }
    Clasa001(String str){
        System.out.println("Clasa001: constructor cu parametru String: " + str);
        this.id = str;
    }
}
class Clasa002 {
    Clasa002(){
//        this();
        new Clasa002();
    }
}

Tot despre constructori


In continuarea exercițiului anterior, iată încă un exemplu pentru a înțelege mai bine funcționarea constructorilor in conjuncție cu extinderea claselor.
 
/**
 * Creati fisierul TestSuperInConstructori.java si copiati codul
 * de mai jos.
 * Ce se intampl
a cand incercati sa compilati ?
 * Stergeti linia cu eroare. Rulati programul.
 * Ce se afiseaza in consol
a ?
 * Decomentati linia "//super();" si rulati iar. Ce se schimb
a?
 * Inlocuiti super(); cu super("blablabla"); si rulati iar. Ce se

 *
schimba ?
 * Ce se schimba daca inlocuiti super(); cu new Parinte(); ?
 */
public class TestSuperInConstructori {
    public static void main (String [] args){
        new Copil();
        System.out.println("-------");
        new Copil(2);
    }
}
class Parinte {
    Parinte(){
        System.out.println("constructor Parinte()");
    }
    Parinte(String s){
        System.out.println("constructor Parinte(" + s + ")");
    }
}
class Copil extends Parinte{
    Copil(){
        System.out.println("constructor Copil()");
          super("abc");
    }
    Copil(int i){
//        super();       
        System.out.println("constructor Copil(" + i + ")");
    }
}

De ce un blog cu Java ?

- Fiindcă este un limbaj de programare foarte larg răspândit, se bucură de o comunitate extrem de numeroasă și de activă, dar in limba română nu există foarte multe site-uri cu tutoriale Java.
- Fiindcă vreau să împărtășesc o parte din experiența mea (nu foarte bogată, dar în continuă creștere) cu cei interesați de limbajul/tehnologia Java. Postările mele vor avea, cel mai adesea, caracterul de "temă de gândire", cu răspuns destul de evident, dar nu "mură in gură".
- Fiindcă, deși exista o sumedenie de biblioteci, framework-uri, plugin-uri (de la Sun, sau third-party), un programator nu are nevoie doar de tool-uri complexe, ci și de o bună înțelegere a limbajului, cu capcanele, punctele forte și slăbiciunile lui.

Așa cum probabil ați ghicit deja, acest blog va pune accent pe fundamentele limbajului Java. El se adresează celor care fac acum - sau au făcut deja - primii pași in Java, fără a se considera încă experți.
Iată deci o primă tema de gândire:

/**
* Se compileaza codul de mai jos?

* Dar daca inlocuiti "Copil()" cu "Copil(int i)" ?

* Care este explicatia?

*/

class Parinte {
    Parinte(int i){    //constructor cu parametri
        
//niste cod
    }
}
class Copil extends Parinte{
    Copil(){         
//constructor fara parametri
        //niste cod

    }

}