tutorials.de Buch-Aktion 05/2012
ERLEDIGT
JA
ANTWORTEN
4
ZUGRIFFE
570
EMPFEHLEN
  • An Twitter übertragen
  • An Facebook übertragen
AUF DIESES THEMA
ANTWORTEN
  1. #1
    Avatar von Muepe32
    Muepe32 Muepe32 ist offline Mitglied Brokat
    Registriert seit
    Mar 2011
    Beiträge
    353
    Hallo zusammen,

    Nachdem ich mich in letzer Zeit nur oberflächlich mit Java beschäftigt habe hat mich nun das Interesse gepackt mein nächstes Projekt, das ich eigentlich in C# - wie immer - programmieren wollten mal mit Java anzupacken.

    Erwartungsgemäss funktioniert vieles eigentlich problemlos, da es doch nicht so gewaltige Unterschiede gibt zwischen den zwei Sprachen. Jedoch gibt es jetzt ein Problem mit generischen Typen. In C# ist es problemlos möglich von einem generischen Typen eine Instanz zu erstellen durch ein Constraint:
    Code csharp:
    1
    2
    3
    4
    5
    
    class Generic<T> where T : new()
    {
    public:
       T Create() { return new T(); }
    }

    Der Typ den man nun an Generic übergibt muss nun einen parameterlosen Konstruktor besitzen und auch instanzierbar sein (kein Interface, keine abstrakte Klasse, ...). In Java habe ich das bisher nicht hinbekommen. Ist tatsächlich so, dass so etwas elementares nur über Umwege möglich ist, oder gibt es etwas vergleichbares? Bzw um genau zu sein habe ich es bisher noch nicht mal über Umwege hinbekommen eine Instanz von dem generisch angegebenen Typen zu erstellen.

    Gruss
    Muepe
     
    Viele Tutorials und Artikel zur Programmierung unter Windows mit C++ und C#. Tägliche Updates und Antworten auf eure Fragen:
    Win32Easy - Blog
    Es würde mich freuen, wenn ihr einen Kommentar postet!

  2. #2
    SE Tutorials.de Gastzugang
    Also ohne mich jetzt selbst mit generischen Typen auszukennen würde ich meinen das sowas in Java nur mit Reflections möglich sein wird.
     

  3. #3
    Registriert seit
    Jun 2002
    Ort
    Saarbrücken (Saarland)
    Beiträge
    9.886
    Blog-Einträge
    29
    Hallo,

    das was du machen willst (Erzeugung von generischen Typen) geht mit Java eigentlich nicht bzw. wird es von Java nicht direkt unterstützt. Jedoch ist es "prinzipiell" möglich das von dir gewünschte Verhalten nachzuahmen.

    Generics in Java und C# sind unterschiedlich implementiert. Bei Java gibt es zur Laufzeit keine Informationen mehr zu Generics, denn diese werden vom Java Compiler (bis auf wenige Ausnahmen) entfernt (Stichwort: Type Erasure). Bei C# bleiben die Informationen zu Generics nach dem kompilieren erhalten und lassen sich zur Laufzeit auswerten.

    Es gibt für Java ein paar Tricks wie man den Compiler dazu bringen kann Code zu generieren der die generischen Typinformationen in machen Situationen erhält.

    Ein Trick ist beispielsweise einer Methode mit generischem Varargs (..., ellipse) Parameter und dem selben Rückgabetyp zu erstellen und diese Methode dann im Code aufzurufen. Der Java Compiler fasst dann die beim Methodenaufruf übergebenen Parameter zusammen, indem er mit Type Inferenz den Typ ermittelt welcher den übergebenen Parametern zugrundeliegt und anschließend ein Array vom dem Typ erzeugt.

    Siehe Beispiel.

    Beispiel:
    Code java:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    
    package de.tutorials.training;
     
    import javax.swing.JButton;
    import javax.swing.table.DefaultTableModel;
     
    public class GenericTypeFactoryExample {
     
      public static void main(String[] args) {
        System.out.println(new Generic<Object>().create());
        System.out.println(new Generic<DefaultTableModel>().create());
        
        
        JButton button = create(); 
        // Vom Java Compiler wird nun folgender Code erzeugt:
        //JButton button = create(new JButton[0]);
        //Durch Type Inference zum Rückgabetyp der create Methode wird der generische Parameter Typ auf JButton gesetzt 
        
        //Hier ein Beispiel für die explizite Angabe des zu verwendenden Typs 
        System.out.println(GenericTypeFactoryExample.<JButton>create());
        //Vom Java Compiler wird nun folgender Code erzeugt:
        //JButton button = create(new JButton[0]);
        
        
        
      }
      
      public static <T> T create(T...ts){
        try {
          return (T)ts.getClass().getComponentType().newInstance();
        } catch (Exception e) {
          throw new RuntimeException(e);
        }
      }
      
      static class Generic<T>{
        @SuppressWarnings("unchecked")
        public T create(T...ts){
          try {
            return (T)ts.getClass().getComponentType().newInstance();
          } catch (Exception e) {
            throw new RuntimeException(e);
          }
        }  
      }
    }

    Ausgabe:
    Code :
    1
    2
    3
    
    java.lang.Object@5d0385c1
    javax.swing.table.DefaultTableModel@164f1d0d
    javax.swing.JButton[,0,0,0x0,invalid,alignmentX=0.0,alignmentY=0.5,border=javax.swing.plaf.BorderUIResource$CompoundBorderUIResource@1cf11404,flags=296,maximumSize=,minimumSize=,preferredSize=,defaultIcon=,disabledIcon=,disabledSelectedIcon=,margin=javax.swing.plaf.InsetsUIResource[top=2,left=14,bottom=2,right=14],paintBorder=true,paintFocus=true,pressedIcon=,rolloverEnabled=true,rolloverIcon=,rolloverSelectedIcon=,selectedIcon=,text=,defaultCapable=true]

    Gruß Tom
     
    Java rocks!
    How to become a good Java Programmer?
    Does IT in Java and .Net
    The only valid measurement of code quality: WTFs / minute
    Blog
    Xing
    Twitter

  4. #4
    Avatar von Muepe32
    Muepe32 Muepe32 ist offline Mitglied Brokat
    Registriert seit
    Mar 2011
    Beiträge
    353
    Hallo Tom,

    Besten Dank für deine Infos, das hat mich schon viel weiter gebracht! Allerdings habe ich jetzt noch ein Problem bezüglich Vererbung. Meine Klasse sieht folgendermassen aus:
    Code java:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    
    public class ListenServer<T extends ClientSocket> {
    //...
        @SuppressWarnings("unchecked")
        private T createSocketWrapper(T...ts) {
            try {
                return (T)ts.getClass().getComponentType().newInstance();
            } catch (Exception e) {
                System.out.println(ts.getClass().getComponentType().toString());
                throw new java.lang.RuntimeException(e);
            }
        }
    //...
    }

    In meinem Testprojekt habe ich dann folgende Versuchsklasse gemacht:
    Code java:
    1
    2
    3
    4
    5
    6
    
    public class LogonClient extends ClientSocket {
        @Override
        protected void OnConnect() {
            System.out.println("Client connected: " + mClientSocket.toString());
        }
    }

    Entsprechend ist ClientSocket eine abstrakte Klasse. In der Verwendung sieht es folgendermassen aus:
    Code java:
    1
    
    ListenServer<LogonClient> listener = new ListenServer<LogonClient>();

    Das Problem nun ist jetzt aber, dass in der Klasse createSocketWrapper Methode versucht wird eine Instanz der Klasse ClientSocket zu erstellen und nicht von LogonClient. Das schlägt natürlich (rückwirkend betrachtet zum Glück) fehl da ClientSocket abstrakt ist. Aber warum das?

    Gruss
    Muepe
     
    Viele Tutorials und Artikel zur Programmierung unter Windows mit C++ und C#. Tägliche Updates und Antworten auf eure Fragen:
    Win32Easy - Blog
    Es würde mich freuen, wenn ihr einen Kommentar postet!

  5. #5
    Avatar von Muepe32
    Muepe32 Muepe32 ist offline Mitglied Brokat
    Registriert seit
    Mar 2011
    Beiträge
    353
    Nachdem ich mir das über Nacht mal bisschen durch den Kopf habe gehen lassen ist mir eigentlich auch klar geworden warum das obige Verhalten auftritt:
    die createSocketWrapper Methode wird innerhalb der Klasse LogonClient aufgerufen und das generische vararg Element wird daher bereits beim Compilieren der Klasse LogonClient ausgefüllt. Zu diesem Zeitpunkt kennt der Compiler den finalen Typ LogonClient natürlich noch nicht und muss einen möglichst guten Treffer, der aber immer funktioniert für T finden. Das ist dann natürlich ClientSocket, da T sicher immer von ClientSocket erbt. Ich habe es nun so gemacht, dass der Konstruktor von LogonClient noch variable generische Parameter hat, die dann verwendet werden können.
    Code java:
    1
    2
    3
    4
    
        public ListenServer(String addr, int port, T... ts) throws IOException {
            //...       
            mGenericCreator = new Generic<T>(ts.getClass().getComponentType());
        }

    Wobei dann mGenericCreator eine Instanz der folgenden privaten Klasse ist:
    Code java:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    
        private class Generic<S> {
            public Generic(Class<?> typeClass) {
                mTypeClass = typeClass;
            }   
            
            @SuppressWarnings("unchecked")
            public S createSocketWrapper() {
                System.out.println(mTypeClass.toString());
                try {
                    return (S)mTypeClass.newInstance();
                } catch (Exception e) {
                    throw new java.lang.RuntimeException(e);
                }
            }
            
            private Class<?> mTypeClass;
        }

    Damit funktioniert jetzt eigentlich alles so wie ich es möchte. Ist zwar ziemlich umständlich (leider, da ich als von C++ und C# kommender natürlich eine viel grössere Flexibilität von Generics gewohnt bin und mein Code exzessiven Gebrauch davon macht), aber am Ende zählt ja, dass es funktioniert

    Gruss
    Muepe
     
    Viele Tutorials und Artikel zur Programmierung unter Windows mit C++ und C#. Tägliche Updates und Antworten auf eure Fragen:
    Win32Easy - Blog
    Es würde mich freuen, wenn ihr einen Kommentar postet!

Ähnliche Themen

  1. Instanzieren von generischen Typen
    Von xxsaikoxx im Forum Java
    Antworten: 3
    Letzter Beitrag: 30.12.07, 11:14
  2. Antworten: 11
    Letzter Beitrag: 23.10.07, 11:32
  3. XSD-Problem mit gemeinsamen Typen
    Von Eko im Forum XML Technologien
    Antworten: 2
    Letzter Beitrag: 01.10.07, 19:48
  4. Antworten: 0
    Letzter Beitrag: 27.03.07, 14:13
  5. JNI Typen-Problem
    Von kroesi im Forum Java
    Antworten: 2
    Letzter Beitrag: 21.11.05, 12:57