Generics: spricht etwas dagegen raw types zu verwenden?

Status
Nicht offen für weitere Antworten.

-frank

Bekanntes Mitglied
ich bin nach einem eclipse update nochmal die compiler-error/warnings-einstellungen durchgegangen und frage mich nun, ob ich bei verwendung von raw types ein warning ausgegen lassen soll oder nicht. also genauer gesagt hatte ich ich es bisher nicht und weiß nun nicht, ob es besser ist, wenn ich meinen code entsprechend ändere. prinzipiell ist es ja kein problem ein "List" zu einem "List<Object>" zu machen (oder List<?>), andererseits stelle ich mir die sinnfrage: wenn ich ein "List" sehe, dann denke ich mir das <Object> ja dazu bzw weiß ich ja, dass die Objekte in der Liste nicht näher definiert sind. IMO bringts also nix, das <Object> anzugeben.
kann aber gut sein, dass ich hier auf etwas wichtiges vergesse, weshalb ich hier mal nachfragen wollte, ob ihr raw types noch verwendet bzw. was dafür/dagegen spricht.
 

byte

Top Contributor
Ich sehs so: Bei alten Projekten kann mans auch lassen, wenn einem das Refactoring sonst zu viel wird. Bei neuen Projekten sollte man direkt Generics richtig einsetzen. Wer das nicht tut, macht sich langfristig nur Mehrarbeit.
 

-frank

Bekanntes Mitglied
Code:
public static void print(Object[] array) {..}
        if (array != null) {
            print(Arrays.asList(array));
        } else {
            print((List) null);
        }
    }

    public static void print(List list) {..}
    }

in diesem beispiel hätte ich zb zwei methoden die eine liste bzw. ein array schön formatiert ausgeben sollen. weil der methoden name überladen ist (worüber man natürlich streiten kann, aber für mein beispiel muss es so sein ;) ), müsste ich dann sogar den cast in
Code:
print((List) null);
parametrisieren, was aus meiner sicht vollkommen sinnlos ist.
 
B

Beni

Gast
Du denkst dir "<Object>" dazu, ich würde zu "<?>" tendieren. Und schon haben wir ein Problem weil jemand ein <> nicht geschrieben hat :wink:

Und was soll erst der Compiler sagen? Er benutzt die Generics um Fehler zu finden, im erraten was ein Code meint, ist er nicht so gut...
 
S

SlaterB

Gast
der Sinn davon ist ja auch nicht, überall List<Object> zu schreiben, sondern List<TypDesInhalts>!

wenn du nicht gerade eine superallgemeine Anwendung hast,
wäre die Warning bei List<Object> auch gar nicht so dumm

bei Listen hätte ich persönlich kein Problem mit der Warning,
aber insbesondere bei Comparable wäre mir das zu nervig

und auch bei eigenen Klassen mit generischen Parameter,
die auch als Basisklasse mit dem bekannten Basis-Generic-Tyy Verwendung finden

siehe auch
http://www.java-forum.org/de/viewtopic.php?t=53319
ab Mitte zweiter Seite
 

-frank

Bekanntes Mitglied
Beni hat gesagt.:
Du denkst dir "<Object>" dazu, ich würde zu "<?>" tendieren.

naja, bevor es Generics gab, konnte man alle Objekte in eine Liste schreiben. dasselbe verhalten erzielt man jetzt mit List<Object>. in eine List<?> kann ich hingegen nix schreiben, weshalb ich mir bei List ein <Object> dazudenke.
aber klar, wenn ich einen Parameter List<Object> habe und eine Liste übergeben will, dann ists wieder umgekehrt und nur List<?> akzeptiert alles, versteh also schon was du meinst.

auf jeden fall mal danke an alle. da es mir ja nicht um mich persönlich geht, sondern darum, wie mein code auf andere wirkt, reicht es mir schon zu wissen, dass einige hier lieber die generics vorfinden. und die unterscheidung zwischen List<?> und List<Object> ist ja ne zusätzliche info, also sicher nix schlechtes.
 

-frank

Bekanntes Mitglied
SlaterB hat gesagt.:
wenn du nicht gerade eine superallgemeine Anwendung hast,
wäre die Warning bei List<Object> auch gar nicht so dumm

naja, ich habe einige GUI klassen/methoden, welche mit Listen arbeiten und zb nur die toString() methode brauchen, um text in zellen von tabellen zu setzen oder menuitems zu generieren. da brauche ich nicht nur List<?>, sondern auch List<Object>.
ansonsten aber äußerst selten.
 

-frank

Bekanntes Mitglied
byto hat gesagt.:
Ich sehs so: Bei alten Projekten kann mans auch lassen, wenn einem das Refactoring sonst zu viel wird. Bei neuen Projekten sollte man direkt Generics richtig einsetzen. Wer das nicht tut, macht sich langfristig nur Mehrarbeit.

meinst du mehrarbeit, weil ich es früher oder später dann doch ändern würde oder weil es aufgrund der nichtverwendung von generics zu höherem aufwand kommt? wenn letzteres, warum? bzw. kannst du mir ein beispiel sagen? (ich werde generics einsetzen, weils mir wie gesagt schon reicht, dass es etliche leute hier wollen. aber mich persönlich störts wie gesagt nicht, wenn die <> fehlen (bei manchen methoden). speziell auch wenn mit Class-Objekten gearbeitet wird)
 

Tellerrand

Bekanntes Mitglied
-frank hat gesagt.:
meinst du mehrarbeit, weil ich es früher oder später dann doch ändern würde oder weil es aufgrund der nichtverwendung von generics zu höherem aufwand kommt? wenn letzteres, warum?
Ohne Generics muss man die Casts selber schreiben und bei jedem Container drauf achten welchen Typ man nun in diesem verwaltet.

Generics sind imo nur eine Möglichkeit sich Schreibarbeit und die möglichen Flüchtigkeitsfehler zu sparen.
Und bei alten Projekten ist die Schreibarbeit kein Argument mehr ;)
 

byte

Top Contributor
Durch die Verwendung von Generics können eben viele Fehler schon zur Designzeit erkannt werden. Man spart insofern Zeit, weil durch die Verwendung somit viele Fehler gar nicht mehr auftreten können.
Wenn man natürlich so allgemeingültigen Code schreibt, dass man nur mit Objects hantiert, dann ist der Nutzen natürlich nicht so groß. Natürlich sollte man dann aber aus Konsistenzgründen auch <Object> schreiben.

Ich muss dazu sagen, dass ich mir bisher noch keine Gedanken darüber gemacht hab, weil ich quasi nie nur mit Objects hantiere, sondern eigentlich immer eigene Typen definiere. Du kannst ja mal drauf achten, wie häufig Du Deine Objects in andere Typen casten musst. ;)
 

byte

Top Contributor
Tellerrand hat gesagt.:
Generics sind imo nur eine Möglichkeit sich Schreibarbeit und die möglichen Flüchtigkeitsfehler zu sparen.
Und bei alten Projekten ist die Schreibarbeit kein Argument mehr ;)

Die "Flüchtigkeitsfehler" sind gar nicht mehr so flüchtig, wenn Du mit einem größeren Entwicklerteam an einem Projekt arbeitest. Gerade über die Schnittstellen der Module hinaus können dadurch viele Exceptions im Vorhinein ausgeschlossen werden.
 
S

SlaterB

Gast
es geht hier doch nur um die Raw-Types-Warning, nicht um Generics an sich..,
wenn man List mit Usern hat, dann wird auch jeder List<User> schreiben,
das ist klar und ausgeklammert

es geht nur um die übriggebliebenen allgemeinen List- und sonstige Raw-Type-Anwendungen..
 
B

bygones

Gast
dank den collection verkommen die generics leider immer mehr bei den programmieren als nice to have... weniger casts und somit weniger schreibarbeit.

Dass sie mehr bieten uebersehen die meisten....


naja zum thema

muessen musst du nichts... wenn du keine lust hast und es einen zu grossen aufwand darstellt mach es nicht. Dank des legacy princips funktioniert der alte code ja auch noch...
 

Tellerrand

Bekanntes Mitglied
Okay ;)
Alte Anwendungen muss man ja nicht umformen, aber bei neuen würde ich schon das <Object> setzen.
Ich verfechte da 2 Grundsätze:
a) Man sollte möglichst nie Compiler Warnings ignorieren. Führt nur zu schlechten Angewohnheiten.
b) Wenn man <Object> schreibt meint man das auch und hat nicht nur die Typangabe vergessen.

Beispiel:
Code:
public LinkedList test() {
		LinkedList<Integer> l = new LinkedList<Integer>();
		return l;
	}
Erzeugt bei mir nur eine Warnung, ignorieren würde ich diese nicht.


Dass sie mehr bieten uebersehen die meisten....
Dann sage mir was sie sonst bringen außer "weniger Schreib-/Denkarbeit" und auch weniger "Fehlerquellen".
 
S

SlaterB

Gast
diese Art der Warnung ist z.B. sinnvoll, die habe ich auch immer eingeschaltet,
wenn ich sie sehe, dann ist das zu 95% so einfach zu korrigieren wie in dem Beispiel und zu 5% kommt ein suppressWarning hin,
weil z.B. eine Hibernate-Ergibnis-Liste initial auf den richtigen Typ gemappt wird

aber bei Raw-Type-Warnings ist die Relation eben nicht 95%, sondern nahe 0%,
wenn ich eine Klasse ohne Typ verwende, dann meine ich das auch so,
da kann es einfach zu keine Fehler kommen
 

Tellerrand

Bekanntes Mitglied
aber bei Raw-Type-Warnings ist die Relation eben nicht 95%, sondern nahe 0%,
wenn ich eine Klasse ohne Typ verwende, dann meine ich das auch so,
da kann es einfach zu keine Fehler kommen.

Mein Beispiel erzeugt bei mir nur ein Raw-Type-Warning.
Und ich kann sogar test().add("irgendwas") aufrufen ohne etwas anderes zu bekommen.
Ist das bei dir anderst, oder hab ich jetzt was verpeilt?
 
S

SlaterB

Gast
stimmt, hab nicht so genau geschaut ;),
aber ist dann umso mehr ein gutes Beispiel:

sofern die Operation so für sich steht, gibts keine Warning (nur das sinnlose raw-type), kein Problem, niemand wird verletzt,

wenn ich jetzt irgendwo
List list = test();
if (list == null) {
}

usw. schreibe, gibts immer noch keine Warning, warum auch?

aber wenn ich nun
List<Integer> list = test();
schreibe, das wäre ja halbwegs gefährlich,

schwupps kommt 'unchecked conversion' oder wie das heißt,
ich werde gewarnt und kann die Operation dann korrieren, alles paletti

wozu braucht man die raw-type-Warning?

in diesem Beispiel wäre sie vielleicht sinnvoll, wenn man eine Library schreibt, mit Operationen, die intern nie genutzt werden..
 

Tellerrand

Bekanntes Mitglied
Ich finde das Beispiel auch gut,
kann damit einen String (Oder irgendetwas anderes) in eine LinkedList<Integer> stecken und das einzige was ich bekomme ist eine Raw Type Warnung. :shock:

Natürlich ist so ein Fehler recht selten, aber man weiß von außen nicht, ob diese LinkedList nicht doch eine LinkedList<Irgendwas> ist.
Wenn ich eine LinkedList<Object> bekomme kann ich mir hingegen sicher sein. ;)


EDIT: Hmm, ich schau nochmal ob ich da wirklich nciht irgendeine andere Warning bekomme :oops:

Also ich bekomme doch die unchecked Warning, aber immer wenn ich versuche irgendetwas einem Raw Type hinzuzufügen.
Ergo müsste man diese Warnung ebenso ignorieren, um mit einem Raw Typ zu arbeiten.
... da bleib ich doch lieber bei <Object> ;)
 
S

SlaterB

Gast
> aber man weiß von außen nicht, ob diese LinkedList nicht doch eine LinkedList<Irgendwas> ist

?
habe ich doch geschrieben: wenn man meint, dass es List<Integer> sein soll, also

List<Integer> list = test();
schreibt, dann kommt 'unchecked conversion'
 

Tellerrand

Bekanntes Mitglied
List<Integer> list = test();
schreibt, dann kommt 'unchecked conversion'

Anderes Beispiel:

Code:
import java.util.LinkedList;

public class TestMain {
	
        private static LinkedList<Integer> list = new LinkedList<Integer>(); 
         /* private static LinkedList list = new LinkedList(); */

    public static LinkedList test() { 
           return list; 
    }
	
	
	public static void main(String[] args) {
		
		
		test().add("asd");
	}
}

Ob ich nun RawTyp verwende oder den Integer Typ, in beiden Fällen die gleiche Warnung.
 

-frank

Bekanntes Mitglied
also dies verwundert mich jetzt wieder:

Code:
public class Main2 {

    private static class A<T extends A<T>> {}

    private static class B extends A[B] {}

    public static void main(String[] args) {
        B b = new B();
        A a = b; // warning (raw type)
        A<?> a2 = b;
        A[B] a3 = b;

        System.out.println(b == a); // funkt
        System.out.println(b == a2); // compilation error: incomparable types
        System.out.println(b == a3); // funkt
    }
}

díes ist ziemlich nervig. warum kann simpler == check nicht auch mit A<?> gemacht werden? dies zwingt mich in diesem fall ja sogar dazu, den raw type zu verwenden und dann ein suppresswarnings zu setzen.

(falls ihr da keinen compiler error bekommt, siehe anderes posting: http://www.java-forum.org/de/viewtopic.php?t=54486)
 

Tellerrand

Bekanntes Mitglied
Ganz ehrlich,
das sind Konstrukte bei denen sich meine Nackenhaare aufstellen.
Das Design sträubt sich gegen OOP und am Ende wird sowas in 99% der Fälle Ärger bereiten.

Da bist du mit deiner Frage jetzt auch tief im Thema Generics drin, mit dem Innenleben der Wildcards kenn ich mich auch nicht sonderlich gut aus.
Dürfte afaik daran liegen, dass die statische Typinformation vollkommen verschieden ist, der Typ B ist dem Compiler bekannt, der Typ A<?> ist hingegen zur Compilezeit schon nicht bekannt. Daher resultiert das Problem zwei Referenzen unterschiedlichen Types, es wäre ja möglich, dass A<?> von einem gaaanz anderem Typ ist.

Näheres findet man vielleicht hier:
http://www.angelikalanger.com/Articles/JavaMagazin/Generics/GenericsPart2.html


EDIT:
Probier mal ein A<? extends A> aus :shock:
 

-frank

Bekanntes Mitglied
Tellerrand hat gesagt.:
EDIT:
Probier mal ein A<? extends A> aus :shock:

macht keinen unterschied. sollte es IMO auch nicht machen, da der compiler ja A<?> sowieso zu A<? extends A<?>> machen kann.

Ganz ehrlich,
das sind Konstrukte bei denen sich meine Nackenhaare aufstellen.
Das Design sträubt sich gegen OOP und am Ende wird sowas in 99% der Fälle Ärger bereiten.

und ich überlege auch, ob ichs wieder rausnehmen soll. ich finds ja auch schrecklich. aber auf der anderen seite erspare ich mir durch solche konstrukte sehr viel redundanten code, sehr viele casts, etc.
du sagst es sträubt sich gegen OOP und naja, kann dir da eigentlich nur zustimmen. aber IMO sträubt es sich doch auch gegen OOP, wenn ich code, den ich in einer superklasse implementieren könnte stattdessen in x anderen klassen stehen habe, nur um zum beispiel die methode zu überschreiben und einen genaueren typ zu returnieren. oder aber ich muss ständig instanceof checks machen bzw. casten und dokumentieren, dass die unterklasse einen spezielleren typ verlangt. diese dinge erspare ich mir, wenn ich typen über generics an die superklasse bzw. das interface weitergebe.

ich weiß einfach nicht bzw. kann mich nicht entscheiden, was besser ist.
edit: aber ich habe gerade eine idee, einen teil der probleme mit interfaces zu umgehen. mal sehen, ob das klappt...
 

Tellerrand

Bekanntes Mitglied
-frank hat gesagt.:
macht keinen unterschied. sollte es IMO auch nicht machen, da der compiler ja A<?> sowieso zu A<? extends A<?>> machen kann.
Sollte es nicht, nein ... aber Compiler müssen ja nicht so intelligent sein, war nur eine reine Vermutung ;)


-frank hat gesagt.:
du sagst es sträubt sich gegen OOP und naja, kann dir da eigentlich nur zustimmen. aber IMO sträubt es sich doch auch gegen OOP, wenn ich code, den ich in einer superklasse implementieren könnte stattdessen in x anderen klassen stehen habe, nur um zum beispiel die methode zu überschreiben und einen genaueren typ zu returnieren. oder aber ich muss ständig instanceof checks machen bzw. casten und dokumentieren, dass die unterklasse einen spezielleren typ verlangt. diese dinge erspare ich mir, wenn ich typen über generics an die superklasse bzw. das interface weitergebe.

Normalerweise braucht man nur den allgemeinen Return Typ der Superklasse.
Das Code in mehreren Klassen neu implementiert werden muss kann auch an der fehlenden Mehrfachvererbung liegen und ist nicht immer ein Zeichen von schlechtem Design.
Das Ziel ist es doch (soweit ich es verfolgt habe) von jeglichen Printable Objekten sich PrintData liefern lassen zu können. Also z.B. eine Methode schreiben zu können, welche eine Liste aus Printable Objekten verarbeitet. Wenn jetzt Printable Objekte unterschiedliche "Arten" von PrintData liefern, kann man sich dies auch sparen, denn die Gemeinsamkeit, welche die Superklasse implementiert, existiert anscheinend nicht.

Andere Erklärung:
Wenn du es schaffst, dass deine verschiedenen Subklassen unterschiedliche Typen retunieren, dann frage ich mich immernoch an welcher Stelle das hilft. Eine Methode print(Printable p) müsste immernoch jedes Printable Objekt anderst behandeln.
Im Prinziep ist die Verwendung von instance of in 99% der Fälle schon auf schlechtes Design zurück zu führen, diese Verwendung nun mit Generics versuchen zu ersetzen ändert imo nicht viel am Design.

Dummerweise kann man dir auch kein alternatives Design vorschlagen ohne genau zu wissen was verlangt ist.
Im Extremfall ist das Design auch nicht verkehrt, sondern es ist einfach das Problem welches etwas haarig ist.
 

-frank

Bekanntes Mitglied
Tellerrand hat gesagt.:
Wenn du es schaffst, dass deine verschiedenen Subklassen unterschiedliche Typen retunieren, dann frage ich mich immernoch an welcher Stelle das hilft. Eine Methode print(Printable p) müsste immernoch jedes Printable Objekt anderst behandeln.

diesbezüglich kann ich dir nicht folgen, da dies bei mir oft der fall ist und es für mich auch ganz normal ist.
ich meine, dass eine Klasse Dog ein Objekt DogPaintData liefert und eine Klasse Cat CatPaintData returniert, das ist doch nicht ungewöhnlich oder?? da hab ich dann eben unterschiedliche returnwerte in den subklassen.

und ob print(printable p) dann die objekte unterschiedlich behandeln muss, ist IMO einfach von der implementierung abhängig. zb könnte diese methode sehr wohl unterschiedlich behandeln, eine andere methode wie printInfo(Printable) aber nur daten über die größe, die anzahl der farben oder sowas auslesen und dafür die untertypen eventuell garnicht brauchen. in meinem fall ists so, dass ich oft allgemeinere methoden habe, die nur den supertyp PaintData verlangen oder Animal oder sowas.

hast du das jetzt anders verstanden bzw. hab ich dich falsch verstanden oder meinst du wirklich, dass dies schon auf schlechtes design deutet? wenn ja, erklär mir bitte warum!
 

Tellerrand

Bekanntes Mitglied
Ich denke wir verstehen uns hier gegenseitig nicht, ich habe das auch etwas unglücklich formuliert.

ich meine, dass eine Klasse Dog ein Objekt DogPaintData liefert und eine Klasse Cat CatPaintData returniert, das ist doch nicht ungewöhnlich oder?? da hab ich dann eben unterschiedliche returnwerte in den subklassen.
Das ist ganz normal, nur warum willst du dies in der Superklasse implementieren, darum ging es mir.

und ob print(printable p) dann die objekte unterschiedlich behandeln muss, ist IMO einfach von der implementierung abhängig. zb könnte diese methode sehr wohl unterschiedlich behandeln, eine andere methode wie printInfo(Printable) aber nur daten über die größe, die anzahl der farben oder sowas auslesen und dafür die untertypen eventuell garnicht brauchen.
Meiner Meinung nach sollte eine Methode print(Printable p) möglichst nie Rücksicht darauf nehmen welcher genaue Subtyp nun übergeben wird, sondern wie du es auch selber schon geschrieben hast den allgemeinen Typ verwenden.
Genauso ist es meine Meinung, dass wenn man eine Liste, gefüllt mit Objekten unterschiedlichen Typs, hat und die Objekte dieser Liste dann je nach Typ unterschiedlich verarbeiten will, dann existiert ein Designfehler.

meinst du wirklich, dass dies schon auf schlechtes design deutet? wenn ja, erklär mir bitte warum!
Ja, es deutet in meinen Augen auf ein schlechtes Design hin. Begründung ist die Alternative von vielen Casts, instance of, etc.
Genaueres sagen, wie z.B. "Ja das ist schlecht, weil..." oder "Ist ok, sehe da nichts falsches" kann ich nur wenn ich auch weiß was du genau versuchst zu implementieren und z.B. ein Klassendiagramm vorliegen habe.
Also bleibe ich dabei zu sagen "Das Design scheint mir komisch zu sein"
 

-frank

Bekanntes Mitglied
@Tellerrand:
ich habe ehrlich gesagt nicht bewusst darauf geachtet, dass bei Printable-Objekten nicht zwischen den Untertypen von PaintData unterschieden werden sollte, aber unbewusst/intuitiv hab ich das eh so gemacht. Und ja, wenn ich so drüber nachdenke, gebe ich dir recht, dass der genaue Typ im Interface eigentlich nicht viel verloren hat. Ich habs eben generisch ins Interface gepackt, weil ich dann zum Beispiel im Interface DogPaintData (welches Paintable extended) nicht die Methode nochmal (mit genauerem Returnwert) angeben muss. aber ich seh ja jetzt in meinem Code, dass ich überall Paintable<?> als Parameter habe, weil mir der spezielle Typ an diesen Stellen ganz egal ist. wichtig ist mir nur, dass die konnkreten Klassen wie Dog oder DogPaintData Dog-Objekte liefern (und das findest du ja auch ganz normal, wie du gesagt hast). aber ja, dann sollte ich das deswegen wohl nicht ins Paintable interface packen.
der grund, warum ich dies schon in eine abstrakte superklasse bzw. ein interface packen wollte, ist, dass ich in meinem konkreten beispiel ein paar methoden habe. also angenommen es gibt dann noch methoden wie getFriend() in Animal. jedes Animal hat einen Freund, wobei Hunde Hunde als Freunde haben (ist jetzt nur ein blödes beispiel...). und noch mehr solcher methoden. Dies führt dazu, dass ich bei jeder Klasse wie Dog, Cat, etc. sehr viele Methoden habe, die ich überschreiben muss, um den genauen returntyp anzugeben, bzw. es gibt sehr viele methoden, wo ich überprüfen muss, ob zb bei setFriend(Animal) der richtige Subtyp übergeben wird. solche dinge wollte ich umgehen, das war der einzige grund eigentlich.

allerdings sehe ich jetzt ja selbst, dass ich im Code dann oft zb "Animal<?,?,?>" stehen habe (vorher hatte ich nur den raw type verwendet, aber jetzt wo die Warnung auf on ist ...). Mein Denkfehler war, dass ich zB mit einem Animal<Dog, DogPaintData, DogSomething> arbeiten würde, aber das stimmt ja nicht. ich arbeite entweder mit einem Animal<?,?,?> (und dann sind mir typen auch egal) oder aber mit einem konkreten Tier wie Dog.
wenn ich Animal ungenerisch mache hats eben den einen Nachteil, dass ich nicht angeben kann, dass ein Dog bei setFriend(..) einen anderen Dog erwartet und kein Tier. Aber damit muss ich wohl leben.
 

Tellerrand

Bekanntes Mitglied
-frank hat gesagt.:
wenn ich Animal ungenerisch mache hats eben den einen Nachteil, dass ich nicht angeben kann, dass ein Dog bei setFriend(..) einen anderen Dog erwartet und kein Tier. Aber damit muss ich wohl leben.

Hier sehe ich auch das Problem am Design, du willst in der Superklasse eine Methode definieren die nicht für alle Subklassen gilt.
Im schlimmsten Fall definierst du später von Dog noch weitere Subklassen, z.B. BigDog und LittleDog und hängst an der selben Stelle ... wie macht man es möglich, dass LittleDog Objekte auch nur LittleDog Freunde haben dürfen.
Meiner Meinung nach ist die Methode setFriend also nicht für alle Subklassen von Animal gleicherweise gegeben, ich würde sie also auch nicht auf diese Weise in die Klasse Animal stecken.

Ein einfaches alternatives Design ist z.B. die Methoden:
Code:
boolean isPossibleFriend(Animal a)
// und
void setFriend(Animal a) throws IllegalFriendException
// (Oder halt irgendeine andere passende Exception)
in die Klasse Animal zu stecken.

Fehlt noch eine Art Vorgehensweise für die Prüfung von isPossibleFriend, aber wenn man diese hat wäre es imo schöner. Egal welches Tier ich habe und welches Tier ich als Freund setzen will, ich kann mit isPossibleFriend nachfragen obs passt und dann mit setFriend setzen, ... unabhängig von jeglichen Subklassen.


Nunja, das nur so als Anregung, das Problem ist wirklich etwas haarig und eine richtig elegante Lösung fällt mir da auf Anhieb auch nicht ein. :?
 

-frank

Bekanntes Mitglied
Tellerrand hat gesagt.:
-frank hat gesagt.:
wenn ich Animal ungenerisch mache hats eben den einen Nachteil, dass ich nicht angeben kann, dass ein Dog bei setFriend(..) einen anderen Dog erwartet und kein Tier. Aber damit muss ich wohl leben.

Hier sehe ich auch das Problem am Design, du willst in der Superklasse eine Methode definieren die nicht für alle Subklassen gilt.

weiß nicht... ich will definieren, dass alle Tiere Freunde haben können aber eben nur Freunde vom selben Typ. wenn das eine abbildung der "real world" bzw. eben so gefordert ist, dann würde ich es nicht als schlechtes design ansehen bzw. wüsste ich nicht wirklich, wie ich es anders machen kann.

dein codebeispiel ist aber ein guter vorschlag IMO. ich werde im interface definieren, dass zb setFriend() eine exception werfen kann, falls der falsche typ übergeben wird. und sowas wie isPossibleFriend() macht absolut sinn! den check bzw. das setzen kann ich dann aber wohl trotzdem noch in einer abstrakten klasse machen. der abstrakten klasse kann ich dann auch ein paar generics geben um genauere return-werte zurückzugeben bzw. ein Class-Objekt, um den isPossibleCheck zu implementieren. in der abstrakten klasse stören mich diese dinge viel weniger, da sie - und ich hoffe ich irre mich da nicht (bin erst dabei es auszuprobieren) - wirklich nur bei der implementierung eines neuen Tieres relevant sind. Sämtliche Clientklassen haben nur ne Referenz auf das Interface Animal anstatt auf AbstractAnimal (und somit ist das Generic bzw. RawType-Problem keines mehr).
das einzige, was ich damit natürlich nicht erreiche, ist, den Typ von setFriend() genau anzugeben. ich hätte zwar die information dazu in AbstractAnimal, aber natürlich darf ich das Interface Animal nicht einschränken. daher muss ich eben wie in deinem vorschlag Animal akzeptieren und ggf. ne exception werfen. aber ich kann sehr wohl den Check in der zentralen (abstrakten) klasse machen und ich kann dort bzw. im interface auch die notwendige dokumentation platzieren. und die genaueren returnwerte kann ich ebenfalls returnieren. hab also trotzdem die redundanzen raus.
ich denke, dass es so ganz gut klappen sollte. aber muss es noch testen...
 

Tellerrand

Bekanntes Mitglied
-frank hat gesagt.:
Tellerrand hat gesagt.:
-frank hat gesagt.:
wenn ich Animal ungenerisch mache hats eben den einen Nachteil, dass ich nicht angeben kann, dass ein Dog bei setFriend(..) einen anderen Dog erwartet und kein Tier. Aber damit muss ich wohl leben.

Hier sehe ich auch das Problem am Design, du willst in der Superklasse eine Methode definieren die nicht für alle Subklassen gilt.

weiß nicht... ich will definieren, dass alle Tiere Freunde haben können aber eben nur Freunde vom selben Typ. wenn das eine abbildung der "real world" bzw. eben so gefordert ist, dann würde ich es nicht als schlechtes design ansehen bzw. wüsste ich nicht wirklich, wie ich es anders machen kann.

Vielleicht liegt ein Problem auch hier, für mich bestimmt die Aufgabenstellung(=Problem) das Design.
Wenn der Typ eines Tieres eine Information sein soll, dann würde ich gegebenenfalls diesen Typ (nur) als Attribut/Information nutzen.
Also ein enum AnimalTyp definieren und getAnimalTyp() als Methode in Animal implementieren.
Erst wenn das Problem Vererbung sinnvoll macht (Z.B. Unterschiedliche Tiere = unterschiedliche Methoden / Attribute) würde ich diese auch nutzen. Wobei die beiden Varianten sich nicht gegenseitig ausschliessen, man kann Vererbung nutzen, aber trotzdem noch ein Attribut AnimalTyp einfügen.

Die Typinformation von Java als Information im Programm selber zu nutzen ist manchmal fragwürdig.
Das endet öfters im Bereich Reflection, wenn man mit dieser Information komplexere Dinge machen will.
Oft wäre es dann bedeutend einfacher gewesen hätte man diese Information als Attribut, Variable angesehen.
(Was ist z.B. wenn du später ausgeben willst ob das Tier nun ein Vogel oder ein Hund ist?)

Nunja, das ist halt alles sehr vage, ich kann hier auch nur Anregungen liefern ein Kochrezept existiert ja nicht ;)
 

-frank

Bekanntes Mitglied
Tellerrand hat gesagt.:
Nunja, das ist halt alles sehr vage, ich kann hier auch nur Anregungen liefern ein Kochrezept existiert ja nicht ;)

aber danke, du hast mir schon sehr geholfen!

Die Typinformation von Java als Information im Programm selber zu nutzen ist manchmal fragwürdig.
Das endet öfters im Bereich Reflection, wenn man mit dieser Information komplexere Dinge machen will.
Oft wäre es dann bedeutend einfacher gewesen hätte man diese Information als Attribut, Variable angesehen.
(Was ist z.B. wenn du später ausgeben willst ob das Tier nun ein Vogel oder ein Hund ist?)

das ist leicht, denn eine enum AnimalType hab ich ohnehin ;)
und ich verwende diese typinformation auch, aber für die oben besprochenen dinge hilft es mir ja nicht wirklich weiter. ich meine, ja, ich kann im interface definieren, dass bei setFriend(Animal) Animal ein Tier vom selben AnimalType sein muss. oder bei getFriend() dazu schreiben, dass der returnierte wert immer ein Animal desselben AnimalTypes ist, klar. und ich kann in einer Methode printAnimalType() einfach
Code:
getAnimalType.toString()
oder
if(getAnimalType().equals(Animal.DOG)) {..}
schreiben. aber es hilft mir nicht die oben besprochenen redundanzen bzw. checks wegzubekommen.
 
Status
Nicht offen für weitere Antworten.
Ähnliche Java Themen
  Titel Forum Antworten Datum
J Best Practice Generics mit Enum Allgemeine Java-Themen 3
H Kombination Interface und Abstrakte Klasse bei Generics Allgemeine Java-Themen 3
Zeppi Cast Object in Generics Allgemeine Java-Themen 4
P Generics und Arrays Allgemeine Java-Themen 6
M Generics / Typen Allgemeine Java-Themen 1
Kirby.exe InsertionSort mit Generics Allgemeine Java-Themen 33
Kirby.exe Vererbung bei Generics Allgemeine Java-Themen 7
H Klarnamen etc... (von Wie Generics lernen?) Allgemeine Java-Themen 26
D Wie Generics lernen? Allgemeine Java-Themen 26
L Compiler-Fehler Generics beim Anhängen von Predicates Allgemeine Java-Themen 1
W Vererbung Generics - mal wieder die verhaßte Rückwärtskompatibilität Allgemeine Java-Themen 2
S Verstaendnisfrage Generics Allgemeine Java-Themen 19
W Generics + Vererbung Allgemeine Java-Themen 47
I Methoden Generics-Methode Allgemeine Java-Themen 3
D Mit Generics arbeiten - Übungsaufgabe Allgemeine Java-Themen 3
K Factory Pattern: Mit Generics umgehen Allgemeine Java-Themen 6
G Generics Allgemeine Java-Themen 31
perlenfischer1984 Liste mit generics zurück liefern Allgemeine Java-Themen 8
Hacer Generics & Collections Allgemeine Java-Themen 8
Neumi5694 Interface Generics für Enum-Filterung verwenden Allgemeine Java-Themen 5
H Collector Generics Problem (incl. Stream & Lambda) Allgemeine Java-Themen 4
C Gemeinsame Oberklasse zweier Generics Allgemeine Java-Themen 10
erdmann Datentypen Methodendeklaration mit Generics Allgemeine Java-Themen 2
Z Datentypen Verschachtelte Generics Allgemeine Java-Themen 1
Neumi5694 Datentypen Generics Allgemeine Java-Themen 5
S Mit Generics Klasse erstellen die selbst T erweitert..? Allgemeine Java-Themen 4
Tarrew Generics - Type erasure Allgemeine Java-Themen 5
N Problem mit Generics und Interface Allgemeine Java-Themen 4
H Generics als Parameter Allgemeine Java-Themen 1
kaoZ Generics und Vererbung Allgemeine Java-Themen 3
A Datentypen Generics: Wie am besten auf Typparameter zugreifen Allgemeine Java-Themen 2
C Generics Objekt in ArrayList Allgemeine Java-Themen 2
vandread Kleine Generics Aufgabe aus einer Prüfung... wie ist das gemeint? Allgemeine Java-Themen 6
G Generics sind zu streng - oder ich zu naiv? Allgemeine Java-Themen 3
G Verschachtelte Generics Allgemeine Java-Themen 2
O Generics Allgemeine Java-Themen 42
M Problem mit Generics Allgemeine Java-Themen 10
M Generics (bounded wildcards statt Interface Bezeichnern) -- Sinn oder Unsinn? Allgemeine Java-Themen 2
darekkay Generics: Wildcard und Object Allgemeine Java-Themen 5
H Collections Generics und Reflection Allgemeine Java-Themen 6
F Google Guice + Generics + Vererbung Allgemeine Java-Themen 5
H Problem mit Java Generics Allgemeine Java-Themen 6
J Generics: Typparameter als Klasse zurückliefern Allgemeine Java-Themen 4
H Generics Allgemeine Java-Themen 5
P Probleme mit Generics Allgemeine Java-Themen 5
B Generics und primitve arrays Allgemeine Java-Themen 6
M Generics Allgemeine Java-Themen 11
1 Collections Generics, internes Verhalten Allgemeine Java-Themen 16
T Warnungsfreie Verwendung von Generics Allgemeine Java-Themen 11
M Probleme mit Generics Allgemeine Java-Themen 5
D Java Generics Allgemeine Java-Themen 8
2 Generics: bounded wildcards Allgemeine Java-Themen 4
J Generics / vermeiden von downcasts Allgemeine Java-Themen 2
2 Generics oder nicht? Allgemeine Java-Themen 8
E Problem mit Generics und Comparable Allgemeine Java-Themen 16
W Erweitern einer Klasse mit Generics Allgemeine Java-Themen 8
H Generics für Methode Allgemeine Java-Themen 14
N Überladen mit Hilfe von Generics Allgemeine Java-Themen 3
S Generics: Fuer Set<T> ein T-Klassenobjekt erhalten? Allgemeine Java-Themen 3
Q Der innere Typ von Generics? Allgemeine Java-Themen 3
N Generics-NullpointerException Allgemeine Java-Themen 7
2 Generics - Typ Allgemeine Java-Themen 12
P Generics Problem Allgemeine Java-Themen 10
S Type safety Warnings beim casten von Generics Allgemeine Java-Themen 6
N Generics Allgemeine Java-Themen 3
V Frage zu Generics Allgemeine Java-Themen 2
S java generics klassen deklaration Allgemeine Java-Themen 7
B hashtable für unterschiedliche Typen - mit Generics Allgemeine Java-Themen 8
E Generics Allgemeine Java-Themen 3
MQue Generics Allgemeine Java-Themen 4
R Problem mit Reflection und Generics Allgemeine Java-Themen 3
C Klassen, die aufeinander verweisen (mit Generics) Allgemeine Java-Themen 16
G Generics - W.card unter Nutzung von Annotationsklasse? Allgemeine Java-Themen 6
G sortieren von generics Allgemeine Java-Themen 10
G Generics in Map. Type of value abhängig vom key Allgemeine Java-Themen 3
A Generics Verständnisfrage Allgemeine Java-Themen 7
Z Generics funzt nicht? Allgemeine Java-Themen 2
T Generics Allgemeine Java-Themen 18
G ComboBox: Nur eine Art Klasse zulassen (Generics) Allgemeine Java-Themen 3
J Generics Expertenwissen? Allgemeine Java-Themen 5
S Generics-Problem Allgemeine Java-Themen 3
T Generics und Wil-dcards Allgemeine Java-Themen 8
Q Typen von Generics & Casten Allgemeine Java-Themen 3
S Generics Allgemeine Java-Themen 2
R Problem mit Generics Allgemeine Java-Themen 2
G Trotz Generics Cast-Fehler! Allgemeine Java-Themen 5
T TreeMap durch Comparator mit Generics sortieren Allgemeine Java-Themen 9
T Generics und instanceof Allgemeine Java-Themen 10
T Generics und Exceptions Allgemeine Java-Themen 6
M Beliebig viele Typen bei Generics Allgemeine Java-Themen 3
G Reflection objekt mit generics erzeugen Allgemeine Java-Themen 5
S Singleton Pattern mit Generics Allgemeine Java-Themen 4
G Generics und Comparable Allgemeine Java-Themen 11
H Generics Problem Allgemeine Java-Themen 3
M Generics - besser programmieren, Warnung umgehen Allgemeine Java-Themen 4
E Java, UML, Generics Allgemeine Java-Themen 6
P Array von Vectoren + Generics Allgemeine Java-Themen 6
M ArrayList erweitern - generics Allgemeine Java-Themen 4
E Generics -> UML Allgemeine Java-Themen 4
G Generics: Instanzieren einer Klasse in einer Methode. Allgemeine Java-Themen 2

Ähnliche Java Themen

Neue Themen


Oben