PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : [java] generics


Unfug
2006-02-13, 00:47:24
Hallo,wenn ich sowas hier habe
public class ShoppingCartElement<P extends Product>

was bedeutet das? Ich hab dann ja einen "neuen Datentyp" P richtig?

Also könnte ich in der Klasse irgendwo machen:
P producta; Nur was bringt mir das? Ich versteh das nicht so.Oder ist jetzt auch die ganze Klasse vererbt von Product?? :confused:

Pinoccio
2006-02-13, 01:09:03
Ich habe keine Ahnung von Generics. Aber vielleicht hilft das (http://de.wikipedia.org/wiki/Generische_Programmierung_in_Java_5.0).

mfg Sebastian

DocEW
2006-02-13, 01:40:07
Stell es dir als eine Art zusätzlichen (Konstruktor-)Parameter vor, der besagt, mit was für einer Art von Java-Klassen diese Klasse "umgeht". In deinem Fall hieße "umgeht" soviel wie "aufnimmt", der ShoppingCart nimmt Produkte auf.

Weitere Beispiel findest du beim Link von Pinoccio.

Monger
2006-02-13, 09:03:14
Generische Typen sind ein wenig knifflig. Das Problem ist, dass generische Typen keine Vererbung kennen (dürfen). Lies dir mal das hier durch: http://java.sun.com/j2se/1.5/pdf/generics-tutorial.pdf


Ich muss da auch immer wieder nachschlagen, weil diese Art von Logik einfach schwer in den Kopf reingeht. Im Prinzip geht es darum, dass du dem Compiler irgendwie klarmachen musst was genau du mit dem Generic vorhast, damit er richtig damit umgehen kann.

"extends" hat in diesem Zusammenhang eben NICHTS mit Vererbung zu tun, sondern erweitert die Menge alle anwendbaren Tyxpen.

DocEW
2006-02-13, 10:28:44
"extends" hat in diesem Zusammenhang eben NICHTS mit Vererbung zu tun, sondern erweitert die Menge alle anwendbaren Tyxpen.
Die Logik geht aber noch finde ich:
Im Beispiel oben arbeitet das ShoppingCartElement halt mit irgendwas, was "mindestens" ein Product ist, oder irgendwas noch spezielleres. Von daher hat es mit Vererbung natürlich ne Menge zu tun, hehe... ;) Aber ist klar, was du meintest.

HellHorse
2006-02-13, 10:38:14
Ich hab dann ja einen "neuen Datentyp" P richtig?
Nö, du hast einen Datentyp ShoppingCartElement<P>, wobei P etwas beliebiges sein kann, was von Product erbt, z.B. ShoppingCartElement<Book>.

In diesem Fall sehe ich den Sinn von Generics nicht, vermutlich hat einfach irgend jemand Polymorphismus nicht geschnallt oder wollte umbedingt Generics anwenden.

Ich versteh das nicht so.Oder ist jetzt auch die ganze Klasse vererbt von Product?? :confused:
Nö, so sie es aussieht von Object.

Unfug
2006-02-13, 11:44:19
Danke,
dann werd ich mich mal durch den ganzen kram da durchwurschteln.

DocEW
2006-02-13, 16:33:49
In diesem Fall sehe ich den Sinn von Generics nicht, vermutlich hat einfach irgend jemand Polymorphismus nicht geschnallt oder wollte umbedingt Generics anwenden.
Kannst du das bitte etwas näher erläutern, ich verstehe das nicht.
Ist doch nützlich, man spart sich doch die Definition eines Interface, oder? Oder wie soll man das Vorhandensein von Methoden an dieser Stelle sonst "vertraglich absichern"?

HellHorse
2006-02-13, 18:32:29
Kannst du das bitte etwas näher erläutern, ich verstehe das nicht.
Ist bloss so ein Gefühl. Ich müsste den Code sehen, der es verwendet.

Du hast ein ShoppingCartElement, welches ein Product behinhaltet. So weit so gut.
Wie viele sinnvolle Fälle kannst du dir nun Vorstellen, in denen ein Klient wissen muss, dass es sich um ein ShoppingCartElement<Book> und nicht um ein ShoppingCartElement<VideoTape> handelt? Wir reden hier ja von Code, der unterschiedliche ShoppingCartElemente verarbeitet und nicht von Code, der Books verarbeitet.
Sollte es nicht viel mehr reichen zu wissen, dass in dem SchoppingCart ein Product ist (hoffentlich ein Interface) und alle notwendigen Operationen dort definiert sein?

DocEW
2006-02-13, 18:45:18
Das ShoppingCartElement weiß ja so auch nur, daß ein Produkt drin ist, es sei denn es macht instanceof. Das ist ja nicht der Punkt, oder?

Den Vorteil sehe ich darin, daß man sagen kann "... soll mit allem klarkommen, was ein Produkt ist.", auch ohne ein Interface zu definieren. Wobei... was ist denn, wenn man ShoppingCartElement<Product> macht? Kann man deine Books einfügen..??

c.p.d.
2006-02-13, 19:59:23
bei generics gehts vornehmlich um typsicherheit.

So kann man z.B. Collectoren (vector, etc) bei der Instanzierung (sprich zur Laufzeit) mitteilen, welche Klassen (Typen) im Collector gespeichert werden sollen.
Hat man dies einmal definiert, so kann man nur noch Objekte dieses Typs dem Collector hinzufuegen (bzw. entfernen). Der praktische Nutzen daraus ist, dass man nicht mehr wie wild im zeugs rumcasten muss (was ja nicht so schoen sein soll :)).

zeckensack
2006-02-14, 02:19:53
Das ShoppingCartElement weiß ja so auch nur, daß ein Produkt drin ist, es sei denn es macht instanceof. Das ist ja nicht der Punkt, oder?

Den Vorteil sehe ich darin, daß man sagen kann "... soll mit allem klarkommen, was ein Produkt ist.", auch ohne ein Interface zu definieren. Wobei... was ist denn, wenn man ShoppingCartElement<Product> macht? Kann man deine Books einfügen..??Es ergibt keinen Sinn. Ein Buch ist ein mögliches ShoppingCartElement und jedes mögliche ShoppingCartElement ist ein "Product". Von daher sind hier zumindest die Generics fehl am Platze.
Evtl ist sogar die ganze Kapselung überflüssig. Anstatt mit ShoppingCartElements zu hantieren, kann man doch gleich mit Products hantieren ... es sei denn -- Vorsicht: Supermarktanalogie -- man will wissen in welcher Reihenfolge die Produkte im Einkaufswagen gestapelt sind. Aber selbst dann ist es schwaches Design, denn diese Art Wissen steht nur einem Container zu.

Vielleicht ist die Klasse einfach nur blöd benannt. Vielleicht ist zB ShoppingCartElement ein Container für mehrere Produkte. Und selbst dann ist es wieder blöd, denn der Container muss polymorphe Produkte speichern können. Durch die Generics wird es erlaubt Container für nur Bücher und Container für nur Hühnerbrustfilets anlegen, nur wozu sollte man das wollen?

Oooooooder ... da war sich jemand nicht ganz klar über Instanzen und Typen. ZB könnte man auf die Idee kommen zu sagen, ja, wir führen das Produkt "Milch in Tüten", aber in den Einkaufswagen kommt nicht das Produkt, sondern ein Exemplar dieses Produkts. Err. *kreisch*

Summa summarum IMO Anfänger-OOP vom feinsten.

DocEW
2006-02-14, 02:51:42
Also diese Sinnfragen finde ich immer ein bißchen anstrengend... man kann sowieso nicht sagen, ob es nicht irgend einen Fall gibt, wo es halt doch Sinn macht.

Weißt du eine Antwort auf meine Frage? Kann man in ein ShoppingCartElement<Product> eine Klasse einfügen, was von Product abgeleitet ist? Ok, ich könnte es auch ausprobieren... aber jetzt ist's mir gerade zu spät dazu. :D

ScottManDeath
2006-02-14, 03:32:46
Weißt du eine Antwort auf meine Frage? Kann man in ein ShoppingCartElement<Product> eine Klasse einfügen, was von Product abgeleitet ist? Ok, ich könnte es auch ausprobieren... aber jetzt ist's mir gerade zu spät dazu. :D

Klar, das Product soll ja nur ein Constraint sein, was der Typ erfüllen muss, damit man dessen Interface nutzen kann. Für Container reicht meist das Interface von Object. In C# ist das IMHO etwas günstiger gelöst, das sieht das z.B. so aus.

public classScene<TAccelerationStructure> : Scene
where TAccelerationStructure : Acceleration.AccelerationStructure, new()
{
}

zeckensack
2006-02-14, 03:37:23
Also diese Sinnfragen finde ich immer ein bißchen anstrengend... man kann sowieso nicht sagen, ob es nicht irgend einen Fall gibt, wo es halt doch Sinn macht.

Weißt du eine Antwort auf meine Frage? Kann man in ein ShoppingCartElement<Product> eine Klasse einfügen, was von Product abgeleitet ist? Ok, ich könnte es auch ausprobieren... aber jetzt ist's mir gerade zu spät dazu. :DOhne den restlichen Code, oder zumindest die Methodendeklarationen der Klasse, wird dir niemand diese Frage beantworten können.

Aber: wenn zB Kartoffelsack von Product erbt, und du ein Objekt vom Typ ShoppingCartElement <Kartoffelsack> erzeugst, ist für dieses Objekt P nur noch Kartoffelsack. Dort wo die ShoppingCartElement-Klasse ein P erwartet, werden von diesem konkreten SCE-Objekt andere von Product geerbte Typen oder Product selbst nicht mehr akzeptiert.

DocEW
2006-02-14, 10:55:32
Danke für eure Antworten!

P.S.: Und ich dachte, ICH gehe spät ins Bett... ;)

grandmasterw
2006-02-14, 11:11:30
Ist in der Tat recht eigenartig. Das einzig Sinnvolle, das ich mir vorstellen kann, ist, dass das ShoppingCartElement eine Gruppe gleichartiger Produkte ist. So à la "Mainboard X" als Element,und dann 3 davon in der Liste. Warum man das aber so doppelt schachteln sollte, is mir auchn Rätsel.

ScottManDeath
2006-02-14, 14:56:42
Danke für eure Antworten!

P.S.: Und ich dachte, ICH gehe spät ins Bett... ;)

Also ich habe meine Post 19:32:46 Ortszeit abgesetzt ;)

DocEW
2006-02-14, 16:01:41
Also ich habe meine Post 19:32:46 Ortszeit abgesetzt ;)
Ach ja richtig, bist ja da drüben... ;)

Wanginator
2006-02-14, 22:37:15
Es gibt meistens einen Sinn, warum man Generics einsetzt um eine gewisse Polymorphie zu garantieren. Die Logik dahinter, bes. die Typverträglichkeiten sind teilweise eigenartig, aber sie dienen nur dazu, dass man mit den Generics nichts wildes undefiniertes anstellen kann.

Der Codeschnipsel
public class ShoppingCartElement<P extends Product>
hat auch einen Sinn, ein ShoppingCartElement (als Menge interpretiert) enthält halt ein Product oder ein Untertyp von Product. Angenommen Product ist ein Interface, dann kann ein ShoppingCartElement alles enthalten, was das Product-Interface implementiert.

Weiterer möglicher Sinn: Haben wir ein List<P extends Product> und nehmen wir eins raus, haben wir keine Ahnung was es ist, es ist aber garantiert ein Product. Und somit kann man mit dem Interfacetyp Product als statischen Typ weiter arbeiten. Ohne Generics müsste man hier mit Object arbeiten oder wild rumcasten. Und gerade das sollen die Generics ja vermeiden zu stabileren/sicheren Programmierung.

HellHorse
2006-02-14, 22:54:33
Mann, das ist ja schlimm hier.

So kann man z.B. Collectoren (vector, etc) bei der Instanzierung (sprich zur Laufzeit) mitteilen, welche Klassen (Typen) im Collector gespeichert werden sollen.
Zur Laufzeit ist von generics _gar nichts_ mehr da (ausser dem cast, den der Compiler eingefügt hat). Bitte lern noch mal was Generics sind.
Der Codeschnipsel
public class ShoppingCartElement<P extends Product>
hat auch einen Sinn, ein ShoppingCartElement ist halt ein Product oder ein Untertyp von Product.
NEIN! Bitte lern noch mal was generics sind.

Geneics fügen null Typsicherheit hinzu, sie sparen casts die dafür der Compiler einfügt, das ist auch schon alles.

grandmasterw
2006-02-14, 23:17:30
Weiterer möglicher Sinn: Haben wir ein List<P extends Product> und nehmen wir eins raus, haben wir keine Ahnung was es ist, es ist aber garantiert ein Product. Und somit kann man mit dem Interfacetyp Product als statischen Typ weiter arbeiten. Ohne Generics müsste man hier mit Object arbeiten oder wild rumcasten. Und gerade das sollen die Generics ja vermeiden zu stabileren/sicheren Programmierung.

Das hab ich mir auch zuerst gedacht, aber es is Unsinn. Das was du meinst, ist ein "ShoppingCart<P extends Product>", also ein Container, der eben ein par ShoppingCart-spezifische Sachen kann, die ein Vector nicht kann, und natürlich Untertypen von Product enthält. Es ist jedoch anzunehmen, dass ein ShoppingCartElement nur ein Trum ist, und man das einfach ganz normal von Product ableiten könnte.

Wanginator
2006-02-14, 23:32:19
@HellHorse: Ja, das war Mist. Aber ich habs auch schon editiert gleich nachdem ich es gepostet hab. Meinte "enthält" nicht "ist" :)

@grandmasterw: bei einem Element ist das natürlich richtig. Aber man weiß ja nie was die Implementierung von dem "Ding" ist :) . Namen sind halt Schall und Rauch!

ScottManDeath
2006-02-15, 00:25:38
Mann, das ist ja schlimm hier.


Zur Laufzeit ist von generics _gar nichts_ mehr da (ausser dem cast, den der Compiler eingefügt hat). Bitte lern noch mal was Generics sind.

NEIN! Bitte lern noch mal was generics sind.

Geneics fügen null Typsicherheit hinzu, sie sparen casts die dafür der Compiler einfügt, das ist auch schon alles.

D.h. ich kann zur Laufzeit keinen generischen Typ nehmen, den dann über Reflektion mit einem anderen Typ als T bevölkern, und dann nutzen. Dann sind die .NET generics doch anders als die von Java, oder auch C++.

zeckensack
2006-02-15, 02:27:31
D.h. ich kann zur Laufzeit keinen generischen Typ nehmen, den dann über Reflektion mit einem anderen Typ als T bevölkern, und dann nutzen.Rüchtüch :)
edit: (wenn T vom konkreten "generischen" Basistypen erbt, geht's allerdings schon)Dann sind die .NET generics doch anders als die von Java, oder auch C++.Nicht unbedingt ... wenn du in C++ einen std::vector <KartoffelSack> anlegst, gilt das gleiche wie bei den Java-Generics: du kannst nur noch Objekte des Typs Kartoffelsack oder geerbte Typen in diesen konkreten std::vector einfügen. Nicht jedoch Superklassen von KartoffelSack (im Beispiel "Product").

Es existiert IMO genau das gleiche "Problem" wie mit den Java Generics. Dieses "Problem" ist überhaupt der Sinn der Sache.

ScottManDeath
2006-02-15, 06:00:39
Klar, C++ sind auf der einen Seite mächtiger als die .NET generics (man kann alles reinstopfen und es kracht beim kompilieren, wenn z.B. die Methodennamen nicht stimmen; Metaprogrammierung geht auch nur so), auf der anderen Seite aber auch schwächer, da die Metadaten verloren gehen.

In .NET lade ich mir z.B. eine Assembly, kralle mir einen generic Type, binde z.B. einen meiner eigenen Typen daran, erstellen dann davon eine Instanz und kann damit dann arbeiten, ohne überhaupt zu wissen, was für ein generic Type ich da habe. Wird natürlich sinnvoller, wenn der generic Type z.b. Interfaces implementiert, oder eben Constraints hat, so dass ich eben im generic Type auch Methoden von Object Subklassen nutzen kann. Was ich doof finde ist, dass es zwar IComparable interfaces gibt, aber keine Möglichkeit, Operatoren des Typparameters zu nutzen. :(

Geht mein Szenario mit Java?

Monger
2006-02-15, 08:29:11
Geht mein Szenario mit Java?

Nein. Die Generics sind im Grunde nur ein (wenn auch ziemlich schöner) Compiler Hack. Zur Laufzeit bleibt von den Generics rein gar nichts mehr übrig. Mit Bindungen zur Laufzeit sieht es in Java allgemein ziemlich schlecht aus.

So wie ich das sehe, konzentriert sich Java mehr darauf, zum Zeitpunkt der Compilierung möglichst typsicher zu sein. C# hat eine ganze Reihe von Features, die Sicherheit zur Laufzeit verbessern sollen. Dazu gehören z.B. auch die Delegates, die Java ja überhaupt nicht kennt.

del_4901
2006-02-15, 10:56:34
Naja man könnte Polymorphie nutzen, um den von Generics erzeugten Code dann zur Laufzeit jeh nach Typ zu wechseln.
Das Überladen allein reicht dafür meißt aus. wenns zu häufig wird, könnte man überlegen ob eine Vererbungsvariante nicht klüger ist.

Trap
2006-02-15, 14:57:58
Dazu gehören z.B. auch die Delegates, die Java ja überhaupt nicht kennt.
Sun ist der Meinung dass Java schon eine bessere Alternative enthält:
http://java.sun.com/docs/white/delegates.html

Coda
2006-02-15, 15:06:45
Also vom überfliegen her ist das ein einfaches Observer-Pattern. Delegates sind schon eleganter imho.

Gast
2006-02-15, 15:21:12
Geneics fügen null Typsicherheit hinzu, sie sparen casts die dafür der Compiler einfügt, das ist auch schon alles.

Öhm, da irrst du dich leider gewaltig. Generics tragen sehr wohl zur Typsicherheit bei und zwar zur Compile-Time. Im Gegensatz zu einem Object, kann man eben einen spezifischen Typen, für z.B. Collections angeben. Wie schnell passiert es denn, dass man bei einem Type-Cast, den falschen Typen angibt? Der Compiler sagt nichts dazu. Mit Generics, kann soetwas aber rechtzeitig erkannt werden.

Monger
2006-02-15, 15:23:56
Sun ist der Meinung dass Java schon eine bessere Alternative enthält:
http://java.sun.com/docs/white/delegates.html

Ich habs mir mal durchgelesen, aber mein Verständnis reicht nicht wirklich aus, um den Wahrheitsgehalt dieser Aussagen beurteilen zu können.

Gefühlsmäßig geht es mir zuwider, eine Methode auszuführen dessen Kontext ich gar nicht kenne. Für mich ist eine Methode immer nur Bestandteil eines Objektes. Das ist ja bei den Delegates nicht anders, aber der Delegate weiß ja nicht, was er da gerade ausführt. Das irritiert mich persönlich ein bißchen.
Ich vermute, dass MS die Delegates eingeführt hat, weil die umsteigenden C++ Entwickler gerne eine Art Funktionspointer haben wollten, und auf C++ bin ich nicht wirklich gut zu sprechen. ;)


Gibt es irgendeinen Fall, wo Delegates besser wären? Mir fehlt gerde die Kreativität, mir ein passendes Szenario auszudenken.

Coda
2006-02-15, 15:32:24
Für Event-Handling ist das schon angenehmer als einen Observer zu benützen. In C++ gehen Funktionspointer auf Memberfunktionen übrigens gar nicht so einfach, da braucht man einiges boost-magic dafür.

muhkuh_rs
2006-02-15, 15:40:21
Rüchtüch :)
edit: (wenn T vom konkreten "generischen" Basistypen erbt, geht's allerdings schon)Nicht unbedingt ... wenn du in C++ einen std::vector <KartoffelSack> anlegst, gilt das gleiche wie bei den Java-Generics: du kannst nur noch Objekte des Typs Kartoffelsack oder geerbte Typen in diesen konkreten std::vector einfügen. Nicht jedoch Superklassen von KartoffelSack (im Beispiel "Product").


Ich weiß ja nicht wie das bei Java ist, kann mich noch dunkel erinnern, dass eigentlich immer nur Rreferenzen existieren. Wenn man jedoch in C++ einen std::vector<A> anlegegt, dann kann man zwar auch von Klasse A abgeletete Objectinstanzen reinpacken, jedoch geht alles flöten, was die abgeleitete Klasse mehr als A hatte. Das Dürfte selten sinnvoll sein.

HellHorse
2006-02-15, 18:04:37
D.h. ich kann zur Laufzeit keinen generischen Typ nehmen, den dann über Reflektion mit einem anderen Typ als T bevölkern, und dann nutzen.
Du hast zur Laufzeit gar keine Möglichkeit rauszufinden was T ist/war. Du kannst einen gerischen Typ bevölkern mit was du willst (innerhalb der upper bound) und niemand, ganz besonders nicht der Compiler, kann dich davon abhalten.
Dann sind die .NET generics doch anders als die von Java, oder auch C++.
Gaynau

Nicht unbedingt ... wenn du in C++ einen std::vector <KartoffelSack> anlegst, gilt das gleiche wie bei den Java-Generics: du kannst nur noch Objekte des Typs Kartoffelsack oder geerbte Typen in diesen konkreten std::vector einfügen. Nicht jedoch Superklassen von KartoffelSack (im Beispiel "Product").
Doch gayt leider. Enweder über Reflection oder unchecked cast.
Meinte "enthält" nicht "ist" :)
Wofür wie gesagt generics völlig unnötig sind, da Variablen in Java schon so polymorph sind.
Öhm, da irrst du dich leider gewaltig. Generics tragen sehr wohl zur Typsicherheit bei und zwar zur Compile-Time.
Im Gegensatz zu einem Object, kann man eben einen spezifischen Typen, für z.B. Collections angeben. Wie schnell passiert es denn, dass man bei einem Type-Cast, den falschen Typen angibt? Der Compiler sagt nichts dazu.
Mit Generics, kann soetwas aber rechtzeitig erkannt werden.
Wie schon gesagt, generics führen dazu, dass der Compiler automatisch ein paar casts hinzufügt, die du selbst nicht mehr hinzufügen musst.

ScottManDeath
2006-02-15, 18:22:02
Also vom überfliegen her ist das ein einfaches Observer-Pattern. Delegates sind schon eleganter imho.

Jo, obwohl erst anonyme delegates den anonymen Java listenern gleich kommen. Jetzt kann ich endlich mein Heightfield on the fly mit Werten füllen im Konstruktor, ohne extra einen benannten delegate zu bauen :)

Jetzt sieht das in C# 2.0 nahezu genauso aus wie in Java mit den anonymen Listenern (das Paper scheint schon etwas älter zu sein. Datum war nicht dabei). Im Vergleich zu C# 1.0 ist das doch angenehmer zum Arbeiten, siehe folgende Beispiele:



root.Add
(
new HeightField
(
delegate(HeightField.FunctionParameter g)
{
float d0 = 4.0f* Vector.Length(g.Parameter - new Vector2(0.25f,0.25f));
float d1 = 8.0f* Vector.Length(g.Parameter - new Vector2(0.25f,0.75f));
float d2 = 16.0f * Vector.Length(g.Parameter - new Vector2(0.75f, 0.25f));
float d3 = 32.0f * Vector.Length(g.Parameter - new Vector2(0.75f, 0.75f));
float pp0 = 1.0f;
float pp1 = 2.0f;
float pp2 = 4.0f;
float pp3 = 8.0f;
double rr = Math.Sin(2.0f * Math.PI * d0 +pp0) + Math.Sin(2.0f * Math.PI * d1 +pp1) + Math.Sin(2.0f * Math.PI * d2+pp2) + Math.Sin(2.0f * Math.PI * d3+pp3);
return (float)rr;
},
400,
400,
new Vector3(-60.0f, -60.0f, -10.0f),
new Vector3(40.0f, 40.0f, -8.0f)
),
hfmatl
);



List<LeafNode> leaves = Root.GetLeaves();
leaves.ForEach
(
delegate( LeafNode node)
{
if (node.VolumeMaterial == null)
node.VolumeMaterial = InitialVolume;
}
);

Gast
2006-02-15, 19:23:00
Sun ist der Meinung dass Java schon eine bessere Alternative enthält:
http://java.sun.com/docs/white/delegates.html
Das Ding ist ja steinalt; die Antwort von Microsoft stammt jedenfalls von 1998:
http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/dnarvj/html/msdn_deltruth.asp

Gast
2006-02-15, 19:31:06
Wie schon gesagt, generics führen dazu, dass der Compiler automatisch ein paar casts hinzufügt, die du selbst nicht mehr hinzufügen musst.
Der andere Gast wollte auf was anderes hinaus:
ArrayList myList = new ArrayList();
myList.Add(new Typ1());
...
Typ2 foo = (Typ2) myList[0];Das wird erst zur Laufzeit krachen, läßt sich aber problemlos kompilieren.

Anders wenn man Generics verwendet:
List myList = new List()<Typ1>;
myList.Add(new Typ1());
...
Typ2 foo = myList[0];Das läßt sich erst gar nicht kompilieren.

Monger
2006-02-15, 20:25:33
Für Event-Handling ist das schon angenehmer als einen Observer zu benützen.

Wenn ich so drüber nachdenke, sind die Java Listener wirklich etwas hässlich. Ich hab ein kleines Programm, das schon mit etlichen Knöpfen zurechtkommen muss. Meine Oberfläche besteht deshalb zu 80% aus EventHandlern, und dementsprechend ziemlich vielen inneren Classes.

Deshalb bastel ich ungern an grafischen Oberflächen rum: man betreibt relativ viel Aufwand für relativ wenig Wirkung. Mir macht es mehr Spaß, in der Programmlogik rumzuwühlen.

Coda
2006-02-15, 20:38:49
Am schönsten dafür finde ich die signals und slots von Qt.

HellHorse
2006-02-15, 21:30:14
Der andere Gast wollte auf was anderes hinaus:
ArrayList myList = new ArrayList();
myList.Add(new Typ1());
...
Typ2 foo = (Typ2) myList[0];Das wird erst zur Laufzeit krachen, läßt sich aber problemlos kompilieren.

Anders wenn man Generics verwendet:
List myList = new List()<Typ1>;
myList.Add(new Typ1());
...
Typ2 foo = myList[0];Das läßt sich erst gar nicht kompilieren.

List<Typ1> myList = new List()<Typ1>;
myList.add(new Typ1());
List<Typ2> myList2 = (List<Typ2>)(List<?>)myList;
...
Typ2 foo = myList2.get(0);

RoKo
2006-02-15, 23:15:29
List<Typ1> myList = new List()<Typ1>;
myList.add(new Typ1());
List<Typ2> myList2 = (List<Typ2>)(List<?>)myList;
...
Typ2 foo = myList2.get(0);
Der Unterschied ist allerdings, dass Dein Beispiel niemals jemand aus Versehen machen würde. Das Beispiel vom Gast ist mir hingegen selber schon oft genug passiert, mit Generics nicht mehr - ergo bessere Typsicherheit, wenn auch nur praktisch und nicht theoretisch.

In C++ gehen Funktionspointer auf Memberfunktionen übrigens gar nicht so einfach, da braucht man einiges boost-magic dafür.
Die Syntax mag zwar schwer zu merken sein, aber weshalb brauche ich da Boost?

ScottManDeath
2006-02-15, 23:41:35
Die Syntax mag zwar schwer zu merken sein, aber weshalb brauche ich da Boost?

Weils damit sexy und kompakt wird :)


Beispiel aus meinem Log system. In m_loggers kann man verschiede 'Listeners', reinstecken, die die Informationen z.b. and die Konsole ausgegben, in eine Datei speichern, filtern,.... Dazu muss ich alle 'Events' wie z.B. Exceptions, Messages ... an alle Elemente in m_loggers verteilen.

Mit boost::bind und boost::lambda sieht das dann so aus:


void Log::ThrowException(const SourceLocation& loc,const Exception& _exception)
{
for_each(m_loggers.begin(),m_loggers.end(), bind(&LoggerBase::OnThrowException,_1,loc,_exception,GetDateNow(),GetTimeNow()));
}

RoKo
2006-02-16, 00:45:40
Weils damit sexy und kompakt wird :)
Ahso, das ist schon klar, mit Boost wird vieles sexy und kompakt :)

Gast
2006-02-16, 01:18:10
List<Typ1> myList = new List()<Typ1>;
myList.add(new Typ1());
List<Typ2> myList2 = (List<Typ2>)(List<?>)myList;
...
Typ2 foo = myList2.get(0);
Worauf willst Du hinaus? Daß ich in der ersten Zeile vergessen habe, den Typ anzugeben? Okay, mein Fehler. Warum du aber die C#-Syntax durch Java ersetzen willst, ist mir ein Rätsel.

HellHorse
2006-02-16, 09:54:35
Worauf willst Du hinaus?
Dass die angebliche compiletime Sicherheit von generics nur unter gewissen Umständen zutrifft. Diese Umstände sind zufälligerweise genau die Fälle, in denen casten in <= 1.4 auch schon funktionierte ;). Schlussendlich ändert sich eigentlich gar nichts. Generics verhindern nichts was nicht auch schon mit <= 1.4 möglich war und ermöglichen nichts, was mit <= 1.4 unmöglich war. Es wirklich nur ein paar automatisch eingefügt casts.
Warum du aber die C#-Syntax durch Java ersetzen willst, ist mir ein Rätsel.
Weil es hier um Java geht. Gäste :rolleyes: