Dobrý den,
chyba se stack overflow je celkem jasná, protože donekonečna vyrábíte nové zaměstnance a na nich voláte getNarozeni(), časem dojde prostor pro zásobník... Obecně se na tento problém doporučuje vracet kopii objektu, pokud není immutable, takže (z hlavy) napřklad, nebo klidně to co jste psal vy, nicméně metoda clone je potřeba používat opatrně, viz například Effective Java od pana Blocha (http://www.amazon.co.uk/Effective-Java-Second-Joshua-Bloch/dp/0321356683/ref=sr_1_1?s=books&ie=UTF8&qid=1301987382&sr=1-1).

    public Date getNarozeni() {
return new Date(narozeni.getTime()); // vracím kopii, se kterou ať si každý dělá co se mu zachce, můj originál mi zůstává...
    }

Tohle není problém ukazatelů, ale toho, jestli jsou objekty immutable nebo ne....

S pozdravem

Lukáš Záruba (Lukas Zaruba)


Dne 5.4.2011 08:41, Libor Jelinek napsal(a):
Jak v Javě ukazatele nejsou, ale vlastně tak trochu jsou, je podle mě ve výsledku ještě komplikovanější, než kdyby opravdu byly :-)

Může se Vás zeptat na bug, který zmiňujete (http://findbugs.sourceforge.net/bugDescriptions.html#EI_EXPOSE_REP)? Jak přesně se proti tomu bránit?

Tento prográmek by mi asi Findbugs označil právě chybou EI_EXPOSE_REP, protože mi opravdu umoňuje vynulovat datum narození zaměstnance i když jsem si ho označil jako private a nezveřejňuji setter.

import java.util.Date;

public class ZmenaBezSetteru {
    public static void main(String[] args) {
Zamestnanec zam = new Zamestnanec(new Date(System.currentTimeMillis()));
        System.out.println("Osoba2.getNarozeni() = " + zam.getNarozeni());

        zam.getNarozeni().setTime(0L);
        System.out.println("Osoba2.getNarozeni() = " + zam.getNarozeni());
    }
}

class Zamestnanec {
    private Date narozeni;

    Zamestnanec(Date narozeni) {
        this.narozeni = narozeni;
    }

    public Date getNarozeni() {
        /*Zamestnanec kopieZamestnance = new Zamestnanec(narozeni);
        return kopieZamestnance.getNarozeni();*/

        return narozeni;
    }
}

Ovšem do jaké podoby přepsat Zamestnanec.getNarozeni(), aby teda nevracela referenci na privátní objekt Date, ale kopii. Tedy odolné proti zam.getNarozeni().setTime(0L);, aby i po tomto příkazu zůstalo datum narození v nezměné?

První co mě napadá je přepsat getNarozeni() na toto:

    public Date getNarozeni() {
        Zamestnanec kopieZamestnance = new Zamestnanec(narozeni);
        return kopieZamestnance.getNarozeni();
    }

Ovšem s tím nepochodím a skončím s ošklivou chybou:

Exception in thread "main" java.lang.StackOverflowError
    at Zamestnanec.<init>(ZmenaBezSetteru.java:16)
    at Zamestnanec.getNarozeni(ZmenaBezSetteru.java:21)
(a tento řádek vypsán ještě asi 30x :-))

Proč skončí tato varianta s vytvořením nového objektu na sebe sama s chybou StackOverflowError? Když zkusím druhé co mě napadá na toto:

    public Date getNarozeni() {
        return (Date) narozeni.clone();
    }

Pak již hlavní program vypíše 2x po sobě stejné datum.

--
Libor

2011/4/4 Ondřej Fafejta <[email protected] <mailto:[email protected]>>

    2011/4/4 Robert Novotny <[email protected]
    <mailto:[email protected]>>:
    > Este by som to vylepsil, aby bolo vidiet efekt:
    >
    > I. Primitivy hodnotou:
    >
    > public static void zlyPokusOZmenuParametra(int i) {
    >    ++i;
    > }
    >
    > int i = 1;
    > zlyPokusOZmenuParametra(i);
    > System.out.println("i == " + i);  // 1
    >
    > II. Objekty referenciou
    >
    > public static void zmenDate(Date d) {
    >    d.setTime(0L);
    > }
    >
    > Date date = new Date();
    > System.out.println("date == " + date);    // v case mojeho spusteni
    > ... date == Mon Apr 04 14:15:27 CEST 2011
    > zmenDate(date);
    > System.out.println("date == " + date);    // date == Thu Jan 01
    > 01:00:00 CET 1970


    jj. tento příklad je výstižnější  ... (návratový typ je zbytečně
    matoucí ;-))

    Jinak ještě doplním, že findbugs hlásí chybu, když např. entita má
    getter pro parametr, u kterého můžeme přepsat hodnotu bez toho abychom
    volali setter...

    http://findbugs.sourceforge.net/bugDescriptions.html#EI_EXPOSE_REP

    např. (píšu z hlavy - určitě někde budu mít překlep ;))

    public class NejakaEntita implements Serializable {
       private Date createdAt;

      public Date getCreatedAt() {
          return createdAt;
      }
    }

    Fafi


Odpovedet emailem