tufan: snapshot von einem thread

hallo,

ich habe heute mit einem Java Problem zu kämpfen.
Folgende Situation:

Mein Programm soll verschiedene Sortieralgorithmen graphisch darstellen.
Sortieralgorithmen sollen nebenläufig ablaufen und es soll möglich sein, modular weitere Sortierallgorithmen hinzuzufügen.
Der Status des (sortierten) Arrays soll in einem vordefinierten Zeitintervall abgefragt und graphisch dargestellt werden.

  • Für die Modularität setze ich ein eigenes ClassLoader ein.
  • Sortierallgorithmen müssen mein Interface SortModule implementieren
  • und erweitern die Klasse Thread.

Mein Problem resultiert daraus, dass ich die durch das Constructer-Object von Reflect erstellte Instanz der Sortiermodule nicht in mein Interface SortModule casten kann.
Dafür ist folgender Code zuständig:

  
  Enumeration en = this.selectedAllgorithms.elements();  
  
      while(en.hasMoreElements())  
      {  
        String className = en.nextElement().toString();  
  
        String classPath = "pfad zur Klasse"+className;  
        CustomClassLoader ccl = new CustomClassLoader();  
  
        Class c = ccl.loadClass( classPath );  
  
        Constructor[] theConstructors = c.getConstructors();  
        Class[] parameterTypes = theConstructors[0].getParameterTypes();  
  
        Constructor cons = c.getConstructor(parameterTypes);  
  
        Object argumentsList[] = new Object[2];  
        argumentsList[0] = this;  
        argumentsList[1] = this.data;  
        Thread sm =  (Thread)cons.newInstance(argumentsList);  /* hier funktioniert der type cast in SortModule nicht: SortModule sm =  (SortModule)cons.newInstance(argumentsList); )*/  
        sm.start();  
      }  

da sm vom Typ Thread sein muss; kann ich die Variablen und Methoden meiner Sortierklasse nur über getField() und invoke() bekommen (wenn es andere Möglichkeiten gibt, bin ich froh, diese zu hören).
Ich habe jedoch keine Möglichkeit gefunden ein Integer Array zu erhalten (das Array, das sortiert werden soll; und von dem ich die Snapschüsse brauche).

Kontrollerklasse -- starts (mit dem obigen Code) --> BubbleSort (sortiert einwandfrei, in echtzeit kann ich auch eine sehr hübsche Animation darstellen.

Wie kann ich das ganze zeitversetzt visualisieren?
Ist es möglich, dass sm alle 300 ms irgendwie das Array an die Kontrollerklasse schmeisst (welche es fängt, und daraus ein Bild generiert)?
oder alle 300ms holt sich die Kontrollerklasse das Array vom sm?

Bin für Vorschläge dankbar.

Grüße aus Berlin,

tufi

  1. Hallo,

    Mein Programm soll verschiedene Sortieralgorithmen graphisch darstellen.
    Sortieralgorithmen sollen nebenläufig ablaufen und es soll möglich sein, modular weitere Sortierallgorithmen hinzuzufügen.

    Algorithmus schreibt man mit nur einem l. Oben schreibst du es zweimal
    richtig. Danach immer falsch, auch im Quellcode.

    • Für die Modularität setze ich ein eigenes ClassLoader ein.

    Die URLClassLoader-Klasse hätte es evtl. auch getan. Aber ein eigener
    ClassLoader schadet eigentlich auch nicht, sofern man keine Bugs
    reinprogrammiert. :)

    • Sortierallgorithmen müssen mein Interface SortModule implementieren

    Klingt sinnvoll.

    • und erweitern die Klasse Thread.

    Könnte man die Start-Methode nicht auch mit in SortModule reinnehmen?
    Ob die Klasse nun von Thread ableitet oder nur eine Start-Methode
    anbietet, die dann vielleicht an einen Thread delegiert, ist doch
    eigentlich egal.

    Mein Problem resultiert daraus, dass ich die durch das Constructer-Object von Reflect erstellte Instanz der Sortiermodule nicht in mein Interface SortModule casten kann.

    Warum nicht? Das sollte schon gehen.

    Dafür ist folgender Code zuständig:

    Enumeration en = this.selectedAllgorithms.elements();

    Schau dir mal iterator() und Iterator an. Das ist die "modernere"  
    Methode des Java Collections Framework, das die Enumeration-Geschichte  
    ablösen sollte. Steht auch so im Javadoc der Enumeration-Klasse.  
      
    
    >   
    >       while(en.hasMoreElements())  
    >       {  
    
    [...]  
    
    >   
    >         Object argumentsList[] = new Object[2];  
    >         argumentsList[0] = this;  
    >         argumentsList[1] = this.data;  
    >         Thread sm =  (Thread)cons.newInstance(argumentsList);  /\* hier funktioniert der type cast in SortModule nicht: SortModule sm =  (SortModule)cons.newInstance(argumentsList); )\*/  
      
    Keine Ahnung, wieso das nicht gehen soll. Es scheint für mich gültiger  
    Java-Code zu sein. Zumindest solange das zu instanzierende Objekt  
    tatsächlich das Interface "SortModule" implementiert. (Allerdings  
    habe ich es jetzt nicht ausprobiert.)  
      
    Was passiert, wenn du "sm" nachträglich nach "SortModule" castest?  
      
    Wie genau äußert sich das "funktioniert nicht" eigentlich? Welche  
    Fehlermeldung erscheint?  
      
    
    > Ich habe jedoch keine Möglichkeit gefunden ein Integer Array zu erhalten (das Array, das sortiert werden soll; und von dem ich die Snapschüsse brauche).  
      
    Aus der Javadoc-Doku von java.lang.reflect.Method.invoke():  
    "If the method completes normally, the value it returns is returned  
    to the caller of invoke; if the value has a primitive type, it is  
    first appropriately wrapped in an object. However, if the value has  
    the type of an array of a primitive type, the elements of the array  
    are not wrapped in objects; in other words, an array of primitive  
    type is returned."  
      
    
    > Wie kann ich das ganze zeitversetzt visualisieren?  
    > Ist es möglich, dass sm alle 300 ms irgendwie das Array an die Kontrollerklasse schmeisst (welche es fängt, und daraus ein Bild generiert)?  
    > oder alle 300ms holt sich die Kontrollerklasse das Array vom sm?  
      
    Letzteres würde nach meinem Verständnis mehr Sinn machen. Wieso sollte  
    die Sortier-Klasse wissen wie oft die GUI aktualisiert werden soll?  
      
    Nimm doch eine der Timer-Klassen, um den Zustand der Sortier-Klassen  
    kontinuierlich abzufragen. Für GUIs am besten javax.swing.Timer.  
      
    Gruß  
    Slyh  
      
    PS: Beim Durchlesen kam mir mein Posting etwas mürrisch vor. Falls dem  
    so sein sollte: Es ist nicht mürrisch. :-)
    
    1. Hallo Slyh,

      Algorithmus schreibt man mit nur einem l. Oben schreibst du es zweimal
      richtig. Danach immer falsch, auch im Quellcode.

      danke. künftig weiss ich es besser :-)

      Die URLClassLoader-Klasse hätte es evtl. auch getan. Aber ein eigener
      ClassLoader schadet eigentlich auch nicht, sofern man keine Bugs
      reinprogrammiert. :)

      hmm.. scheint bisjetzt gut zu laufen. Ausserdem kompiliert mein ClassLoader auch .java dateien, wenn es sein muss.

      Könnte man die Start-Methode nicht auch mit in SortModule reinnehmen?
      Ob die Klasse nun von Thread ableitet oder nur eine Start-Methode
      anbietet, die dann vielleicht an einen Thread delegiert, ist doch
      eigentlich egal.

      SortModule ist ein interface. Ich könnte höchstens noch definieren, dass die abgeleiteten Klassen eine run() Methode haben sollen. Wäre aber IMHO nicht sinnvoll.

      Schau dir mal iterator() und Iterator an. Das ist die "modernere"
      Methode des Java Collections Framework, das die Enumeration-Geschichte
      ablösen sollte. Steht auch so im Javadoc der Enumeration-Klasse.

      wenn mir noch Zeit bleibt, werde ich auf Iterator umstellen. Danke für den Tipp.

      Keine Ahnung, wieso das nicht gehen soll. Es scheint für mich gültiger
      Java-Code zu sein. Zumindest solange das zu instanzierende Objekt
      tatsächlich das Interface "SortModule" implementiert. (Allerdings
      habe ich es jetzt nicht ausprobiert.)

      eben, das war auch mein Problem. Ich habe auch keine Ahnung warum das nicht geht. Hat mich eine Menge nerven gekostet bisjetzt.

      Was passiert, wenn du "sm" nachträglich nach "SortModule" castest?

      Wie genau äußert sich das "funktioniert nicht" eigentlich? Welche
      Fehlermeldung erscheint?

      ClassCastException ist die Folge. Die Ausführung wird beendet.

      Ich habe jedoch keine Möglichkeit gefunden ein Integer Array zu erhalten (das Array, das sortiert werden soll; und von dem ich die Snapschüsse brauche).

      Aus der Javadoc-Doku von java.lang.reflect.Method.invoke():
      "If the method completes normally, the value it returns is returned
      to the caller of invoke; if the value has a primitive type, it is
      first appropriately wrapped in an object. However, if the value has
      the type of an array of a primitive type, the elements of the array
      are not wrapped in objects; in other words, an array of primitive
      type is returned."

      jepp. Aber, ich hatte bis vor ein paar Stunden nicht die aktuellste Java Version. Da hat invoke immer nur "gewrapptes" Object zurückgeliefert.

      Letzteres würde nach meinem Verständnis mehr Sinn machen. Wieso sollte
      die Sortier-Klasse wissen wie oft die GUI aktualisiert werden soll?

      Nimm doch eine der Timer-Klassen, um den Zustand der Sortier-Klassen
      kontinuierlich abzufragen. Für GUIs am besten javax.swing.Timer.

      hmm.. damit das möglich ist, muss ich das type-casting-Problem (s.o.)lösen.

      PS:
      Das Interface SortModule:

        
      public interface SortModule  {  
       public void swap (int idx1, int idx2);  
       public void draw(int index, int wert);  
      }  
      
      

      Grüsse aus Berlin

      tufi.

    2. hallo wieder,

      Keine Ahnung, wieso das nicht gehen soll. Es scheint für mich gültiger
      Java-Code zu sein. Zumindest solange das zu instanzierende Objekt
      tatsächlich das Interface "SortModule" implementiert. (Allerdings
      habe ich es jetzt nicht ausprobiert.)

      Irgendwie kann ich meine abgeleiteten Klassen nicht casten; auch nicht, wenn ich deren Typ selber angebe. Selbst folgender Code liefert ein Exception:

        
      BubleSort o = (BubleSort)cons.newInstance(argumentsList);  
        
      Exception in thread "Thread-2" java.lang.ClassCastException: ub4.util.BubbleSort cannot be cast to ub4.util.BubbleSort  
       at ub4.gui.Visualiser.run(Visualiser.java:140)  
       at java.lang.Thread.run(Unknown Source)  
      
      

      Warum kann ein "gewrapptes" BubbleSort nicht in ein BubleSort umgewandelt werden?
      und warum funktioniert (Thread)cons.newInstance(argumentsList);, wenn BubbleSort Thread erweitert?

      Grüße aus Berlin,

      tufi

      1. Hallo,

        BubleSort o = (BubleSort)cons.newInstance(argumentsList);

        Exception in thread "Thread-2" java.lang.ClassCastException: ub4.util.BubbleSort cannot be cast to ub4.util.BubbleSort
        at ub4.gui.Visualiser.run(Visualiser.java:140)
        at java.lang.Thread.run(Unknown Source)

          
        Daß du einmal BubleSort und ein BubbleSort schreibst, ist nur ein Fehler  
        in deinem Beispiel, nicht in deinem Code, ja?  
          
        
        > Warum kann ein "gewrapptes" BubbleSort nicht in ein BubleSort umgewandelt werden?  
          
        Das ist seltsam. Sehr seltsam. Kann es sein, daß dein ClassLoader vielleicht  
        doch nicht korrekt funktioniert?  
        Wird die BubbleSort-Klasse dynamisch kompiliert? Das könnte ein Problem  
        sein, weil die VM dadurch evtl. erkennt, daß es sich um zwei verschiedene  
        Klassen handelt. (Nur weil beide Klassen gleich heißen, müssen sie ja  
        nicht identisch sein.)  
          
        Aber so aus der Entfernung fällt es mir jetzt etwas schwer, den Fehler  
        genauer einzugrenzen.  
        Debugge doch mal deinen ClassLoader und schau nach, wo die ClassCastException  
        genau geworfen wird, also welche Vorbedingung nicht erfüllt wird, durch  
        die es zur ClassCastException kommt. Ich bin mir ziemlich sicher, daß  
        das Problem irgendwo beim dynamischen Kompilieren oder beim Klasse-  
        Laden liegt...  
          
        Gruß  
        Slyh  
        
        
        1. Hallo,

          Debugge doch mal deinen ClassLoader und schau nach, wo die ClassCastException
          genau geworfen wird, also welche Vorbedingung nicht erfüllt wird, durch
          die es zur ClassCastException kommt.

          Vergiss den obenstehenden Satz. Der ist ja mal sowas von falsch. :-)

          Gruß
          Slyh

        2. hallo Slyh,

          Daß du einmal BubleSort und ein BubbleSort schreibst, ist nur ein Fehler
          in deinem Beispiel, nicht in deinem Code, ja?

          jepp, nur ein Tippfehler in diesem Beispiel.

          Das ist seltsam. Sehr seltsam. Kann es sein, daß dein ClassLoader vielleicht
          doch nicht korrekt funktioniert?

          Also für das Casting-Problem habe ich glaube ich eine Erklärung gefunden:
          [zitat]
          Identical classes loaded by different classloaders are considered to be different classes by the JVM [/zitat]
          Es scheint, das Problem resultierte tatsächlich, auch wenn nur indirekt, aus meinem ClassLoader. Es fehlt mir aber immer noch die Möglichkeit, wie ich meine Instanz trotz allen casten kann.
          Du hattest UrlClassLoader erwaehnt. Das werde ich ausprobieren, sobald ich Zuhause bin. Wenn es mit dem URLClassLoader klappt, dann bin ich sogar bereit, auf das dynamische kompilieren zu verzichten :)

          Werde darüber nochmal berichten.

          Grüße aus Berlin,

          tufi

          1. hallo,

            Werde darüber nochmal berichten.

            der URLClassLoader wirft ClassNotFoundException raus.
            Und da mir die Zeit wegrennt, werde ich -im Moment- auf dessen Verwendung verzichten müssen.
            Muss wohl, ohne direkten Zugriff auf die Klassenvariablen auskommen.

            Danke für die Hilfe.
            Grüße aus Berlin,

            tufi