Java wie Methoden von Generic Typen erweitern, oder casten?

T

Tersus

Gast
Hallo alle zusammen,

wenn ich einen generischen Typen <T> habe, der ja jeden Typ repräsentiert, und meine variable var vom Typ T ist. Wie kann ich dann eventuelle Methoden aufrufen?

Beispiel:

Code:
public static <T> void test(T var){

  boolean methode_existiert = false;
  Methode methoden[] = var.getClass().getMethods();
  String gesuchteMethode = "...tueEtwas()...";


  for(int z = 0; z < methoden.length && !methode_existiert; z++){

    if(methoden.toString().equals(gesuchteMethode)){
      methode_existiert = true;
    }

  }

  if(methode_existiert){

    var.tueEtwas();  // Fehler, da der Compiler zu diesem Zeitpunkt noch nicht
                     // weiß, dass diese Instanzmethode für den Typ existiert.

  }

}

Muss ich var hier casten, damit das Ganze klappt? Aber wie?

Danke schon mal! :)
 
Zuletzt bearbeitet von einem Moderator: (Quelltext weitgehend sichtbar gemacht)
Was du suchst, ist vermutlich "instanceof" mit anschließendem cast.
 
Zuletzt bearbeitet:
Zeit uns erst mal den ganzen Code.
 
@~purplet~
Nein, wirft keinen Fehler!

Wir gehen davon aus, dass var bereits initialisiert ist! Der Code beschreibt eine Methode. var vom Typ T ist dabei Übergabeparameter.

@wahli
Habe den Code im Eingangsbeitrag ergänzt.
 
Zuletzt bearbeitet von einem Moderator:
if (var instanceof Deineklasse){
((Deineklasse) var).tueEtwas();
}
Ergänzung ()

So geht es auch noch:
Object result = object1.getClass().getMethod("gesuchteMethode", null).invoke(var, null);

Schau dir die Doku zu getMethode() und invoke() an.
 
wahli schrieb:
if (var instanceof Deineklasse){
((Deineklasse) var).tueEtwas();
}

Ich dachte mir schon, dass du auf soetwas hinaus willst. ;)
Das ist aber total sinnlos, weil dabei der Effekt der generischen Methode (alle möglichen Dateitypen redundanzarm abzuarbeiten) zunichte gemacht wird. Bei deinem Code wird der generische Typ mit nur einem Datentyp gleichgestellt. Wozu dann überhaupt den generischen Typ verwenden?

Was ich suche, muss allgemeiner sein. tueEtwas() soll eine Methode sein, die von mehreren Klassen implementiert wird. Als Beispiel könnte man die compareTo() nennen.

Eine Vielzahl von Klassen implementiert diese Methode, aber halt nicht alle.

EDIT:

Ich glaube ich bin gerade selbst auf die Lösung gekommen. Dafür nutzt man ein Interface.
 
Zuletzt bearbeitet von einem Moderator:
Dann schau dir doch mal meine Ergänzung von #7 an, Stichwort "Reflection".

Wenn du für die betroffenen Klassen ein Interface verwenden kannst, dann geht das natürlich auch.
if (var instanceof Interfacename){
((Interfacename) var).tueEtwas();
}
 
Zuletzt bearbeitet:
Ja, die Ergänzung habe ich mir angeschaut. Ist eine Möglichkeit. Wie in meiner Ergänzung von #8 bereits erwähnt, empfinde ich die Lösung per Interface angenehmer. ;) Manchmal zerbricht man sich so lange den Kopf, dass man blind für die simpelsten Lösungen ist.

Danke für die Unterstützung!

EDIT:

Dein Edit von #9 um 15:58 Uhr bringt es auf den Punkt. So habe ich es gemacht. Also per var instanceof Interface. ;-)
 
Zuletzt bearbeitet von einem Moderator:
Ich komme von C# und habe von Java keinen Plan, gebe aber mal meinen Senf dazu, da es das Konzept in C# auch gibt und ich denke, dass es ähnlich sein wird. Die Methode ist generisch, also sollst Du auf dem generischen Objekt auch keine Methoden aufrufen, via Reflection umgehst Du das Konzept. Generische Typen dienen nur als in und out Parameter. In C# kann man den generischen Typ über das where Keyword eingrenzen, dann kann man auch entsprechend des Typs Methoden aufrufen...
 
@Drexel
Gut, hilft mir jetzt so aber erstmal nicht weiter. ;)


Eine Frage habe ich aber noch. Sehr viele Klassen implementieren das Interface Cloneable und verfügen somit über eine öffentliche clone() Methode.

Im Interface Cloneable selbst ist die clone() leider auf protected und somit von außen nicht sichtbar. Wie kann ich für beliebige Instanzen, die Cloneable implementieren und entsprechend clone() public setzen die clone() aufrufen?
 
Tersus schrieb:
@Drexel
Gut, hilft mir jetzt so aber erstmal nicht weiter. ;)

Was er meinte ist, dass Generics keinen Sinn machen, wenn du eh wieder von konkreten Typen abhängig bist. Da wäre es in deinem Fall weniger irreführend, wenn du einfach den Typ Object übergeben würdest (oder der spezifischste gemeinsame Typ aller gewünschten Typen), wenn dann anschließend sowieso eine Typprüfung samt Cast erfolgt. Generics werden in der Regel zur Wiederverwendbarkeit von Programmteilen unter Beibehaltung der Typsicherheit verwendet, das ist bei dir nicht der Fall.

Tersus schrieb:
Eine Frage habe ich aber noch. Sehr viele Klassen implementieren das Interface Cloneable und verfügen somit über eine öffentliche clone() Methode.

Nein, die Methode "clone" wird als protected bereits in Object definiert und bei Bedarf überschrieben, sie ist somit immer vorhanden. Das gleichnamige Interface ist ein Marker-Interface, das keine relevanten Methoden beinhaltet. Es zeigt bei Vorhandensein lediglich an: "Ja, den Typ hier darfst du klonen". Wird die Methode aufgerufen, ohne dass das Interface implementiert wurde, dann wird eine " CloneNotSupportedException" geworfen.

Das protected ist aber leider fest, nicht nur deswegen wird clone/cloneable als Fehlentscheidung in Javas Klassendesign angesehen und ist nicht besonders populär. Das hier funktioniert eben nicht immer:

Code:
if(a instanceof Cloneable) {
    copy = ((Cloneable) a).clone();
}

Du solltest schauen, ob du nicht mit einem Copy Constructor o.ä. besser bedient wärst.
 
Zuletzt bearbeitet:
Mach es mit reflection
 
Reflection? :freak:

Ich weiß zwar immer noch nicht, was du machen willst, aber so wie ich das verstanden habe, kannst du das einfach mit einem Interface lösen.

Code:
public interface Basic {

    public void tueEs();
}

Code:
public class BasicImpl implements Basic {

    @Override
    public void tueEs() {
        System.out.println("Hallo Welt");
    }
}

Jeder deiner in Frage kommenden Klassen implementieren das Interface

Code:
public class Main{

    public static void ichWillWasTun(Basic basic){
        basic.tueEs();
    }

    public static void main(String[] args) {
        BasicImpl basic = new BasicImpl();
        ichWillWasTun(basic);
    }
}

Du kannst dann als Parameter dein Interface angeben und reichst immer eine konkrete Implementierung rein. Dessen Methode wird dann ausgeführt.
 
Auf jeden Fall ist das Interface die beste Lösung. Falls Du aus Gründen, die Dein Code nicht unbedingt verdeutlicht, die Genrics trotzdem brauchst, deklarier' die Methode mit:

Code:
public static <T extends MyInterface> void test(T var)
 
Zuletzt bearbeitet:
@carom (#13)

Sehr aufschlussreicher Beitrag, Danke! :) Dennoch bin ich gezwungen Generics zu verwenden. Ich zeige euch später meine Methode und bin gespannt, wenn diese auch ohne Generics möglich gewesen wäre. ;)

@RioCoding

Dass Interfaces der Weg zum Ziel sind, habe ich doch bereits im Beitrag #8 erwähnt. Und ab da an wurde diese Lösung bereits mehrmals erwähnt.

@ SHIVAno1

Dein Code liefert auch einen interessanten Einblick in die Java Mechanik, bzw. was so möglich ist. Prinzipiell auch eine gute Lösung, hilft mir bei meinem speziellen Fall, den ich hier hoffentlich bald veröffentlichen werde, leider nicht weiter. :(
 
Zurück
Oben