[ karas @ 26.10.2004. 15:10 ] @
Code:

Object obj = new String("Hello, World!");
if(obj instanceof String) System.out.println("true");


shtampa true!? Zar ne bi trebalo da je obj tipa Object a ne String? Pa tek sa (String)obj da dobijem String?
[ filmil @ 26.10.2004. 16:34 ] @
Ne bi trebalo. U suprotnom ti instanceof ne bi ni bilo potrebno, jer bi uvek znao da je Object zapravo Object.

Instanceof upravo služi da dohvatiš izvorni tip objekta kada je taj podatak uništen downcastom.

// edit: e, da: U tvom primeru, da instanceof vrati Object, ne bi znao da li je konverzija u String dozvoljena ili ne.

Evo primer koji pokazuje šta bi bilo da je onako kako kažeš:
Code:

Object obj = new String(10);  // Ovo je OK
if(obj instanceof String) 
  System.out.println("true"); // Pretpostavimo da se ovo NE ispisuje, tj da instanceof radi onako kako kažeš

// kako sad da znam da mogu da uradim (String) obj?!


f

[Ovu poruku je menjao filmil dana 27.10.2004. u 11:44 GMT+1]
[ Java Beograd @ 27.10.2004. 10:31 ] @
Ili to shvati ovako:

Avion YU-569 je novi Boeing 737-300.

Da li je YU-569 vrste Boeing 737-300?

Jeste.
[ karas @ 28.10.2004. 08:35 ] @
Znachi, obj je i dalje tipa Object, a instanceof mi pokazuje da li ga je mogucce konvertovati u String?
[ filmil @ 28.10.2004. 09:13 ] @
Citat:
Znachi, obj je i dalje tipa Object, a instanceof mi pokazuje da li ga je mogucce konvertovati u String?
Ne znam da li je to „zvanično“ objašnjenje, ali bih se složio s njim.

Primeti takođe da važi: obj instanceof Object == true kao i obj instanceof String == true. U slučaju da tvoja klasa implementira neke interfejse važilo bi i obj instanceof ITajInterfejs == true, kao i za sve interfejse koje on nasleđuje.

f
[ dusanmiloradovic @ 28.10.2004. 09:28 ] @
Ne, to znaci da je obj tipa String, ali klasa String nasledjuje klasu Object (kao i sve ostale klase).
Zbog toga je moguce objekat obj kastovati na tip koji je vise u hijerarhiji, u tvom slucaju Object.
Instanceof ti pokazuje kog je tipa tvoj objekat zaista.
Zasto bi uopste napisao nesto kao:
Object obj = new String(10); ?
To bi uradio u slucaju da treba objekat obj da prosledis nekoj metodi u nekom objektu ili klasi koja kao parametar ima promenljivu tipa Object. Znaci, zamisli da imas jednu klasu koju nasledjuje vise drugih
klasa. Npr:
class Covek{}
class Muskarac extends Covek{}
class Zena etends Covek{}
Sada recimo da imas jednu klasu kojoj je potrebna referenca na Covek:
public class Student{
Covek stud;
public Student(Covek stud){
this.stud=stud;
}
public oceni(int ocena){
....
}
public static void main(String[] args){
Covek osoba1=new Muskarac();
Covek osoba2=new Zena();
Student student1=new Student(osoba1);
Student student2=new Student(osoba2);
osoba1.oceni(6);
osoba2.oceni(8);

}
}
U ovoj klasi ti nije bitno da li je Covek instanceof Muskarac ili instanceof Zena,
na drugom mestu ti mozes da radis sta hoces sa specificnostima bilo koje od
ove dve klase, ali kada prosledis objekat klasi Student, te specificnosti se ne
koriste.
[ filmil @ 28.10.2004. 10:21 ] @
Citat:
Ne, to znaci da je obj tipa String, ali klasa String nasledjuje klasu Object (kao i sve ostale klase).
....
Instanceof ti pokazuje kog je tipa tvoj objekat zaista.
Instanceof kaže samo da li je objekat instanca neke klase, a ne kog je tipa objekat zaista. U gornjem primeru, obj je instanca String sa istim pravom kao što je instanca Object.

Uz pomoć instanceof se ne može utvrditi šta je stajalo posle operatora new kada je obj alociran. Da se može, onda bi funkcija koja to radi pokazivala kog tipa je obj zaista.
Citat:
Zasto bi uopste napisao nesto kao:
Object obj = new String(10); ?
Obično se ovakve stvari ne pišu; ali ako staviš String u kolekciju, ovo će se implicitno desiti.

f
[ Dragi Tata @ 28.10.2004. 13:24 ] @
Uh, al ste zapetljali prostu stvar. Pazi ovako:

Code:

Object obj = new String("Hello, World!");


u stvari sadrži dve stvari:

Code:

Object obj;
obj = new String("Hello, World!");


Prva linija deklariše obj kao referencu na Object i u jeziku sa statičkim tipovima kao što je Java, obj će "do kraja života" da bude referenca na Object i ništa drugo.

Druga linija konstruiše na heapu objekat tipa String, inicijalizuje ga i dodeljuje vrednost promenljivoj obj da pokazuje na taj objekat. Novostvoreni objekat će "do kraja života" da bude String (ne referenca na String, nego baš String) i ništa drugo. E sad, zašto je dozvoljeno da referenca na Object pokazuje na objekat tipa String? Zato što je String podklasa klase Object - drugim rečima, String je istovremeno i Object.

Dakle, obj je referenca i ona pokazuje na objekat tipa String.

Linija

Code:
if(obj instanceof String) 


na srpskom znači: da li je objekat na koji pokazuje referenca obj tipa String? Odgovor je očigledno "da".
[ bobjan @ 28.10.2004. 16:48 ] @
I više od svega navedenog.
Treba razmišljati do kraja objektno. Kada kreiraš instancu nekog objekta ti zapravo kažeš kog tipa je taj objekat,a on može istovremeno da bude instance više tipova. I uvek će instanceof da za sve to kaže true. Evo dole primer:
Code:

interface InterOne{}
interface InterTwo{}

public class Objekat implements InterOne, InterTwo{
    public static void main(String[] args){
        Objekat obj = new Objekat();
        if(obj instanceof Objekat){
            System.out.println("Objekat true");
        }
        if(obj instanceof InterOne){
            System.out.println("InterOne true");
        }
        if(obj instanceof InterTwo){
            System.out.println("InterTwo true");
        }
    }
}

Kreirani objekat je istovremeno i Objekat i InterOne i InterTwo, i na sva tri pitanje dole dobije se true.
U OO jezicima nekada je bolje razmišljati u rečenicama koje izgovaramo svakodnevnom komunikacijom, nego se zaglibiti u čisto programersko razjašnjavanje. Znači u nekom sveobuhvatnoj modeliranoj aplikaciji :

Osoba pera = new Osoba("Pera");

Na sva eventualna pitanja
if pera instacneof Osoba, ZivoBice, StanovnikPlanete, PokretljivaStvar, DvonoznoBice, Balkanac(ne uvek:)) .....

odgovor je true, jer je tako i u životu.

[ fop @ 28.10.2004. 17:54 ] @
mislim da bi valjalo spomenuti coveku da sada kada zna sta je instanceof i kako radi, da sada polako zaboravi na ovo zlo i vise ga ne koristi. :)

instanceof nije u duhu objektno orjentisanog programiranja. nikada ne treba pisati kod koji proverava tip i u zavisnosti od tipa nesto izvrsava... to je bespotrebno i ruzno kodiranje, a taj mehanizam se po potrebi dobija polimorfizmom.

voleo bih da cujem kada ste vi poslednji put upotrebili instanceof?
[ Dragi Tata @ 28.10.2004. 18:26 ] @
Citat:
fop:  nikada ne treba ...


Trudim se da ne koristim izraze kao što su "nikada", "obavezno" i "uvek" kad je programiranje u pitanju.
[ filmil @ 28.10.2004. 22:32 ] @
Citat:
mislim da bi valjalo spomenuti coveku da sada kada zna sta je instanceof i kako radi, da sada polako zaboravi na ovo zlo i vise ga ne koristi. :)

instanceof nije u duhu objektno orjentisanog programiranja. nikada ne treba pisati kod koji proverava tip i u zavisnosti od tipa nesto izvrsava... to je bespotrebno i ruzno kodiranje, a taj mehanizam se po potrebi dobija polimorfizmom.
Dozvoli mi da se, blago rečeno, krajnje ne složim sa ovom konstatacijom.

Kada je potrebno koristiti polimorfizam, tj. kada na objektima različitih klasa treba izvršiti operaciju istog tipa (recimo Kvadrat.iscrtaj(), Krug.iscrtaj() i sl), onda tvoj savet stoji. Bez instanceof a implementacijom istog interfejsa u odgovarajućim klasama se vrlo elegantno postiže željeni efekat.

Međutim, kada na objektima različitih klasa treba izvršiti različite operacije, onda se bez instanceof ili sličnog operatora prosto ne može.

Sličan je slučaj ako klase potiču recimo od različitih proizvođača. Da bi izbegao instanceof, obe familije klasa moraju da implementiraju isti, željeni interfejs. Kako naterati različite proizvođače da implementiraju jedan te isti interfejs? Nikako. Naravno, uvek možeš da napraviš adapter koji obmotava dve nesrodne hijerarhije klasa, ali ako tih klasa ima suviše, da li se isplati?

Rekao bih da se ne isplati: šta je npr. sa klasama koje prosto ne implementiraju neke metode? Kod njih odgovarajući metod pokazuje u prazno, što je rasipanje resursa.
Citat:
voleo bih da cujem kada ste vi poslednji put upotrebili instanceof?
Instanceof koristim svaki dan. Danas sam napisao bar 10-tak klasa u kojima se pojavljuje ta ključna reč i ne, nije u pitanju loš dizajn.

Da pojasnim: pravimo multiagentsku platformu zasnovanu na komponentama. Svaki program koji se u platformi izvršava (zovemo ih agenti, bez posebnog razloga) sastoji se iz komponenata koje komuniciraju sa tablom (blackboard). Svaki agent ima sopstvenu tablu. Komponente mogu da postavljaju objekte na tablu i mogu da skidaju željene objekte sa nje. Na tablu se može postaviti objekat bilo kog tipa, a kako komponenata često ima puno i kako obično rade na različitim stvarima, na njoj u datom trenutku mogu da koegzistiraju objekti bez preterano mnogo veze jednih s drugima.

Svaka komponenta može da posebnom objektu (koji se zove Subscriber) dostavi predikat (klasu koja implementira interfejs IPredicate) koji pokazuje kada komponenti treba proslediti neki objekat sa table. Vrlo često komponenta filtrira samo objekte nekog određenog tipa i zato se u predikatu često pojavljuje kod poput:

Code:
public void execute(Object o) {
     return o instanceof NekaKlasa;
 }
 
 
Neki predikati imaju i dodatne provere, ali po pravilu ovo je prva. Ne vidim u ovom pristupu ništa loše a voleo bih i da vidim kako bi se ovo izvelo bez nekog oblika RTTI-ja, čistom upotrebom polimorfizma.

Ko što reče Nemanja (a valjda i neko pre njega, ne sećam se :), nikad ne reci nikad.

f
[ fop @ 29.10.2004. 04:36 ] @
prvo zelim da se slozim sa za vama za ono "nikad"... dobro je usvojiti taj princip.
e sada, zar za navedeni problem ne bi najjednostavnije bilo upotrebiti preklapanje metode?... na primer:

Code:

public void execute(NekaKlasa o) {
     // uradi ono sto je specificno za NekuKlasu
}

public void execute(NekaDrugaKlasa o) {
     // uradi ono sto je specificno za NekuDruguKlasu
}

public void execute(Object o) 
throws KlasaNijePoznataPaKomunikacijaNijeMogucaException {
     throw KlasaNijePoznataPaKomunikacijaNijeMogucaException; // ;)
}


po meni je ovo bolje resenje, jer si rad sa novim tipovima sveo na dodavanje nove metode sto je i nekako logicno jer si proveru tipa delegirao masini.

nazalost javlja se sledeci potencijalni problem:
ako su NekaKlasa i NekaDrugaKlasa zapravo samo interfejsi dakle bez implementacije, i neka je nekiObjekat tipa NekaTreca klasa koja implementira i NekuKlasu, i NekuDrugu, tada ce poziv

Code:

execute(nekiObjekat);


biti viseznacan. nemam ideju za ovo.
[ karas @ 29.10.2004. 07:18 ] @
@Dragi Tata
Hvala, takvo objashnjenje mi je trebalo. U C++--u su lepo razdvojeni pojmovi objekta, pokazivacha, reference, pa je lakshe shvatiti o chemu se radi, u Javi je sve to malo izmeshano (ili u knjigama ne objashnjavaju detaljno).
[ filmil @ 29.10.2004. 07:55 ] @
Citat:
e sada, zar za navedeni problem ne bi najjednostavnije bilo upotrebiti preklapanje metode?... na primer:
Ne bi, zato što bi onda dodavanje nove klase zahtevalo promenu interfejsa IPredicate, dodavanje nove metode za novu klasu i zatim rekompajliranje celokupnog koda koji od tog interfejsa zavisi. Takođe bi morao u sve dotadašnje implementacije IPredicate da dodaš novi metod, osim ukoliko ne napraviš (pravu) baznu klasu koju će nasleđivati svi predikati; međutim ni to ne valja jer onda zbog isključivo jednostrukog nasleđivanja fiksiraš sve implementacije IPredicate u jedno, fiksno mesto (extends AbstractPredicate) što opet ne valja jer onda korisnik ne može da ima svoju hijerarhiju predikata. Dakle uništava se smisao postojanja interfejsa.

U isto vreme bi kod koga prave dve različite grupe programera bilo nemoguće objediniti bez rekompajliranja svega od nule a to uopšte nije polazna ideja: zezanje sa predikatima i komponentama je upravo smišljeno kako bi se omogućilo modularno (dakle nezavisno) razvijanje koda, kao i dinamičko učitavanje modula po potrebi. Da ne pominjem da bi od takvih n metoda u IPredicate, tipično n-1 metoda imala samo throws, što vrlo deluje kao bacanje resursa.

I naravno ostaje problem ako postoje execute metodi za klasu i izvedenu klasu.

Ove stvari naravno mogu da se reše ukoliko su sve klase poznate u vreme kompajliranja. Prosto se inventarišu svi predikati, pronađe sav kod i onda objedini u jednu jedinu klasu predikata. Međutim, mi želimo da to rešimo, ali u vreme izvršavanja (runtime). Zato i jeste potrebno koristiti RTTI.

f
[ -zombie- @ 29.10.2004. 14:23 ] @
Citat:
fop:
prvo zelim da se slozim sa za vama za ono "nikad"... dobro je usvojiti taj princip.
e sada, zar za navedeni problem ne bi najjednostavnije bilo upotrebiti preklapanje metode?... na primer:


to neće da poleti.. zato što u tvom primeru kod:

Code:
Object obj = new NekaKlasa();
execute(obj);


uvek da baci KlasaNijePoznataPaKomunikacijaNijeMogucaException.. (naravno, drugi slučaj, kada je referenca obj tipa NekaKlasa, ne vredi ni razmatrati, jer onda očigledno znamo koju metodu da pozovemo)


filmil: ovo što ti opisuješ (ako sam dobro skapirao) je školski primer asinhronog messaginga, odnosno idealna prilika za korišćenja Envelope objekta.

znači, on bi pored samog objekta koji treba da se okači na tablu sadržao i neke potrebne meta-podatke, tipa ko ga je okačio (koji agent), za koga je (ako je namenjen nekom određenom agentu), vreme kada je okačen (makar zbog logovanja i debugovanja ako za drugo nije bitno), i možda alternativni metod identifikacije (tipa) objekata (znači ne RTTI već neki ID brojevi, stringovi, etc)..

naravno, ako je sve to nepotrebno u konkretnom slučaju, onda predstavlja čist overhead, i sasvim je u redu koristiti RTTI za identifikaciju (nije ništa manje ni više safe od identifikacionih brojeva/stringova).
[ filmil @ 29.10.2004. 14:36 ] @
"-zombie-" wrote:
Citat:
filmil: ovo što ti opisuješ (ako sam dobro skapirao) je školski primer asinhronog messaginga, odnosno idealna prilika za korišćenja Envelope objekta.
....
naravno, ako je sve to nepotrebno u konkretnom slučaju, onda predstavlja čist overhead, i sasvim je u redu koristiti RTTI za identifikaciju (nije ništa manje ni više safe od identifikacionih brojeva/stringova).
Dobro primećeno: dabome da se mogu koristiti nekakvi meta-podaci, jedino što u tom slučaju moraš sam da se staraš da klase zaista i imaju različite meta-podatke; kada koristiš RTTI, java to za tebe odradi automatski (ubr ako neko ne zna, RTTI==runtime type identification). Naravno štos je u tome što se tabla koristi samo za komunikaciju interno između komponenata; za eksternu komunikaciju već dolaze u obzir adrese i ostalo.

f
[ Dragi Tata @ 29.10.2004. 14:41 ] @
Citat:
karas: U C++--u su ...


(Malo da kukam, po običaju). Sa čisto tehničke strane gledano, mislim da je bila enormna glupost uvoditi C++ like sintaksu u tako suštinski različit jezik kao što je Java. Da ne pominjem da je i sama sintaksa C++a "ne baš lepa" (upravo čitam "Design and Evolution of C++" i sam Bjarne Stroustrup konstantno kuka na "prljavu" sintaksu koju je bio prinuđen da nasledi od C-a), ali još gora stvar je što su uveli veštačke sličnosti u sintaksi koje reflektuju potpuno drugačije koncepte, kao što si i sam otkrio.

Naravno, presudan je bio marketing - ciljali su na "preobraćanje" C++ programera.
[ -zombie- @ 30.10.2004. 15:55 ] @
filmil: mislio sam na korišćenje posebnog Envelope objekta koji bi se kreirao neposredno pre kačenja na tablu, i koji bi sadržao, pored metapodataka, i referencu na sam objekat koji treba da se prosledi..

znači, nešto tipa: blackboard.put(new Envelope(objekat, ID, from, to, otherMetaData));
[ filmil @ 30.10.2004. 23:34 ] @
Tabla je interna struktura, tako da najčešće metapodaci nisu potrebni. Izuzetak je kada se objavljuje promena objekta na tabli i tada klijent može da okači dodatne informacije. Ali to nije from i to, zato što to krši semantiku table, tj. ideja je da neimenovana komponenta može da pošalje poruku svim (neimenovanim) zainteresovanim.

f
[ lord_NIKON @ 02.11.2004. 16:55 ] @
Instanceof metoda nam kazuje pripadnost nekog objekta kroz hijerarhiju klasa.(Od superklase do najnize klase), dok metoda getClass nam govori pripadnost objekta konkretno neke klase u hijerarhiji