PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Java Generics Problem


Gast
2009-12-08, 06:06:08
Hi,
habe da mal ein Problem mit den Generics in Java, geht um einen EventBus. Zwei Klassen:


public class EventBus {
private static HashMap<Class<?>, ArrayList<EventSubscriber<?>>> subscriber = new HashMap<Class<?>, ArrayList<EventSubscriber<?>>>();

public static <T> void subscribe(Class<T> class1, EventSubscriber<T> eventSubscriber) {
ArrayList<EventSubscriber<?>> subs;

if (subscriber.containsKey(class1)) {
// alte liste holen und den subscriber hinzufügen
subs = subscriber.get(class1);
subs.add(eventSubscriber);
} else {
// neue arraylist und in die hashmap schreiben
subs = new ArrayList<EventSubscriber<?>>();
subs.add(eventSubscriber);
subscriber.put(class1, subs);
}
}

public static void publish(Object t) {
// falls keine subscriber vorhanden sind, dann abbrechen
if(!subscriber.containsKey(t.getClass()))
return;

ArrayList<EventSubscriber<?>> subs = subscriber.get(t.getClass());

for(EventSubscriber<?> sub : subs){
sub.onEvent(t);
}
}
}



public interface EventSubscriber<E> {
void onEvent(Object t);
}


So siehts momentan aus, und es funktioniert. Allerdings muss ich jedesmal in der onEvent()-Methode ein Cast zum richtigen Object machen welches ich verhindern will.

So benutze ich es jetzt:


EventBus.subscribe(String.class, new EventSubscriber<String>() {
@Override
public void onEvent(Object t) {
String z = (String) t;
Window.alert(z);
}
});



Und so soll es eigentlich sein:


EventBus.subscribe(String.class, new EventSubscriber<String>() {
@Override
public void onEvent(String t) {
Window.alert(t);
}
});



Ich bin mir recht sicher das das Interface hierfür wie folgt sein muss(habe es nur geaendert damit es übehaupt erstmal funktioniert):

public interface EventSubscriber<E> {
void onEvent(E t);
}


Allerdings bekomme ich dann Compile-Errors in der publish()-Methode da der Compiler durch die Wildcards den Typ nicht eindeutig bestimmen kann ... Für eine Lösung wäre ich dankbar, hab nämlich grade keine Ahnung wie ichs hinbekommen könnte :/

GMP100
2009-12-08, 10:49:17
Mir fehlt zwar in der ganzen Geschichte son Bischen die "Event" Klasse, aber ich glaub, wenn du deine EventBus.publish() Methode generifizierst, sollte es klappen mit deinem generischen EventSubscriber.

universaL
2009-12-08, 12:46:34
wenn ich mich recht erinnere kann java Map<A, List<A>> nicht, zumindest nicht ohne manuellen cast, da man ende mehr oder weniger nur:

Map<Class<? extends IAttributes>, List<? extends IAttributes>>> machenkann, man aber nicht spezifieren kann, das die beiden "fragezeichen" dieselbe klasse sein sollen für einen eintrag, aber eben nicht für alle ;)

robobimbo
2009-12-08, 12:58:21
Schau Dir mal diese Präsentation durch, da ist der Grund erklärt (ab Folie 10)

http://www.slideshare.net/tutego/einfhrung-in-den-eventbus

Gast
2009-12-08, 16:41:30
Zum EventBus:
Hat im Grunde nur 2 Methoden: publish(Object) und subscribe(Class, new Eventsubcriber). ICh melde Subscriber auf bestimmte Klassen an und kann dann auf beliebige Objekte "lauschen".
zB subscribe(String.class, new EventSubscriber<String>{onEvent(String s){...}});
und dann: publish(new String("Hallo"));


public static <T> void publish(Tt) {
// falls keine subscriber vorhanden sind, dann abbrechen
if(!subscriber.containsKey(t.getClass()))
return;

ArrayList<EventSubscriber<T>> subs = subscriber.get(t.getClass());

for(EventSubscriber<T> sub : subs){
sub.onEvent(t);
}
}



So ungefähr hatte ich es schon(grad kein Eclipse hier zum testen), er hat auch einzig an einer Stelle gemeckerrt und zwar war es "subscriber.get(t.getClass());". Und da wusste ich dann nicht weiter, weswegen ich so meine Zweifel hatte ob das richtig ist was ich da tue ...
es sollte das PRoblem was universaL beschreibt sein, gibts da keinen workaround oder Lösung für? Vielleicht anstatt eine HashMap irgendwas anderes nehmen?

In der Präsentation gehts um was anderes (wenn ich das alles richtig verstanden habe). Und zwar wird dort ab Folie 10 erklärt das zB ArrayList<String> und ArrayList<Integer> im Grunde die gleiche Klasse sind, weswegen man nicht so einfach wegen des generischen Typs diese Klassen unterscheiden kann .... mit anderen Worten: melde ich ein Subscriber auf ArrayList<String> und einen auf ArrayList<Integer> an, kommen alle ArrayList<X>-Events auch auf diese Subscriber.

Gast
2009-12-08, 22:03:34
ich habe eine zufriedenstellende Lösung in einem anderen forum bekommen.
falls es jemanden interessiert:
http://forum.javacore.de/viewtopic.php?p=62097#62097


kurzfassung:

public static <T> void publish(final T t) {
// falls keine subscriber vorhanden sind, dann abbrechen
if (!subscribers.containsKey(t.getClass())) {
return;
}

for (final EventSubscriber<?> subscriber : subscribers.get(t.getClass())) {
@SuppressWarnings("unchecked")
final EventSubscriber<T> currentSubscriber =
(EventSubscriber<T>) subscriber;
currentSubscriber.onEvent(t);
}




danke für eure hilfe :)