Fórum Root.cz
Hlavní témata => Vývoj => Téma založeno: Natix 14. 09. 2012, 23:42:13
-
Zdravím,
vím, že stringové literály jsou v Javě internované.
Vím, že ("" == "") je true, ale že (new String() == "") je false.
Taky vím, že string získaný voláním subString sdílí své char pole s původním stringem, což může způsobit memory leak, pokud vyrábím z hodně velkého stringu malinký substring, takže je v takovém případě potřeba volat kopírovací konstrutor new String(String).
Ale nedokážu přijít na žádný use case pro defaultní konstruktor new String(). Nenapadá mě situace, kdy bych potřeboval mít prázdný string, který nebude identický s tím, který je internovaný v poolu.
Že by nějaké obskurní použití v IdentityHashMap, WeakHashMap nebo něčem podobném? Nebo tu prostě žádný důvod není a holt v Javě 1.0 ten konstruktor jednou dali public, tak tu bude už navždycky strašit? Tuší někdo?
-
/**
144 * Initializes a newly created {@code String} object so that it represents
145 * an empty character sequence. Note that use of this constructor is
146 * unnecessary since Strings are immutable.
147 */
148 public String() {
149 this.offset = 0;
150 this.count = 0;
151 this.value = new char[0];
152 }
153
asi nanic, sami to priznavaji v javadoc String() constructoru :)
-
Asi je tam pro úplnost, dovedu si představit třeba nějaký fašizující use case, kdy by "" bylo třeba nahradit new String(), aby bylo zřejmé, že se nejedná o magický řetězec, a zároveň by nebylo chtěné mít "" jako konstantu. Sice by to asi nebylo nikterak efektivní, ale v praxi je možné vidět všechno...
Nebo tu prostě žádný důvod není a holt v Javě 1.0 ten konstruktor jednou dali public, tak tu bude už navždycky strašit?
Tohle je každopádně vysoce pravděpodobné, kvůli zachování kompatibility se na API zanechávají všelijaké obskurní metody. Špatně napsané metody a třídy se sice označují jako deprecated, nicméně to zde není třeba, neboť konstruktor dělá přesně to, co má ;-)
-
A ještě mě napadá použití v testech, např. pro testování jedinečnosti klíčů, nebo něco v tom smyslu, kdy by bylo třeba pracovat právě s tímto předpokladem:
Vím, že ("" == "") je true, ale že (new String() == "") je false.
-
Ten konstruktor je asi stejne smysluplny jako konstruktor s parametrem typu String. Nektere nastroje pouzivajici reflexi to mohou pouzivat, napriklad vytvareji defualtni hodnotu cehokoliv volanim defaultniho konstruktoru, tzn. trida bez nej muze byt pro ne problem. Normalni clovek to kazdopadne nikdy nepouzije. Pri zmenach API javy je snaha minimalizovat dopad na existujici kod, takze proc by se mel odstranovat konstruktor, ktery funguje zcela spravne? Aby nestrasil? Mne nestrasi a ani neznam nikoho, koho by strasil:-)
-
kvuli deserializaci
-
Ale nedokážu přijít na žádný use case pro defaultní konstruktor new String().
Je tam zásadní chyba v implementaci operátoru == pro String, nikoliv v existenci konstruktoru, to je celé, porovnávají se pointery na instanci, nikoliv stringy samotné. Správně by (new String() == "") vracelo true, ale soudruzi si řekli ne, my to uděláme špatně.
-
Ale nedokážu přijít na žádný use case pro defaultní konstruktor new String().
Je tam zásadní chyba v implementaci operátoru == pro String, nikoliv v existenci konstruktoru, to je celé, porovnávají se pointery na instanci, nikoliv stringy samotné. Správně by (new String() == "") vracelo true, ale soudruzi si řekli ne, my to uděláme špatně.
To jsou vsechno veci vychazejici ze specifikace - == porovnava instance, new musi vzdy vytvorit novou instanci. Bylo by opravdu chytre mit uplne jine chovani techto zakladnich veci pro String a pro ostatni tridy. A cilem by bylo co? Aby mohl nekdo napsat ptakovinu typu (new String() == "") a mit z toho true...
-
A cilem by bylo co?
Nic než větší přehlednost kódu. Současný stav je nepřehledný, což dokazuje vznik tohoto tématu.
new String() == "" by fungovalo stejně jako 1 == 1
-
Ten problem (resp. nejasnosti okolo ==) vyplyva z toho, ze retezce jsou v Jave na jakemsi pomezi mezi primitivnimi datovymi typy, pro nez existuje spouta operatoru a na druhe strane je to normalni objekt. Samozrejme si tvurci Javy uvedomovali, ze retezce jsou dost zakladni soucast jazyka, takze jsou to sice objekty, ovsem existuji pro ne dve specialni jazykove konstrukce - retezcovy literal typy "hello world" a operator +, ktery se interne preklada jako volani metody. Nicmene uz operator == ma chovani stejne jako pro ostatni objekty, tj. porovnava reference, coz vede ke spatne odhalitelnym chybam, zejmena u lidi, co na Javu prejdou z jinych jazyku. Podle me se mel uz na zacatku pridat operator === ktery by interne byl prekladan na == pro primitivni typy a na .equals pro objektove typy, ale holt to v Jave neni, takze je kod ukecanejsi, nez bych si osobne predstavoval.
-
Nicmene uz operator == ma chovani stejne jako pro ostatni objekty, tj. porovnava reference, coz vede ke spatne odhalitelnym chybam, zejmena u lidi, co na Javu prejdou z jinych jazyku.
Chyba se udělala už tehdy, když se operátor == pro objekty udělal blbě na porovnávání pointerů na instanci a ne na porovnávání obsahů instancí, tak jak by se normální člověk dle selského rozumu domníval podle chování 1 == 1. V dnešním stavu máme jeden operátor s dvěma různými chováními a to nutně muselo skončit průšvihem.
Vyřešit už to patrně nepůjde, není to bug ale feature.
-
Pokud jde o == vs. equals, tak tohle je taky dobrá sranda:
Long x = 5L;
Long y = 5L;
System.out.println(x == y); // true
Long a = 1000L;
Long b = 1000L;
System.out.println(a == b); // false
Ale o tomhle jsem se bavit nechtěl.
kvuli deserializaci
Je možné rozvést?
-
Chyba se udělala už tehdy, když se operátor == pro objekty udělal blbě na porovnávání pointerů na instanci a ne na porovnávání obsahů instancí, tak jak by se normální člověk dle selského rozumu domníval podle chování 1 == 1. V dnešním stavu máme jeden operátor s dvěma různými chováními a to nutně muselo skončit průšvihem.
To je castecne dusledek samotne existence primitivnich datovych typu. Jazyk by byl peknejsi, kdyby v nem vubec nebyly, ale zase by se nedaly nektere veci naprogramovat tak efektivne. Asi by bylo hezci, kdyby se napriklad == prekladalo na equals a pro porovnani "pointeru" by byl jiny operator, ale dopady se prehaneji, viz "to nutně muselo skončit průšvihem". Osobně jsem chybu související s tímto "problémem" myslím nikdy neudělal a v práci jsem ji viděl naposledy před několika lety u naprostého začátečníka - začátečníci ale dělají i spousty dalších chyb. Mnohem víc mi chybí třeba elvis operátory.
-
kvuli deserializaci
Je možné rozvést?
Porno umis na netu najit sam nebo ti s tim pomaha maminka?
-
kvuli deserializaci
Je možné rozvést?
Porno umis na netu najit sam nebo ti s tim pomaha maminka?
Ne, natáčíme si vlastní.
Sorry, že jsem si dovolil na diskuzním fóru položit dotaz, to se asi nesmí.
-
kvuli deserializaci
Jenže konstruktor bez argumentů pro deserializaci Serializable objektů není vůbec potřeba.
-
serializacia nepotrebuje no-arg konstruktor, to len pri dedicnosti, co ocividne nie je pripad stringu
http://www.jguru.com/faq/view.jsp?EID=251942
* odchadza tocit Das Java Dämon III. *
-
No nevím, přijde mi jako celkem základní věc, že konstruktorem se objekt vytváří v nějakém výchozím stavu na základě parametrů, zatímco při deserializaci se *obnovuje* *jakýkoli* jeho stav ze surových dat. Některé jazyky (Objective C) mají to konstruování ještě explicitnější - operace alloc (alokace paměti - provede se jednou) a init (inicializace stavu - může se provést teoreticky i víckrát nad stejným objektem).
Takže Lenin buď vidí do nějakých souvislostí, které jsou nám smrtelníkům utajeny, nebo prostě zase plácá. Což si může dovolit, protože - jak jsme již mnohokráte byli informování - on sockou nelítá - a o to jde.
-
No nevím, přijde mi jako celkem základní věc, že konstruktorem se objekt vytváří v nějakém výchozím stavu na základě parametrů, zatímco při deserializaci se *obnovuje* *jakýkoli* jeho stav ze surových dat. Některé jazyky (Objective C) mají to konstruování ještě explicitnější - operace alloc (alokace paměti - provede se jednou) a init (inicializace stavu - může se provést teoreticky i víckrát nad stejným objektem).
Takže Lenin buď vidí do nějakých souvislostí, které jsou nám smrtelníkům utajeny, nebo prostě zase plácá. Což si může dovolit, protože - jak jsme již mnohokráte byli informování - on sockou nelítá - a o to jde.
Plácá, viz jednoduchý příklad s vlastním objektem, na kterém je zřejmé, že při deserializaci se konstruktor nepoužije:
public class MyClass implements Serializable {
private int value;
private MyClass() {
value = 1;
}
public MyClass(String value) {
this.value = Integer.valueOf(value) * 2;
}
public int getA() {
return value;
}
public void setA(int a) {
this.value = a;
}
}
public class Main {
public static void main(String[] args) throws Exception {
MyClass myClass1 = new MyClass("10");
FileOutputStream fileOut = new FileOutputStream("myclass.ser");
ObjectOutputStream out = new ObjectOutputStream(fileOut);
out.writeObject(myClass1);
out.close();
fileOut.close();
System.out.println("myClass1: " + myClass1.getA());
MyClass myClass2 = null;
FileInputStream fileIn = new FileInputStream("myclass.ser");
ObjectInputStream in = new ObjectInputStream(fileIn);
myClass2 = (MyClass) in.readObject();
in.close();
fileIn.close();
System.out.println("myClass2: " + myClass2.getA());
}
}
Výstup:
myClass1: 20
myClass2: 20
-
Nehovoriac o tom, že Stringy sa i tak serializujú špecifickým spôsobom. Serializácia bežne vbuchne do streamu všetky inštančné premenné (a naopak, pri deserializácii ich vyplní zo streamu) ale OpenJDK má vlastný spôsob:
Class String is special cased within the Serialization Stream Protocol.
A String instance is written initially into an ObjectOutputStream in the
following format:
TC_STRING (utf String)
The String is written by method `DataOutput.writeUTF`.
A new handle is generated to refer to all future references to the
string instance within the stream.
---------------
Z iného súdka: ten copy constructor (public String(String s)) má svoj zmysel. Mamička mi našla, že:
http://hanuska.blogspot.com/2006/03/how-useful-is-stringstring-constructor.html
V skratke: ak vrátite z obrovského Stringu maličký substring, tak ten navrátený String stále odkazuje na pôvodné obrovské pole bajtov. V takom prípade je lepšie vyrobiť radšej novú inštanciu cez copy constructor a obrovský String sa môže radostne zgarbagecollectovať.
-
V skratke: ak vrátite z obrovského Stringu maličký substring, tak ten navrátený String stále odkazuje na pôvodné obrovské pole bajtov. V takom prípade je lepšie vyrobiť radšej novú inštanciu cez copy constructor a obrovský String sa môže radostne zgarbagecollectovať.
O tom už byla řeč v prvním příspěvku.
-
Z iného súdka: ten copy constructor (public String(String s)) má svoj zmysel. Mamička mi našla, že:
http://hanuska.blogspot.com/2006/03/how-useful-is-stringstring-constructor.html
V skratke: ak vrátite z obrovského Stringu maličký substring, tak ten navrátený String stále odkazuje na pôvodné obrovské pole bajtov. V takom prípade je lepšie vyrobiť radšej novú inštanciu cez copy constructor a obrovský String sa môže radostne zgarbagecollectovať.
Pokud je opravdu potreba zamezit sdileni bufferu, tak bych "copy constructor" nedoporucoval. Dokumentace API pozadovane chovani nijak nezarucuje (podobne jako nezarucuje sdileni pri substring, to je jen optimalizace). Ze to tak je implementovane v konkretnich zdrojacich (napr OpenJDK) je fajn, ale jinde to muze byt jinak. Pokud je potreba zarucene zamezit sdileni, tak vhodne reseni je treba
new String(s.toCharArray())
ktere jednoduse to kopirovani (chceme kopirovani, kdyz nam vadi sdileni) vynucuje
-
Ono je to (viacmenej) povedané v dokumentácii:
Initializes a newly created String object so that it represents the same sequence of characters as the argument; in other words, the newly created string is a copy of the argument string. Unless an explicit copy of original is needed, use of this constructor is unnecessary since Strings are immutable.
Ale je pravda, že nechce by som byť v situácii, keď zistím, že niekto natvrdo využil toto chovanie v nejakom programe a nezadokumentoval to :-)
-
Chyba se udělala už tehdy, když se operátor == pro objekty udělal blbě na porovnávání pointerů na instanci a ne na porovnávání obsahů instancí, tak jak by se normální člověk dle selského rozumu domníval podle chování 1 == 1. V dnešním stavu máme jeden operátor s dvěma různými chováními a to nutně muselo skončit průšvihem.
To je castecne dusledek samotne existence primitivnich datovych typu. Jazyk by byl peknejsi, kdyby v nem vubec nebyly, ale zase by se nedaly nektere veci naprogramovat tak efektivne. Asi by bylo hezci, kdyby se napriklad == prekladalo na equals a pro porovnani "pointeru" by byl jiny operator, ale dopady se prehaneji, viz "to nutně muselo skončit průšvihem". Osobně jsem chybu související s tímto "problémem" myslím nikdy neudělal a v práci jsem ji viděl naposledy před několika lety u naprostého začátečníka - začátečníci ale dělají i spousty dalších chyb. Mnohem víc mi chybí třeba elvis operátory.
Ja jsem na tu chybu narazil pri oprave programu, kde nekdo udelal (nevim jakym nastrojem, mozna jen rucne) refactoring ve stylu, ze nahradil v nejake metody paramerty foo(int a, int b) za foo(Integer a, Integer b). Ono mu to "magicky" fungovalo diky unboxingu pro prakticky vsechny operatory i prirazeni, ale ouha ve chvili, kdy tam bylo neco na zpusob if (a==b) .... Prekladac s tim kodem byl spokojeny, zadne warningy atd. No prislo se na to relativne rychle, ale i tak...
-
Pokud jde o == vs. equals, tak tohle je taky dobrá sranda:
Long x = 5L;
Long y = 5L;
System.out.println(x == y); // true
Long a = 1000L;
Long b = 1000L;
System.out.println(a == b); // false
Jojo, na to je potreba dat pozor a vedet, jak se vlastne v Jave implementuje autoboxing - zde se vola Long.valueOf() a u nej je jasne napsane, ze NEMUSI vytvaret nove instance Longu, ale muze pouzit hodnoty cachovane. Ktere to jsou, je jiz implementacni detail, coz dela celou situaci jeste horsi :-)
-
1. bultin java serializaci prakticky nikdo nepouziva. Polozme si otazku proc existuje aspon 20 serializacnich frameworku.
2. jednoduchy priklad je z poloviny blbe. Dodelat, souvisi s 1.
3. Prymek, lichoti mi ze mi zavidis letadlo. Vzhledem k tomu ze se odmitas zmenit, tak si nevydelas ani blbech 50 tisic na cessnu 172.
Rekni si, kdyz prachy umi vydelavat i takovej trouba jako lenin, tak ja chytrej kluk to dokazu taky. Je to jednoduchy, jen to vyzaduje uplne jiny zpusob mysleni nez ktery ma 95% populace. Bylo napsano hodne knizek o tom jak se to dela. Precti si nejakou.
-
A ako to súvisí s prázdnym konštruktorom Stringu?
Ja nechápem, prečo, pán Lenin POWER! ,dokážete jednu informáciu natiahnuť cez dvadsať* arogantných príspevkov s pochybnou kredibilitou, keď stačí napísať "v XStreame na tom stavajú, lebo sa im nechce reflektovať." [teraz trepem]
Dokážete dať aspoň jeden relevantný príklad?
--------
* číslo som vytiahol z brucha rovnako ako počet serializačných frameworkov
-
new musi vzdy vytvorit novou instanci
Pravda, pravda. Příkaz new vracející referenci na existující instanci by asi nebyl to pravé ořechové (byť to v jiných jazycích jde). Mimochodem:
"Ahoj" == new String("Ahoj") // false
"Ahoj" == new String("Ahoj").intern() // true
"" == new String("") // false
"" == new String("").intern() // true
"" == new String() // false
"" == new String().intern() // true
-
1. bultin java serializaci prakticky nikdo nepouziva. Polozme si otazku proc existuje aspon 20 serializacnich frameworku.
Položme si zajímavější otázku: když built-in serializace prázdný konstruktor nepotřebuje, k čemu ho nutně potřebují ty frameworky?
3. Prymek, lichoti mi ze mi zavidis letadlo. Vzhledem k tomu ze se odmitas zmenit, tak si nevydelas ani blbech 50 tisic na cessnu 172.
Rekni si, kdyz prachy umi vydelavat i takovej trouba jako lenin, tak ja chytrej kluk to dokazu taky. Je to jednoduchy, jen to vyzaduje uplne jiny zpusob mysleni nez ktery ma 95% populace. Bylo napsano hodne knizek o tom jak se to dela. Precti si nejakou.
Ty máš asi pořád pocit, že ti všichni všechno závidí :) Jestli to potřebuješ k nějaké svojí osobnostní integritě, nemám problém tě podpořit: já ti tak závidím ty letadla!
Rekni si, kdyz prachy umi vydelavat i takovej trouba jako lenin, tak ja chytrej kluk to dokazu taky. Je to jednoduchy, jen to vyzaduje uplne jiny zpusob mysleni nez ktery ma 95% populace. Bylo napsano hodne knizek o tom jak se to dela. Precti si nejakou.
Přečetl jsem si jednu knížku, ve které mě zaujalo tohle:
Když se rozmnožuje jmění, množí se i příživníci. Jaký prospěch z toho mívá vlastník? Ledaže se na to může dívat.
Sladký je spánek toho, kdo pracuje, ať jí málo nebo mnoho, ale boháčovi nedopřeje spánku sytost.
Je zlý neduh, který jsem pod sluncem viděl: vlastníkovi je ke zlému bohatství, jež střeží.
Po úmorné lopotě může o bohatství přijít a syn, jehož zplodil, stojí s prázdnou rukou.
Jako vyšel z života své matky, nahý zase odchází, jak přišel, a za svoje pachtění si nic neodnese, ani co by se do ruky vešlo.
A také to je zlý neduh: Každý odejde, jak přišel; jaký užitek má z toho, že se pachtil a honil vítr?
-
1. bultin java serializaci prakticky nikdo nepouziva. Polozme si otazku proc existuje aspon 20 serializacnich frameworku.
Když otázka, tak s odpovědí: Ve starších verzích Javy byla nativní serializace pomalá, proto vznikla spousta alternativních serializačních frameworků. Java 6 už má ovšem nativní serializaci tak rychlou že používání těch proprietárních frameworků ztrácí význam.
-
1. bultin java serializaci prakticky nikdo nepouziva. Polozme si otazku proc existuje aspon 20 serializacnich frameworku.
Položme si zajímavější otázku: když built-in serializace prázdný konstruktor nepotřebuje, k čemu ho nutně potřebují ty frameworky?
Built-in serializace podvádí za vydatné podpory JVM. Framework může vytvořit objekt za použití prázdného konstruktoru a pak ho "dodělat" pomocí java.lang.reflect.*.
-
A čo potom java.lang.Long-y a java.lang.Integer-y?
-
alef0: Long je delsi, nez Integer, alokuje si vice pameti
-
Narážal som na to, že Long nemá verejný bezparametrový konštruktor.
-
Built-in serializace podvádí za vydatné podpory JVM. Framework může vytvořit objekt za použití prázdného konstruktoru a pak ho "dodělat" pomocí java.lang.reflect.*.
To ale není důvod k tomu, aby každý objekt měl povinně bezparametrický konstruktor - a o tom je řeč.
-
Napadlo mě, že smysl tohohle defaultního kontruktoru bude asi podobný jako u jeho obdoby u java.lang.Object.
Vytvořit si instanci obyčejného Objectu samo o sobě nemá moc smysl, leda bych si potřeboval držet privátní objekt, o které vím, že je unikátní. V praxi jsem to viděl aplikované asi jenom pro synchronizační zámek:
private final Object lock = new Object();
Teoreticky by se mohl podobným způsobem definovat také privátní unikátní klíč do IdentityHashMap.
A aby to nebylo tak jednoduché, tak jsou 3 způsoby jak vyrobit prázdný string:
String s = "";
String s = new String();
String s = new String("");
A každý z nich funguje jinak. :D
-
Napadlo mě, že smysl tohohle defaultního kontruktoru bude asi podobný jako u jeho obdoby u java.lang.Object.
To těžko - z důvodů, o kterých tady už byla řeč: http://www.jguru.com/faq/view.jsp?EID=34802
-
A aby to nebylo tak jednoduché, tak jsou 3 způsoby jak vyrobit prázdný string:
String s = "";
String s = new String();
String s = new String("");
A každý z nich funguje jinak. :D
Prazdny string jde vytvorit mnohem vice zpusoby. Co to znamena, ze kazdy ze zpusobu funguje jinak? V cm to "neni jednoduche"? A neco z toho vyplyva?
-
A aby to nebylo tak jednoduché, tak jsou 3 způsoby jak vyrobit prázdný string:
String s = "";
String s = new String();
String s = new String("");
A každý z nich funguje jinak. :D
Prazdny string jde vytvorit mnohem vice zpusoby. Co to znamena, ze kazdy ze zpusobu funguje jinak? V cm to "neni jednoduche"? A neco z toho vyplyva?
Jo, těch konstruktorů tam je kopec, ale tyhle tři případy výše se liší v principu, (asi) všechny ostatní už jsou obdobné.
Literál "" se bere ze string poolu. Druhý případ vyrobí nový objekt, který má vlastní (nové) interní char pole. Třetí vyrobí nový string objekt, ale bude mít char pole sdílené s prvním. Viz výpis identity-hashcodů:
""
String hashCode: 30223967
char[] hashCode: 18903403
new String()
String hashCode: 14978587
char[] hashCode: 19770577
new String("")
String hashCode: 28117098
char[] hashCode: 18903403
-
1. bultin java serializaci prakticky nikdo nepouziva. Polozme si otazku proc existuje aspon 20 serializacnich frameworku.
Položme si zajímavější otázku: když built-in serializace prázdný konstruktor nepotřebuje, k čemu ho nutně potřebují ty frameworky?
Built-in serializace podvádí za vydatné podpory JVM. Framework může vytvořit objekt za použití prázdného konstruktoru a pak ho "dodělat" pomocí java.lang.reflect.*.
No vidite, tak jste na to prisli. Pokud jde o objekt varianty typu ala Integer, tak ty se diky efektivite serializuji jako primitivni typy a ne jako jejich objekt varianty.
-
No vidite, tak jste na to prisli. Pokud jde o objekt varianty typu ala Integer, tak ty se diky efektivite serializuji jako primitivni typy a ne jako jejich objekt varianty.
Aha, mně to hnedka nedošlo, máš úplnou pravdu! Natix se ptal, proč autoři Javy do API ten konstruktor dali - a ono to bylo takhle:
A: Ty hele, ta naše serializace je zatraceně pomalá!
B: To je v poho, vyrojí se spousta knihoven, který to budou dělat líp.
A: No jo, jenže nebudou potřebovat String()?
B: No, my to obcházíme neveřejnýma funkcema...
A: Tak jim tam ten String() dáme, ať nám tu serializaci můžou udělat pořádně!
Tak to jo.
Stejně to ale museli být pěkní vohnouti, když to vyřešili takhle, místo aby udělali pořádný rozhraní umožňující custom serializaci...
No ale hlavně že to teda už vím a můžu už googlit jenom porno.
-
Framework může vytvořit objekt za použití prázdného konstruktoru a pak ho "dodělat" pomocí java.lang.reflect.*.
Jak konkrétně by se dal dodělat?
-
....
-1 bod za naše diskuze o IPv6, ale +10 bodů za tenhle post ;D
-
Framework může vytvořit objekt za použití prázdného konstruktoru a pak ho "dodělat" pomocí java.lang.reflect.*.
Jak konkrétně by se dal dodělat?
Nejspíš myslel vytvořit "prázdný" objekt "prázdným" konstruktorem a pak nastavit všechny vlastnosti pomocí java.lang.reflect.Field nebo tak něco...
Tahle myšlenka má jednu drobnou vadu: nemá to absolutně žádnou souvislost s tím, proč má String neparametrický konstruktor. (Nebudeme snad doufám tvrdit, že ho má proto, abysme mohli vytvořit prázdný String a potom ho pomocí reflect.Field změnit...)
-
Nejspíš myslel vytvořit "prázdný" objekt "prázdným" konstruktorem a pak nastavit všechny vlastnosti pomocí java.lang.reflect.Field nebo tak něco...
No což o to, já vím, jak to myslel. Spíše mne ale zajímá, pokud to jde udělat, tak jak? Hodil by se prostě přiklad kódu.
-
No což o to, já vím, jak to myslel. Spíše mne ale zajímá, pokud to jde udělat, tak jak? Hodil by se prostě přiklad kódu.
No hlavně to nejde udělat u Stringu, takže to je úplně mimo mísu. Stejně pro jakýkoli String obecně musím mít nějaké speciální zacházení, takže nechápu, proč bych to speciální zacházení neměl mít ausgerechnet u prázdnýho Stringu...
Ale už bych se v tom nerejpal, tahle debata je ujetá.
Podle mě to do API dali prostě proto, že to nic nestojí a asi jim to připadalo logciký. A jestli to má nějaký využití? No v hodně mokrých snech asi jo...
-
A: Ty hele, ta naše serializace je zatraceně pomalá!
Deserializace je extremne pomala, java serializace je sice tak o rad pomalejsi nez ostatni frameworky, ale to by se jeste sneslo, ne kazdy projekt hodne serializuje. Vykon je jen jeden z duvodu proc se nepouziva, precti si dokumentaci k nejakemu frameworku co za ostatni problemy se pokousi resit.
Stejně to ale museli být pěkní vohnouti, když to vyřešili takhle, místo aby udělali pořádný rozhraní umožňující custom serializaci...
Je tam Externalizable, ale to se pouziva jeste mene nez Serializable, protoze kdyz si nekdo chce psat custom serializaci tak to napise uz poradne s vyuzitim nejakeho dobreho frameworku, ktery poskytuje vice funkci.
Pro stringy ten vyse zmineny postup funguje. Omez to porno a zacni na sobe makat.
Pro inspiraci nejaky ty frameworky http://code.google.com/p/thrift-protobuf-compare/wiki/Benchmarking
-
K puvodni otazce tazatele, k cemu konstruktor bez parametru u stringu. Pokud vim, Java ma generiku a tam je preci jen fajn vedet, ze new E() projde i pro String a nemusim na to vymyslet extraburty.
Skoda ze v C++ to neni jednoznacne. Treba mohu napsat new T() ale funguje to i pro std::string ale kdyz T je treba int, pak hodnota toho objektu je undefined.
-
K puvodni otazce tazatele, k cemu konstruktor bez parametru u stringu. Pokud vim, Java ma generiku a tam je preci jen fajn vedet, ze new E() projde i pro String a nemusim na to vymyslet extraburty.
Skoda ze v C++ to neni jednoznacne. Treba mohu napsat new T() ale funguje to i pro std::string ale kdyz T je treba int, pak hodnota toho objektu je undefined.
new E()??? A to by podle tebe udelalo co? Za predpokladu, ze by se to vubec prelozilo...
-
new E() v Javě napsat nejde díky type erasure
-
No nic, vidím, soudruhu Lenine, že jsi výhrady vůči mimoběžnosti tvého plkání k původní otázce buď nepochopil nebo nevzal v potaz.
Když dovolíš, nemusím na sobě v tomhle ohledu makat, protože v Javě nedělám a dělat nechci. Jednak nejsem primárně programátor, jednak v současnosti používám hlavně Erlang. I ne úplně dobrá znalost Javy stačí na to, aby člověk poznal, jak vaříš z vody.
S dovolením komunikaci s tebou končím, nic mi nedává.
-
Hlavne: objekty je v Jave nutne porovnavat vzdy pres metodu equals. Tyka se to i typu String.
Prazdny konstruktor s char(0) bych typoval na pozustatek z C++.
-
<flame>Aha, koukám, že jsem si myslel o generice v Javě víc, než je schopna. Další důvod, proč Javu nepoužívat</flame>
-
<flame>Aha, koukám, že jsem si myslel o generice v Javě víc, než je schopna. Další důvod, proč Javu nepoužívat</flame>
Aha, koukam, ze o generikach v jave nic nevis. Souhlasim, ze je to duvod, proc bys je nemel pouzivat.
-
Aha, koukam, ze o generikach v jave nic nevis. Souhlasim, ze je to duvod, proc bys je nemel pouzivat.
Je to pravda, že generika v javě jsou v podstatě jenom syntaktický cukr - všechno se provádí jenom při překladu a v runtime už je všechno přeložený v podstatě stejně, jako by to bylo v době, kdy ještě generika neexistovala?
To by pak měl Ondra celkem pravdu, že to je nuda...
-
Je to pravda, že generika v javě jsou v podstatě jenom syntaktický cukr - všechno se provádí jenom při překladu a v runtime už je všechno přeložený v podstatě stejně, jako by to bylo v době, kdy ještě generika neexistovala?
To by pak měl Ondra celkem pravdu, že to je nuda...
Mě jen přepkvapuje, že to řešili právě takto. Přitom si myslím, že by neměl být pro překladač problém vygenerovat kód namíru, tak jak to dělá C++ (malé zjednodušení pro ty, kteří nevědí, jak to funguje v C++, tak si představte trochu vymakanější makra v Cčku).
Momentálně by mě třeba zajímalo, jak v Javě řeší generické továrny objektů, když nefunguje new E ... ale to je v celku fuk.
-
Aha, koukam, ze o generikach v jave nic nevis. Souhlasim, ze je to duvod, proc bys je nemel pouzivat.
Je to pravda, že generika v javě jsou v podstatě jenom syntaktický cukr - všechno se provádí jenom při překladu a v runtime už je všechno přeložený v podstatě stejně, jako by to bylo v době, kdy ještě generika neexistovala?
To by pak měl Ondra celkem pravdu, že to je nuda...
Jestli te zajima, k cemu jsou a jak funguji generika v jave, tak si precti jeden z milionu clanku, ktere o tom existuji. Problem spociva v psani nesmyslu do diskuse k tematu, o kterem dotycny nic nevi (ze konstruktor bez parametru se vyuzije pro generika). At si napise blog "ma predstava o jave, kterou neznam, a jaky ma vztah k C++, ktere znam" a tam se muze zevrubne prozkoumat, proc tu javu udelali tak blbe.
-
Jestli te zajima, k cemu jsou a jak funguji generika v jave, tak si precti jeden z milionu clanku, ktere o tom existuji. Problem spociva v psani nesmyslu do diskuse k tematu, o kterem dotycny nic nevi (ze konstruktor bez parametru se vyuzije pro generika). At si napise blog "ma predstava o jave, kterou neznam, a jaky ma vztah k C++, ktere znam" a tam se muze zevrubne prozkoumat, proc tu javu udelali tak blbe.
Bezvadné vyhození z místnosti :D
Okaj, omlouvám se, netušil jsem, že tohle v Javě nejde. Nicméně pak se nedivím té diskuzi předtím o serializačních frameworcích. Když vidím třeba workaround nemožnosti udělat new na generický typ... doporučení zavolat class.newInstance(), tak ... prominte, musím si odskočit na záchod (chybí tu patřičný smajlík)
Google mi vyplivl taky toto:
http://docs.oracle.com/javase/6/docs/api/java/lang/reflect/Constructor.html
kde newInstance volá konstruktor podle parametrů. Předpokládám, že bude volat String() konstruktor, pokud mu tam předložím třídu String a žádné parametry.
-
Na rozdiel od .NETu, kde sú generiká aj v čase behu, v Jave sa rozhodli to naozaj spraviť v záujme spätnej kompatibility. To má presne dôsledky ako "nemožno spraviť new E", "nemožno sa spýtať, aký typu je prvok List<T>" a podobne, proste všetko je to v čase behu java.lang.Object. Z týchto všetkých vecí ma to až tak neotravuje, asi najdivšia vec bola nemožnosť urobiť pole generických prvkov.
-
Jestli te zajima, k cemu jsou a jak funguji generika v jave, tak si precti jeden z milionu clanku, ktere o tom existuji. Problem spociva v psani nesmyslu do diskuse k tematu, o kterem dotycny nic nevi (ze konstruktor bez parametru se vyuzije pro generika). At si napise blog "ma predstava o jave, kterou neznam, a jaky ma vztah k C++, ktere znam" a tam se muze zevrubne prozkoumat, proc tu javu udelali tak blbe.
Bezvadné vyhození z místnosti :D
Okaj, omlouvám se, netušil jsem, že tohle v Javě nejde. Nicméně pak se nedivím té diskuzi předtím o serializačních frameworcích. Když vidím třeba workaround nemožnosti udělat new na generický typ... doporučení zavolat class.newInstance(), tak ... prominte, musím si odskočit na záchod (chybí tu patřičný smajlík)
Google mi vyplivl taky toto:
http://docs.oracle.com/javase/6/docs/api/java/lang/reflect/Constructor.html
kde newInstance volá konstruktor podle parametrů. Předpokládám, že bude volat String() konstruktor, pokud mu tam předložím třídu String a žádné parametry.
Nikoho nevyhazuju, na to ani nemam prostredky. Pouze je mym nazorem, ze kdyz necemu nerozumim, tak se k tomu nevyjadruju, nebo si nejprve alespon udelam alespon minimalni prehled. Ty ovsem o generikach v jave vis pouze to, ze se tak jmenuji. Posun na uroven, na ktere by ses mohl smysluplne vyjadrit v teto diskusi by ti pritom zabral maximalne 10 minut.
A k veci. Ano pochopitelne lze pomoci reflexe zavolat kontruktor String() - proc by to nemelo jit? Diskuse byla v podstate o tom, ze pokud stejne musim vedet, ze jde o tridu String a jeji konstruktor bez parametru, a zaroven je zaruceno, ze tento konstruktor musi vratit novou instanci, ktera je obsahove shodna s konstantou prazdny retezec, tak mohu rovnou vratit konstantu prazdny retezec a na volani konstruktoru se vybodnout. Tedy by se zdalo, ze se bez tohoto konstruktoru da obejit a odtud puvodni otazka, proc tam vlastne je. A at uz je duvod jakykoliv, napriklad zjednoduseni pro ruzne, ne nutne pouze serializacni frameworky, jiste tento duvod nijak nesouvisi s generiky.
-
Diskuse byla v podstate o tom, ze pokud stejne musim vedet, ze jde o tridu String a jeji konstruktor bez parametru, a zaroven je zaruceno, ze tento konstruktor musi vratit novou instanci, ktera je obsahove shodna s konstantou prazdny retezec, tak mohu rovnou vratit konstantu prazdny retezec a na volani konstruktoru se vybodnout. Tedy by se zdalo, ze se bez tohoto konstruktoru da obejit a odtud puvodni otazka, proc tam vlastne je.
No výborně. Od odboček jsme se vrátili zpátky k tématu. Přesně kvůli tomuhle, co píšeš, nechápu, proč by ten konstruktor měl být nutný - pro String beztak potřebuju speciální zacházení, takže místo String() tam můžu dát prostě "".
-
No výborně. Od odboček jsme se vrátili zpátky k tématu. Přesně kvůli tomuhle, co píšeš, nechápu, proč by ten konstruktor měl být nutný - pro String beztak potřebuju speciální zacházení, takže místo String() tam můžu dát prostě "".
Nikdo netvrdi, ze je ten konstruktor nutny. Na druhou stranu ma rekneme smysluplnou semantiku (zadny vstup = prazdny string), tak proc by tam nemel byt? Pro jine tridy smysluplna semantika neni, tak takovy konstruktor nemaji (napr. BigDecimal). V beznem programu se to smysluplne nepouzije, ale jestli se nekde v existujicim kodu, treba pouzivajicim reflexi, pouziva, tak proc by se to melo necim nahrazovat. Konstruktor proste dela to co ma, vetsina pouziti bude asi chyba (zbytecne vytvarim instanci, kdyz ji nepotrebuju), ale to je chyba spise jen stylu, realny dopad na vykon muze mit pouze ve specifickych pripadech.
-
Aha, koukam, ze o generikach v jave nic nevis. Souhlasim, ze je to duvod, proc bys je nemel pouzivat.
Je to pravda, že generika v javě jsou v podstatě jenom syntaktický cukr - všechno se provádí jenom při překladu a v runtime už je všechno přeložený v podstatě stejně, jako by to bylo v době, kdy ještě generika neexistovala?
To by pak měl Ondra celkem pravdu, že to je nuda...
Ano a ne :) Ze signatur metody informace o generikach pri prekladu skutecne "zmizi". Takze napriklad void test1(List) a void test2(List<String>) budou mit shodnou signaturu. Ovsem v bajtkodu se ta informace ve skutecnosti zachova ve forme metadat (nechci tady pouzit slovo atribut, ktere ma bohuzel jiny vyznam v ceskem OOP zargonu), coz si hlida prekladac ve chvili, kdyz se nekde jinde vola mujObjekt.test1() a mujObjekt.test2(). Takze erasure zajisti jednodussi a zpetne kompatibilni volani metod - pamatujme na to, ze Java je novy COBOL :) - a na druhou stranu to zajistuje alespon nejakou typovou bezpecnost.
Co me osobne vadi vice je fakt, ze generika (resp. ty typy) nejsou kovariantni, i kdyz by podle me mohly byt :/
-
Na rozdiel od .NETu, kde sú generiká aj v čase behu, v Jave sa rozhodli to naozaj spraviť v záujme spätnej kompatibility. To má presne dôsledky ako "nemožno spraviť new E", "nemožno sa spýtať, aký typu je prvok List<T>" a podobne, proste všetko je to v čase behu java.lang.Object. Z týchto všetkých vecí ma to až tak neotravuje, asi najdivšia vec bola nemožnosť urobiť pole generických prvkov.
Na druhou stranu je treba diky tomu implementace Clojure pro JVM mnohem snazsi nez v .NET, takze je to neco za neco :)
-
Ovsem v bajtkodu se ta informace ve skutecnosti zachova ve forme metadat [...], coz si hlida prekladac ve chvili, kdyz se nekde jinde vola mujObjekt.test1() a mujObjekt.test2().
To je zajimava informace - o jaký přesně metadata se jedná? Jak se to správně jmenuje (abych si o tom mohl něco vygooglit)?
A dá se s těmi metadaty nějak softwarově pracovat? Když např. z nějakého zdroje dostanu obecný objekt a chci za běhu zjistit, jakého je typu, můžu nějak zjistit, jestli je to List<X> nebo List<Y>?
A jak je to s tou (obecnou) factory? Když mu předám obecný objekt, dá se vytvořit nová instance? Jde to nějak přibližně takhle?
Object neznamyObjekt = nepredvidatelnyZdrojObjektu.getNext();
Constructor[] constructors = neznamyObjekt.getClass().getConstructors();
[...výběr bezparametrického konstruktoru...]
Object neznamyObjekt2 = constructor.newInstance();
Co me osobne vadi vice je fakt, ze generika (resp. ty typy) nejsou kovariantni, i kdyz by podle me mohly byt :/
Jak přesně se tohle projevuje? Že List<X> nemůžu předat někam, kde se očekává List? To je asi blbost že? Všechno je to za běhu List. Teď si nějak neumím představit, o co jde :)
Na druhou stranu je treba diky tomu implementace Clojure pro JVM mnohem snazsi nez v .NET, takze je to neco za neco :)
V čem přesně je snazší?
(dík za odpovědi - u většiny z nich bude stačit třeba i jenom nasměrování na článek, vhodnou google frázi nebo tak něco :)
-
Jak přesně se tohle projevuje? Že List<X> nemůžu předat někam, kde se očekává List? To je asi blbost že? Všechno je to za běhu List. Teď si nějak neumím představit, o co jde :)
...nebo že do metoda(List<X>) bych měl mít možnost předat parametr typu List<Y> za předpokladu, že Y je podtřída X?
-
Jak přesně se tohle projevuje? Že List<X> nemůžu předat někam, kde se očekává List? To je asi blbost že? Všechno je to za běhu List. Teď si nějak neumím představit, o co jde :)
...nebo že do metoda(List<X>) bych měl mít možnost předat parametr typu List<Y> za předpokladu, že Y je podtřída X?
To jde pokud metodu deklarujete takto: metoda(List<? extends X>)
-
To jde pokud metodu deklarujete takto: metoda(List<? extends X>)
Aha. Ale nemělo by to jít automaticky bez berliček? Není to trochu krkolomné? (silně na mě z toho vane duch C++ ;)
-
To jde pokud metodu deklarujete takto: metoda(List<? extends X>)
Aha. Ale nemělo by to jít automaticky bez berliček? Není to trochu krkolomné? (silně na mě z toho vane duch C++ ;)
To není berlička ale nutnost. Nastudujte si rozdíl mezi List<? extends X> a List<? super X> a pochopíte.
-
To není berlička ale nutnost. Nastudujte si rozdíl mezi List<? extends X> a List<? super X> a pochopíte.
Mluvím o tom, že celá tahle konstrukce se mi nelíbí. Považoval bych za normální, že Ypsilonem můžu Xko nahradit v jakémkoli kontextu bez toho, abych to někomu nějak zvlášť dával najevo.
-
Ovsem v bajtkodu se ta informace ve skutecnosti zachova ve forme metadat [...], coz si hlida prekladac ve chvili, kdyz se nekde jinde vola mujObjekt.test1() a mujObjekt.test2().
To je zajimava informace - o jaký přesně metadata se jedná? Jak se to správně jmenuje (abych si o tom mohl něco vygooglit)?
A dá se s těmi metadaty nějak softwarově pracovat? Když např. z nějakého zdroje dostanu obecný objekt a chci za běhu zjistit, jakého je typu, můžu nějak zjistit, jestli je to List<X> nebo List<Y>?
A jak je to s tou (obecnou) factory? Když mu předám obecný objekt, dá se vytvořit nová instance? Jde to nějak přibližně takhle?
Object neznamyObjekt = nepredvidatelnyZdrojObjektu.getNext();
Constructor[] constructors = neznamyObjekt.getClass().getConstructors();
[...výběr bezparametrického konstruktoru...]
Object neznamyObjekt2 = constructor.newInstance();
Co me osobne vadi vice je fakt, ze generika (resp. ty typy) nejsou kovariantni, i kdyz by podle me mohly byt :/
Jak přesně se tohle projevuje? Že List<X> nemůžu předat někam, kde se očekává List? To je asi blbost že? Všechno je to za běhu List. Teď si nějak neumím představit, o co jde :)
Na druhou stranu je treba diky tomu implementace Clojure pro JVM mnohem snazsi nez v .NET, takze je to neco za neco :)
V čem přesně je snazší?
(dík za odpovědi - u většiny z nich bude stačit třeba i jenom nasměrování na článek, vhodnou google frázi nebo tak něco :)
Generiky v bajtkodu:
http://docs.oracle.com/javase/specs/jls/se7/html/jls-4.html#jls-4.4
http://docs.oracle.com/javase/specs/jls/se7/html/jls-4.html#jls-4.8
Neni to uplne jednoduchy cteni, zkusim se o tom nekdy rozepsat (sam to budu muset ted nastudovat do vetsi hloubky, nez je zdravo :)
Ad kovariance: je to treba ukazano zde: http://www.ibm.com/developerworks/java/library/j-jtp01255/index.html
Dovedu pochopit, proc to je takto navrzeno, ale z hlediska OOP (kde mame Integer extends Number a Float extends Number - dosadte si libovolnou jinou cast ze stromu hierarchiche) to cloveka nekdy prekvapi.
-
Mluvím o tom, že celá tahle konstrukce se mi nelíbí. Považoval bych za normální, že Ypsilonem můžu Xko nahradit v jakémkoli kontextu bez toho, abych to někomu nějak zvlášť dával najevo.
Tedy bych si deklaroval List<Y> a predal ho metode, ktera pracuje s List<X>. Ta by do nej pridala instanci tridy Z (ktera je rovnez potomkem X). Potom bych postupne zpracoval prvky sveho List<Y> a volal na nich metody tridy Y. Co by se stalo, az bych narazil na instaci tridy Z? Kde by byla slibovana typova kontrola? Pro nazornost si dosadme treba X=Number, Y=BigDecimal, Z=Short.
-
Generiky v bajtkodu:
http://docs.oracle.com/javase/specs/jls/se7/html/jls-4.html#jls-4.4
http://docs.oracle.com/javase/specs/jls/se7/html/jls-4.html#jls-4.8
Neni to uplne jednoduchy cteni, zkusim se o tom nekdy rozepsat (sam to budu muset ted nastudovat do vetsi hloubky, nez je zdravo :)
Uff, tak to je na mě fakt moc velkej guláš, to si raději počkám na ten článek (předem díky ;)
Ad kovariance: je to treba ukazano zde: http://www.ibm.com/developerworks/java/library/j-jtp01255/index.html
Dovedu pochopit, proc to je takto navrzeno, ale z hlediska OOP (kde mame Integer extends Number a Float extends Number - dosadte si libovolnou jinou cast ze stromu hierarchiche) to cloveka nekdy prekvapi.
Jasně, tak to jsem pochopil správně. Jo, je to docela matoucí - hlavně ta nekonzistence s Array.
-
Aby byla třída JavaBean, musí mít i konstruktor bez parametrů, viz. http://en.wikipedia.org/wiki/JavaBeans (http://en.wikipedia.org/wiki/JavaBeans)
;)
-
Tedy bych si deklaroval List<Y> a predal ho metode, ktera pracuje s List<X>. Ta by do nej pridala instanci tridy Z (ktera je rovnez potomkem X). Potom bych postupne zpracoval prvky sveho List<Y> a volal na nich metody tridy Y. Co by se stalo, az bych narazil na instaci tridy Z? Kde by byla slibovana typova kontrola? Pro nazornost si dosadme treba X=Number, Y=BigDecimal, Z=Short.
U Array to nevadí? :)
-
U Array to nevadí? :)
Ne nevadi. BTW jak Array souvisi s generiky a jejich typovou bezpecnosti?
-
U Array to nevadí? :)
Tohle se u polí kontroluje, viz ArrayStoreException.
-
Tedy bych si deklaroval List<Y> a predal ho metode, ktera pracuje s List<X>. Ta by do nej pridala instanci tridy Z (ktera je rovnez potomkem X). Potom bych postupne zpracoval prvky sveho List<Y> a volal na nich metody tridy Y. Co by se stalo, az bych narazil na instaci tridy Z? Kde by byla slibovana typova kontrola? Pro nazornost si dosadme treba X=Number, Y=BigDecimal, Z=Short.
U Array to nevadí? :)
Čistě z pohledu typového systému jsou kovariantní pole špatně a invariantní generiky správně. Ovšem use-site variance je peklo na druhou...
-
Ne nevadi. BTW jak Array souvisi s generiky a jejich typovou bezpecnosti?
No tak, že to, co u generik vůbec nejde, to u Array jde, ale vyvolá to runtime výjimku.
-
Čistě z pohledu typového systému jsou kovariantní pole špatně a invariantní generiky správně. Ovšem use-site variance je peklo na druhou...
Můžeš trochu rozvést důvody? (pokud možno tak, abych to jako ne-fulltime programátor, ne-javista pochopil :)
-
Čistě z pohledu typového systému jsou kovariantní pole špatně a invariantní generiky správně. Ovšem use-site variance je peklo na druhou...
Můžeš trochu rozvést důvody? (pokud možno tak, abych to jako ne-fulltime programátor, ne-javista pochopil :)
U generik je to správně proto že kontroly provádí přímo kompilátor. U polí je to špatně protože kompilátor nekontroluje a může to tedy vést k pádům programů za běhu, což je přesně to co by silně typový jazyk neměl dovolovat. No a to že je to jednou tak a podruhé tak je prostě to peklo na druhou...
-
No tak, že to, co u generik vůbec nejde, to u Array jde, ale vyvolá to runtime výjimku.
A prave proto, ze by to vyvolalo behovou vyjimku, to u generik nejde, coz jsem se snazil vysvetlit. Tam by to vadilo, protoze generika zarucuji, ze k behove vyjimce nedojde, protoze se nesoulad typu objevi uz pri prekladu - to je ostatne hlavni prinos generik. Pole to nezarucuji a proto to u nich nevadi, kazdy proste vi/mel by vedet, ze k takove situaci muze dojit. Princip typove kontroly poli a generik je uplne jiny, coz je sice sveho druhu "souvislost", podle mne ale vzhledem k tematu generik irelevantni.
-
U generik je to správně proto že kontroly provádí přímo kompilátor. U polí je to špatně protože kompilátor nekontroluje a může to tedy vést k pádům programů za běhu, což je přesně to co by silně typový jazyk neměl dovolovat. No a to že je to jednou tak a podruhé tak je prostě to peklo na druhou...
Ok, hledal jsem za tím něco složitějšího. Jestli je to správně, to nevím. Je to prostě tak :) Má to taky své nevýhody a v jiných jazycích se to afaik řeší jinak.
A prave proto, ze by to vyvolalo behovou vyjimku, to u generik nejde, coz jsem se snazil vysvetlit. Tam by to vadilo, protoze generika zarucuji, ze k behove vyjimce nedojde, protoze se nesoulad typu objevi uz pri prekladu - to je ostatne hlavni prinos generik. Pole to nezarucuji a proto to u nich nevadi, kazdy proste vi/mel by vedet, ze k takove situaci muze dojit. Princip typove kontroly poli a generik je uplne jiny, coz je sice sveho druhu "souvislost", podle mne ale vzhledem k tematu generik irelevantni.
No takže u polí to vadí taky, ale tam to "každý ví" :)
-
Pokud jde o generické wildcards, tak tam se člověk hodně rychle dostane do situací, kdy se mu dělají uzly na mozku. :P
Jen tak pro zajímavost:
- do List<? extends Number> nemůžu nic vložit, maximálně null
- z List<? super Number> nemůžu odebírat, respektive mám zaručeno pouze to, že tyto objekty budou implementovat lava.lang.Object
Naštěstí existuje docela použitelná mnemotechnická pomůcka od Joshe Blocha: PECS - Producer Extends, Consumer Super
Nicméně už jenom přijít na to, co je ten producent a konzument, je občas problém. Pak to vede na úchvatné signatury metod typu:
public static <T extends Comparable<? super T>> void sort(List<T> list)
-
A prave proto, ze by to vyvolalo behovou vyjimku, to u generik nejde, coz jsem se snazil vysvetlit. Tam by to vadilo, protoze generika zarucuji, ze k behove vyjimce nedojde, protoze se nesoulad typu objevi uz pri prekladu - to je ostatne hlavni prinos generik. Pole to nezarucuji a proto to u nich nevadi, kazdy proste vi/mel by vedet, ze k takove situaci muze dojit. Princip typove kontroly poli a generik je uplne jiny, coz je sice sveho druhu "souvislost", podle mne ale vzhledem k tematu generik irelevantni.
No takže u polí to vadí taky, ale tam to "každý ví" :)
Pouzij prosim hlavu a zamysli se nad tim, co znamena, kdyz neco zarucuje specifikace - to proste fungovat MUSI. U poli to mozna subjektivne vadi tobe, ale to je trochu jiny smysl slova "vadit". Nekompatibilita poli a generik je problem, ktery realne nastava minimalne. V 99% uloh neni zadny duvod pouzivat pole misto kolekci a nedoporucuje se to (napr. proto, ze pole jsou z principu vzdy modifikovatelna). Pole maji misto tam, kde je potreba vysoky vykon, predevsim ve vztahu k primitivnim typum.
-
Pak to vede na úchvatné signatury metod typu:
public static <T extends Comparable<? super T>> void sort(List<T> list)
No dyť jsem říkal, že z toho na mě dýchá C++ ;)
-
@kuka: asi si nerozumíme. Chtěl jsem říct, že ve mně budí podezření jazyky, kde A funguje nějak a B, které je A velmi podobné, funguje úplně opačně - ale zároveň komunita tvrdí, že to, jak B funguje, je bomba.
-
V 99% uloh neni zadny duvod pouzivat pole misto kolekci a nedoporucuje se to (napr. proto, ze pole jsou z principu vzdy modifikovatelna). Pole maji misto tam, kde je potreba vysoky vykon, predevsim ve vztahu k primitivnim typum.
Pole se bohužel používají zcela běžně jako varargy...
Dále jsou běžné v různých API včetně těch základních (java.*, javax.*) a kolekce jsou koneckonců implementované nad nimi (a celé praktické používání generik je pak zajištěno tím že jsou na implementacích vypnuté pomocí @SuppressWarning, což je dost drsný hack).
Bohužel toho všeho se nedá jen tak jednoduše vyřešit bez problémů se zpětnou kompatabilitou nebo novou "paralelní" verzí jazyka. A v tom případě je lepší prostě použít zbrusu nový jazyk. Například Groovy, Scala, Clojure.
-
Pak to vede na úchvatné signatury metod typu:
public static <T extends Comparable<? super T>> void sort(List<T> list)
No dyť jsem říkal, že z toho na mě dýchá C++ ;)
To je matematika (viz http://en.wikipedia.org/wiki/Covariance_and_contravariance_(computer_science) (http://en.wikipedia.org/wiki/Covariance_and_contravariance_(computer_science))), takže to tak nějak dopadnout musí (dokonce ani přesun do jiného vesmíru nepomůže).
-
@kuka: asi si nerozumíme. Chtěl jsem říct, že ve mně budí podezření jazyky, kde A funguje nějak a B, které je A velmi podobné, funguje úplně opačně - ale zároveň komunita tvrdí, že to, jak B funguje, je bomba.
Aha, podezreni neni to, o cem bych se chtel bavit, natoz o komunite. Ja jsem chtel pouze vysvetlit, proc neni spravna tvoje uvaha, ze "pro Y potomka X bych List<Y> mel mit moznost pouzit kdekoliv, kde List<X>, aniz bych to nejak specialne daval najevo". Bud se to povedlo, nebo nepovedlo, ale vic k tomu asi neni co rict.
-
Aha, podezreni neni to, o cem bych se chtel bavit, natoz o komunite.
Ok, nemám důvod to dál rozpitvávat.