» »

[Java] če naredim razred generičen, dobim milijon napak

[Java] če naredim razred generičen, dobim milijon napak

MrStein ::

Malo hecno , ampak. Imam en razred, nekaj takega :
(zakaj ni gumba "St.koda" ? ;) )

public abstract class MojaRazred extends NekiRazred {
...
 protected Map<String, Object> mapa;
...


Ki vsebuje kup metod, polj itd..
Imam tudi kup izpeljanih razredov. In lepo deluje.

Ker pa imam zdaj precej cast-anja, sem mislil malo generike uporabit.

Ampak če spremenim malenkost (dodal le "<T>" v prvo vrstico) :

public abstract class MojRazred <T> extends NekiRazred {
...
 protected Map<String, Object> mapa;
...



..dobim milijon napak v podrazredih.
Kolko sem razumel, generične verzije razredov so kompatibilne nazaj z negeneričnimi. (primer Map in Map<K,V>, stara koda, ki uporablja le Map, čist lepo dela z novo generično verzijo mape).
Še toliko bolj je čudno, ker parametra T zaenkrat sploh nikjer nisem uporabil.

Za začetek bom navedel en warning, ki se mi s tem pojavi. V enem podrazredu od MojRazred imam :
public class PodRazred extends MojRazred
  @Override
    protected void nekaj() throws Exception {
        super.nekaj();
        mapa.put("foo", true); // warning !

Za označeno vrstico mi da opozorilo :

Type safety: The method put(Object, Object) belongs to the raw type Map. References to generic type Map<K,V> should be parameterized

Kaj s tem hoče povedat ??? Kak naj popravim ?

Zdaj pa k napakam. V PodRazred imam tudi :
   @Override
    protected void ojoj(List<Object> spisek, Object obj) {

To da napako :

The method ojoj(List<Object>, Object) of type PodRazred must override a superclass method


Seveda je v superklasi (MojRazred) stvar lepo definirana:
 protected void ojoj(@SuppressWarnings("unused")
    List<Object> spisek, @SuppressWarnings("unused")
    Object testObject) {
        // don't do anything, let subclasses override
    }


Kaj mu fali ? Sicer se napake znebim, če odstranim anotacijo @Override, ampak potem ostane dvom, da superklasa ne bo klicala te, ker kao ni ista. Razen tega ne glede na @Override ima ena podpodklasa naslednjo napako:

Name clash: The method ejej(List<Object>, Object) of type PodRazred has the same erasure as ejej(List<Object>, Object) of type MojRazred but does not override it


Koda:

public class PodPodRazred extends PodRazred{
   @Override
    protected Class getFoobar() { // to je ena abstract metoda v MojRazred
        return Krneki.class;
    }
}
Motiti se je človeško.
Motiti se pogosto je neumno.
Vztrajati pri zmoti je... oh, pozdravljen!

MrStein ::

Aja, kompajler je Sun JDK 1.5.0_09
Motiti se je človeško.
Motiti se pogosto je neumno.
Vztrajati pri zmoti je... oh, pozdravljen!

noraguta ::

bojkodane ne more biti isto dekaracije metod rabijo generični označevalec. v ostalem compiler ne more vedet v kaj razviti kodo. sem skoraj prepican da dobivaš kake trke med referianimi tipi? sicer nisem java guru ampak generiki so nekako tako zadeva , da se substituira glede na uporabljan tip T(pa uni jebeni uklepaji, dejte ze enkat nardit knof za kodo) z tistim kateri je konzumiral generika.
Pust' ot pobyedy k pobyedye vyedyot!

kopernik ::

Odvisno kaj sploh hočeš narediti. Če podrazredi niso generični, potem moraš pri razširjanju povedati kakšnega tipa je parameter v superclassu, e.g. :

public class PodRazred extends MojRazred<String>


Pa se boš rešil warninga.

In zakaj imaš annotatione @SuppressWarnings("unused") v tisti metodi ? Raje naredi tako kot je treba kot da na tak način utišaš compiler. Na netu je polno tutorialov za java generics.

MrStein ::

noraguta, a lahko to ponoviš, na razumljiv način ?

kopernik:
- "Odvisno kaj sploh hočeš narediti."

Uporabiti prednosti generikov, ampak na nazaj kompatibilen način (torej brez spreminjanja že napisanih "uporabnikov" omenjene kode). Beri: kup že napisane kode ne bom spreminjal, ampak bom generike izkoristil pri na novo napisani kodi. Saj sem dal primer. Novi Vector je generičen, ampak stara koda, ki uporablja stari, negeneričen Vector še vedno dela, brez sprememb.

- "Če podrazredi niso generični, potem moraš pri razširjanju povedati kakšnega tipa je parameter v superclassu"

Ne, ne rabim. Temu se reče kompatibilnost nazaj. Če uporabljam razred, ki ni generičen, potem pa nova verzija je, ne rabim jaz svojo kodo nič spreminjat. Lahko, ni pa nujno. Vsaj tak sem jaz razumem omenjeno kompatibilnost nazaj generikov.

- "In zakaj imaš annotatione @SuppressWarnings("unused") v tisti metodi ?"
To itak nima veze s tem problemom. Razen tega, a ni očitno ? Gre za "stub" metodo, ki ne uporablja ta parameter (ker ne uporablja sploh nič, je NO-OP), namenjena pa je temu, da jo izpeljan razred overrajda in pri tem uporabi te parametre.
Motiti se je človeško.
Motiti se pogosto je neumno.
Vztrajati pri zmoti je... oh, pozdravljen!

kopernik ::

Ne, ne rabim. Temu se reče kompatibilnost nazaj. Če uporabljam razred, ki ni generičen, potem pa nova verzija je, ne rabim jaz svojo kodo nič spreminjat. Lahko, ni pa nujno. Vsaj tak sem jaz razumem omenjeno kompatibilnost nazaj generikov.


Glej, najprej si preberi en tutorial. Mešaš jabolka in hruške. Pač si očitno narobe razumel "kompatibilnost generikov".

Zdaj pa malo uporabi logiko in pomisli, kaj hočeš narediti : razred MojRazred je parametriziran s parametrom T, podrazred PodRazred pa ni parametriziran. Kako naj prevajalnik ve, kaj nadomestiti s parametrom T v razredu MojRazred, ko rečeš new PodRazred() ?

MrStein ::

Ne vem, kak ve, ampak očitno nekak ve. Sem namreč naredil novi podrazred in lepo dela. Tak :

public class PodRazred2 extends MojRazred {

    public void foo() {
        System.out.println("A kompajler cita misli ????");
    }

}


Razen tega, če bi sam prebral tutoriale, ki jih omenjaš, bi vedel, da v času, ko se prevaja PodRazred2, MojRazred že preveden, in ker se vsa umetnost generikov pri prevajanju izbriše (glej pod erasure), kompajler nima kaj razmišljat o T, ker takrat T več ne obstaja.

Kakorkoli, v mojem projektu sem vse fajle popravil na roko in vse dela, tak da ni nobene sile...
Motiti se je človeško.
Motiti se pogosto je neumno.
Vztrajati pri zmoti je... oh, pozdravljen!

Quikee ::

..Kako naj prevajalnik ve, kaj nadomestiti s parametrom T v razredu MojRazred, ko rečeš new PodRazred() ?..
Kompiler, če drugače ne navedeš vedno nadomesti z najnižjim možnim, kar je v trenutnem primeru Object in se T tudi tako vede v kodi, če ga hočeš uporabit. Če pa definiraš, da je <T extends String> bo pa T vedno nadomestil z String-om, če ni navedeno drugače.

kopernik ::

Ampak s tem se ne boš rešil warningov. A ni bil to problem ?

Priporočam tudi ogled izvorne kode jdk 1.5, npr. collection frameworka, kjer je precej parametriziranih vmesnikov in razredov, pri čemere je hierarhija kar razvejana. Boš videl, kako extendajo parametrizirane razrede.

EDIT: quikee, to je res in ravno to so mnogi spljuvali pri uvedbi parametrizacije v Javi, ker se v mnogih primerih koda bolj zaplete, namesto da bi se poenostavila. V C++ lahko na parametru kličeš karkoli, medtem ko v Javi največ tisto, kar je v osnovnem tipu (v tem primeru Object).

Zgodovina sprememb…

  • spremenil: kopernik ()

MrStein ::

Ampak s tem se ne boš rešil warningov. A ni bil to problem ?

No ja, ERROR-ji so malo večji problem kot WARNING-i.
Motiti se je človeško.
Motiti se pogosto je neumno.
Vztrajati pri zmoti je... oh, pozdravljen!


Vredno ogleda ...

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

[Android] setText iz AsyncTask

Oddelek: Programiranje
7784 (701) golobich
»

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

Oddelek: Programiranje
211455 (902) shadeX
»

[Java] Castanje

Oddelek: Programiranje
91435 (1290) fiction
»

[JAVA] zaustavitev niti (threadov)

Oddelek: Programiranje
223046 (3046) morbo
»

tomcat - problem z encodingom

Oddelek: Programiranje
72266 (2180) kopernik

Več podobnih tem