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