» »

[Java] Castanje

[Java] Castanje

shadeX ::

Lepo bi prosil če mi to nekdo razloži.

Imam 2 razreda. 1 Razred:

public class Animal {

	public void drink() {
		
		System.out.println("Animals drink water");
		
	}
}


Temu razredu se reče starševski razred oz. parent class, base class itd.., ter je splošen razred.

2. Razred je pa ta:

public class Lion extends Animal {

	public void drink() {
		super.drink();
		
		System.out.println("Lions drink water too");
		
	}	
}


To je otrok prejšnega razreda ( child class.. itd ) Ta razred je bolj opredeljen, saj je Lev vrsta živali.

Potem imam še 3. razred ( Main ) kateri je praktično vstopna točka.

public class Main {

	/**
	 * @param args
	 */
	public static void main(String[] args) {

		Animal lion = new Animal();
		lion.drink();
		
	}

}


Če zaženemo kodo bo rezultat: //Animals drink water

Če uredim Main razred in ga spremenim v:

public class Main {

	/**
	 * @param args
	 */
	public static void main(String[] args) {

		
		
		Lion animal = (Lion) new Animal();
		animal.drink();
		
	}

}


Bo rezultat: ClassCastException .. Zakaj ?

V katerem primeru lahko castam v zgornji razred? Iz recimo Leva v žival ( seveda ko sta v dedovanem razmerju) ? A je to sploh mogoče?

dmok ::

Animal animal = new Lion();
animal.drink();
Lion lion = (Lion)animal;
lion.drink();

Ne moreš parent razreda cast-at v descendant-e. Lahko pa descendante cast-aš v parent-e.

d.

shadeX ::

aha hvala. ja neki sm se zmedel. :S.. še to me zanima.

v čem je fora da naredimo tako:

Animal animal = new Lion();
		animal.drink();


ali pa tako:

Lion l = new Lion();
		l.drink();


Output je itak isti na koncu? Mi lahko kdo to razloži =)

Mavrik ::

V tvojem primeru ni razlike, razen v tem da je prva mogoče malo slabše berljiva pa compiler te bo tepel če boš hotel uporabljati metode, ki pripadajo samo "Lion"-u ;)

Pomembno pa postane, ko enkrat s takimi objekti kaj delaš:

public static void makeItDrink(Animal animal)
{
    animal.drink()
}


ali jih tlačiš v podatkovne strukture:

ArrayList<Animal> animals = new ArrayList<Animal>();
animals.add(new Lion());
animals.add(new Elephant());

for (Animal a : animals)
{
    a.drink();
}
The truth is rarely pure and never simple.

Zgodovina sprememb…

  • spremenil: Mavrik ()

Spura ::

To je polimorfizem na single dispatch sistemu.
Treba je povedat, da overloading ne deluje po istem principu, nima dispatcha. Torej ce imamo metodo whoAmI(), ki vrne "Animal" in "Lion" bo naslednja koda imela naslednje izpise.

public static void method1(Animal a) {
    sysout(a.whoAmI());
}
public static void method2(Animal a) {
    sysout("Animal");
}
public static void method2(Lion l) {
    sysout("Lion");
}

public static void main(String[] args) {
    Animal a = new Animal();
    Animal l = new Lion();
    method1(a);
    method1(l);
    method2(a);
    method2(l);
}

Izpise: Animal Lion Animal Animal

shadeX ::

aha, ok.. hvala vam =)

Sergio ::

@Spura: To je pa en detajl ki ga nisem vedel. Slucajno ves, a bo objekt lion izvedel prvi deklarirani staticni method2 v razredu, ali bo sel takoj na klic najbolj splosnega? Ce bi pod drugim method2 deklariral se public static void method2(Object o), kaj bi se klicalo?
Tako grem jaz, tako gre vsak, kdor čuti cilj v daljavi:
če usoda ustavi mu korak,
on se ji zoperstavi.

Senitel ::

Am... Saj objekt Lion v primeru method2 ne izvede ničesar. Instanci a in l sta tipa Animal, s tem da je l še extendan v Lion. Metoda "metoda2" je overloadana in lahko vzame ali Animal ali Lion. V tem primeru vzame varianto za Animal, če ni hotel dobit varianto za Lion, bi moral l najprej eksplicitno castat nazaj v Lion.

Če imaš še void method2(Object o), potem se bo še vedno klicala void medhod2(Animal a) varianta. Razen seveda, če ne castaš l prej v Object (Object l = new Lion());

Spura ::

Sergio je izjavil:

@Spura: To je pa en detajl ki ga nisem vedel. Slucajno ves, a bo objekt lion izvedel prvi deklarirani staticni method2 v razredu, ali bo sel takoj na klic najbolj splosnega? Ce bi pod drugim method2 deklariral se public static void method2(Object o), kaj bi se klicalo?

Klice se najbolj specificni overload glede na tip spremenljike/reference. Point je torej... pri overloadanju dejanski tip objekta nima veze (se ne ugotavlja), ampak se uporablja tip reference. Oziroma z drugimi besedami - method signature se ne izbira runtime.

Se par stvari:
ce imamo metodi a(int) in a(long) in klicemo z byte, se klice a(int) - najmanjsi widening
Recimo da imamo:
public a(int x, int y);
public a(long x, long y);
public a(Byte x, Byte y);
public a(byte... x);

public m(Object x, Object y);
public m(String... x);

////////////////
byte b = 5;
a(b,b);
m("x", "y");

V odsotnosti tocno pravega signatureja grejo prioritete izbire overloada takole:
Prioriteta je prva, druga, tretja, cetrta metoda A, prva druga M pri izbiri overloading targeta.
Prva metoda A/M ima (type) widening argumentov (iz byte v int ali pa npr iz String v Object), kar ima prednost pred sirsim Wideningom (iz byte v long) in to ima prednost pred AutoBoxingom(Tretja metoda A), kar ima prednost pred Varargs metodami.

fiction ::

Single dispatch je tudi razlog, da se visitor pattern implementira na tak, khm ne čisto intuitiven način z Accept() metodo.

Če bi imel jezik multiple dispatch (in bi bilo to katera metoda se kliče odvisno tudi od runtime tipa argumentov in ne določeno ob compile time-u), bi se dalo vse skupaj poenostaviti.

Pri tem je treba še omeniti, da se da v C# >= 4.0 multiple dispatch simulirati s pomočjo "dynamic" keyworda. Beat that Java ;)


Vredno ogleda ...

TemaSporočilaOglediZadnje sporočilo
TemaSporočilaOglediZadnje sporočilo
»

problemi z javo

Oddelek: Programiranje
61127 (732) MrStein
»

Java passing

Oddelek: Programiranje
203614 (3267) mihibo5
»

[Java] Objekt poslan k metodi v kakšnem stanju?

Oddelek: Programiranje
211560 (1007) shadeX
»

Rekurzija v javi z ArrayList

Oddelek: Programiranje
81586 (1429) marjan_h
»

[Java][Naloga] Skladi

Oddelek: Programiranje
51685 (1484) bijonda

Več podobnih tem