String.intern() és ==

Fórumok

Hali!

Meg tudná valaki magyarázni, hogy miért ajánlják mindenhol a == használatát az intern-ált (lol) Stringek megemlítésekor?

Értem, hogy gyorsabb, mert referenciát hasonlít össze, és nem karakterről-karakterre két sztringet, de nem ugyanúgy if (this==s) return true; -val kezdődik a String-ben az equals(String s)?

üdv,

Hozzászólások

Lehet, hogy ott ahol ezt alkalmazták, kifejezetten azt szerették volna tudni, hogy ugyanarról az objektumról van-e szó, és nem azt, hogy karakterről karakterre megegyezik-e a két string. Valahogy biztos ki lehet deríteni, hogy tényleg ez volt-e a szándéka a programozónak vagy hibázott.

Arról van szó, hogy már a második, egyébként jó Java-s könyvben olvasok az intern-ált stringekről.

Szépen, világosan elmondja, hogy ez h működik. Eddig ok, de aztán még azt is kifejti, h ha sok összehasonlítást végzünk, akkor intern-áljuk, és utána használjuk a == operátort, mert az intern-álás miatt a referenciájuk is meg fog egyezni a stringeknek, aminek az összehasonlítása tényleg nagyságrenddel gyorsabb, mint a karakterről-karakterre való vizsgálat.

Viszont az eqals implementációja úgyis azzal kell kezdődjön, hogy először ezt ellenőrzi?!

Nem hiszem, hogy azzal kezdődik. De ha biztosan akarod tudni, akkor nézd meg a forrást.

Szerintem arrol lehet szo, hogy igy megsporolhatsz egy fuggvenyhivast, mert a JITtelt kodban egy-az-egyben lehet egy referencia compare ahelyett, hogy fel kellene epiteni egy exec stacket, etc.

Tehat

if (a == b)
=>
load address a
load address b
cmp
branch if true ...

if (a equals b)
load address a
load address b
call virtual method equals
branch if true ...

(bocs a pszeudokodert, a java bytecode opokat nem ismerem)

while (!sleep) sheep++;

Megnéztem a forrást, valóban így kezdődik:


 (...)
 1012       public boolean equals(Object anObject) {
 1013           if (this == anObject) {
 1014               return true;
 1015           }
 (...)

--
The Net is indeed vast and infinite...
http://gablog.eu

Talán azért, hogy emlékeztessen, hogy ez egy internált String. ;)

String a = "valami";
String b = a;

boolean bool = true;
long startTime;

startTime = System.currentTimeMillis();
for(int i=0;i<100000000;i++) {
	bool = bool && a == b;
}
System.out.println((System.currentTimeMillis() - startTime));

startTime = System.currentTimeMillis();
for(int i=0;i<100000000;i++) {
	bool = bool && a.equals(b);
}
System.out.println((System.currentTimeMillis() - startTime));

Az elvetemült példa eredménye:
597
2062

Nem mintha számítana valós környezetben…

De mi van, ha van két, egymástól függetlenül létrehozott String objektumom, és mindegyik tartalma "alma".
Ekkor a == false-t fog visszaadni, mert enm ugyan az a referencia.
Ekkor csak az equals() segít, ha meg akarom tudni, hogy ugyan azt a szöveget tartalmazzák-e.

Szerintem erre vagy kiváncsi: a String osztály kezel egy privát elérésű "string-pool"-t. Ha meghívod az intern függvényt a stringeden, akkor az megnézi, hogy a poolban szerepel-e mar a string (equals-szal), es ha igen, akkor erre a stringre ad egy referenciát, ha nem akkor beteszi a poolba az aktuális stringet, és erre való referenciát ad vissza. Ezért két equals alapján azonos string ha intern-álod, akkor referencia alapján is azonos lesz. Gondolom ez arra jó, hogy ha sokszor kell összehasonlítást végezned, akkor először intern-álsz, és utána elég referencia szerint vizsgálnod.

Ilyenkor viszont két különböző változónévvel ellátott, de azonos tartalmú, ezáltal azonos referenciájú, string valamelyikének megváltoztatása magával vonja a másik megváltozását is, amit nem biztos, hogy úgy akartuk. Intern-áláskor tehát nagyon kell vigyázni a stringek módosítgatásával!

Nem erre gondoltam, hanem az intern-álás utáni állapot esetére!


        String s1 = "valami";
        String s2 = s1.intern();
        String s3 = s1.intern();
        s2 = s2 + " + még valami";
        System.out.println(s3);        

De kipróbáltam, ekkor sem lesz egyenlő s2 és s3. De ezt már nem értem, miért nem.
Úgyhogy az előző hozzászólásomat vissza kell szívnom! Bocs!

Ez (s2 = s2 + " + még valami") a sor az alábbinak felel meg:

s4 = s2 + " + még valami";
s2 = s4;

azaz létrejön egy új string, és s2 végül erre fog mutatni.

ha megnézed a string osztályt az összes függvénye "const", azaz soha nem
módosítják az adott objektum értékét, hanem visszatérési értékként egy új objektumot példányosítanak.

pl a concat így néz ki:


   public String concat(String str) {
        int otherLen = str.length();
        if (otherLen == 0) {
            return this;
        }
        char buf[] = new char[count + otherLen];
        getChars(0, count, buf, 0);
        str.getChars(0, otherLen, buf, count);
        return new String(0, count + otherLen, buf);
    }

Azaz akármit csinálhatsz a Stringgel intern() hívás után, csak tudnod kell, hogy az egy másik String lesz ... :)