Pagina 1 di 2 1 2 ultimoultimo
Visualizzazione dei risultati da 1 a 10 su 11

Discussione: reflection

  1. #1

    reflection

    Ciao,
    sono Antonio

    spiego il problema e sotto inserirò il codice

    ho una classe "main" che crea un Oggetto di tipo A e su di
    esso chiama un metodo x(). Tale metodo crea un file B.java.
    Vorrei a questo punto che il "main" proseguisse nel suo
    lavoro creando un oggetto di classe B e utilizzando i suoi
    metodi.
    Ovviamente non si può fare.
    Il mio main ogni volta lanciato genera la classe B
    assegnandogli diciamo un parametro che poi stamperà. Ho
    usato quindi
    Class b = Class.forName("prova.B");
    B bbb =(B) b.newInstance();
    e tutta una serie di comande per cercare di risolvere il
    problema che è il seguente:

    La classe viene creata, riesco a generare anche il .class ma
    viene utilizzato l'oggetto B creato nell'esecuzione
    precedente, cioè se la classe B è esistente e ha
    parametro H e adesso lancio il main che a B da J cmq
    stamperà H e la volta seguente J ma a quel punto gli ho
    passato L.
    Quindi mi serve qualcosa che aggiorni il .class che deve
    essere caricato a runtime...



    CODICE

    allora quest'è la classa che viene utilizzata dal Main che no fa altro che creare un file B.java. Il file B ha al suo interno una variabile di volta in volta diversa che verrà poi stampata su console.
    ---
    public class A
    {
    public void generare(String prova)
    {
    try
    {
    String nameComplete="src\\prova\\B.java";
    File f=new File(nameComplete);
    FileOutputStream fos;
    fos = new FileOutputStream(f);
    PrintStream ps=new PrintStream(fos);
    ps.println("package prova;");
    ps.println("public class B");
    ps.println("{");
    ps.println("String daStampare=\"" + prova + "\";");
    ps.println("public void stampa()");
    ps.println("{");
    ps.println("System.out.println(daStampare);");
    ps.println("return; }");
    ps.println("}");
    ps.close();
    }
    catch (Exception e)
    {
    e.printStackTrace();

    }
    }
    }
    -----
    la classe B quindi è generata a run time, metre questo è il main:
    public class Main extends ClassLoader
    {


    public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException
    {
    A a = new A();
    Scanner in = new Scanner(System.in);
    System.out.println("scrivi stringa che dovrà stamapre classe B");
    String prova = in.nextLine();
    a.generare(prova);




    Class c = Class.forName("prova.B");
    B b =(B) c.newInstance();
    b.stampa();
    }
    }
    -------
    lo scopo è quindi far stamapre ogni volta la nuova stringa. Da notare che tutto gira se e solo se è presente la vecchia versione della classe B che è del tipo:
    package prova;
    public class B
    {
    String daStampare="eee";
    public void stampa()
    {
    System.out.println(daStampare);
    return; }
    }


    perchè altrimenti quando genere un oggetto di tipo B mi da errore.



    grazie mille..
    Antonio

  2. #2
    Moderatore di Programmazione L'avatar di LeleFT
    Registrato dal
    Jun 2003
    Messaggi
    17,328
    Quello che chiedi di poter fare non lo puoi fare in questo modo per il semplice fatto che se il tuo programma A utilizza una classe B, questa deve esistere prima di poter compilare A. Perchè il compilatore deve risolverne tutti i riferimenti quando compila A...

    Quello che puoi fare è definire un'interfaccia (o una super-classe) e generare a runtime un oggetto che derivi da questa interfaccia o super-classe.

    In questo modo istanzierai un oggetto dell'interfaccia (o super-classe) e ne utilizzerai i metodi...

    A grandi linee dovresti fare questo:
    codice:
    public abstract Base {
       ...
       public abstract void stampa(...);
    }
    Compili questa classe, quindi produci il tuo programma A:
    codice:
    public class A {
       ...
       ps.println("public class B extends A {");
       ...
       ps.println("public void stampa(...) {");
       ...
       // Compili B
       ...
       Class c = Class.forName("prova.B");
       A b =(A) c.newInstance();
       b.stampa();
    }
    In pratica devi sfruttare il polimorfismo...

    Un giorno ci spiegherai anche perchè hai deciso di fare tutto questo...

    Ciao.
    "Perchè spendere anche solo 5 dollari per un S.O., quando posso averne uno gratis e spendere quei 5 dollari per 5 bottiglie di birra?" [Jon "maddog" Hall]
    Fatti non foste a viver come bruti, ma per seguir virtute e canoscenza

  3. #3
    Utente di HTML.it L'avatar di andbin
    Registrato dal
    Jan 2006
    residenza
    Italy
    Messaggi
    18,284

    Re: reflection

    Originariamente inviato da peperosso.eu
    ho una classe "main" che crea un Oggetto di tipo A e su di
    esso chiama un metodo x(). Tale metodo crea un file B.java.
    Vorrei a questo punto che il "main" proseguisse nel suo
    lavoro creando un oggetto di classe B e utilizzando i suoi
    metodi.
    Motivo di tutto ciò?? Cioè, voglio dire, quale è lo scopo finale??

    A parte il fatto che "buttare" una stringa in un sorgente come hai fatto non è il massimo. E se la tua stringa contiene un apice doppio?? O un backslash?? O peggio ancora un newline?? (ricordo che nelle stringhe literal, all'interno di " ... " non si può andare a capo).

    Originariamente inviato da peperosso.eu
    Quindi mi serve qualcosa che aggiorni il .class che deve
    essere caricato a runtime...
    http://mindprod.com/jgloss/reloading.html
    Andrea, andbin.devSenior Java developerSCJP 5 (91%) • SCWCD 5 (94%)
    java.util.function Interfaces Cheat SheetJava Versions Cheat Sheet

  4. #4
    Grazie per le celeri risposte.
    Il tutto mi serve perché ho creato un compilatore e a runtime vorrei che un executor eseguisse il tutto, l'esempio che ho caricato stampa solo una stringa (quindi versione stupida del compilatore).

    Ho creato le classi come detto da LeleFT e sono le seguenti:
    ------
    package prova;

    public abstract class Base
    {
    public abstract void stampa();
    }
    ------
    package prova;

    import java.util.Scanner;
    public class Main extends ClassLoader
    {
    public static void main(String[] args)
    {
    try
    {
    A a = new A();
    Scanner in = new Scanner(System.in);
    System.out.println("scrivi stringa che dovrà stamapre classe B");
    String prova = in.nextLine();
    a.generare(prova);
    System.out.println("fine");
    } catch (Exception e)
    {

    e.printStackTrace();
    System.out.println("exception");
    }

    }
    }
    -------

    package prova;

    import java.io.File;
    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.PrintStream;
    import java.nio.channels.FileChannel;

    public class A
    {
    public void generare(String prova)
    {
    try
    {
    String nameComplete="src\\prova\\B.java";
    File f=new File(nameComplete);
    FileOutputStream fos;
    fos = new FileOutputStream(f);
    PrintStream ps=new PrintStream(fos);
    ps.println("package prova;");

    ps.println("public class B extends Base");


    ps.println("{");
    ps.println("String daStampare=\"" + prova + "\";");
    ps.println("public void stampa()");
    ps.println("{");
    ps.println("System.out.println(daStampare);");
    ps.println("return; }");
    ps.println("}");
    ps.close();



    Thread.sleep(5000);
    try
    {
    Process p = Runtime.getRuntime().exec("javac C:\\Users\\antonio\\workspace\\provaDinamica\\src\ \prova\\B.java");
    } catch (Exception e)
    {
    // TODO Auto-generated catch block
    e.printStackTrace();
    }

    Thread.sleep(5000);
    File input = new File("C:\\Users\\antonio\\workspace\\provaDinamica \\src\\prova\\B.class");
    File out = new File("C:\\Users\\antonio\\workspace\\provaDinamica \\bin\\prova\\B.class");

    FileChannel sourceChannel = new FileInputStream(input).getChannel();
    FileChannel destinationChannel = new FileOutputStream(out).getChannel();
    sourceChannel.transferTo(0, sourceChannel.size(), destinationChannel);
    sourceChannel.close();
    destinationChannel.close();
    Thread.sleep(5000);



    Class c = Class.forName("prova.B");
    Base b =(Base) c.newInstance();
    b.stampa();





    }
    catch (Exception e)
    {
    e.printStackTrace();

    }
    }
    }
    ---------------

    ma mia da questo errore e il tutto si interrompe
    java.lang.ClassCastException: prova.B cannot be cast to prova.Base
    at prova.A.generare(A.java:77)
    at prova.Main.main(Main.java:28)


    sai aiutarmi?

    grazie
    Antonio

  5. #5
    Moderatore di Programmazione L'avatar di LeleFT
    Registrato dal
    Jun 2003
    Messaggi
    17,328
    Originariamente inviato da peperosso.eu
    ma mia da questo errore e il tutto si interrompe
    java.lang.ClassCastException: prova.B cannot be cast to prova.Base
    at prova.A.generare(A.java:77)
    at prova.Main.main(Main.java:28)


    sai aiutarmi?

    grazie
    Antonio
    Quando ho scritto l'esempio l'ho scritto in fretta: se la classe si chiama "prova.Base" allora dovrai scrivere (sul println() ) "prova.Base" e non "prova.B" come ho scritto io... cioè bisogna usare coerenza: io creo un file che si chiama "Base.java" all'interno della directory "prova", quindi la classe dovrà chiamarsi "prova.Base" e non "prova.B"...


    PS: quando posti del codice, utilizza i tag [code] e [/code] (come indicato anche nel regolamento) altrimenti non si capisce nulla, perdendo indentazione e stile del carattere...


    Ciao.
    "Perchè spendere anche solo 5 dollari per un S.O., quando posso averne uno gratis e spendere quei 5 dollari per 5 bottiglie di birra?" [Jon "maddog" Hall]
    Fatti non foste a viver come bruti, ma per seguir virtute e canoscenza

  6. #6
    Ciao e di nuovo grazie per la risposta, scusami per il tag html dimenticato!
    In ogni caso la classe Base è l'Abstract, il main chiama la classe A che crea un file B. B estende la classe Base.
    Quindi io avevo fatto:
    codice:
    	        Class c = Class.forName("prova.B");
    	        Base b =(Base) c.newInstance();
    	        b.stampa();
    e adesso ho corretto con
    codice:
    	        Class c = Class.forName("prova.Base");
    	        Base b =(Base) c.newInstance();
    	        b.stampa();
    ma non capisco come faccia a capire che deve prendere la classe B se non la specifico in Class.forName.


    In ogni caso mi da questo errore:

    codice:
    java.lang.InstantiationException
    	at sun.reflect.InstantiationExceptionConstructorAccessorImpl.newInstance(Unknown Source)
    	at java.lang.reflect.Constructor.newInstance(Unknown Source)
    	at java.lang.Class.newInstance0(Unknown Source)
    	at java.lang.Class.newInstance(Unknown Source)
    	at prova.A.generare(A.java:71)
    	at prova.Main.main(Main.java:18)
    su

    codice:
     Base b =(Base) c.newInstance();
    grazie !!!!

  7. #7
    Moderatore di Programmazione L'avatar di LeleFT
    Registrato dal
    Jun 2003
    Messaggi
    17,328
    Faccio prima a postarti un esempio funzionante:

    Questa è la classe astratta di base (che ho chiamato "A"):
    codice:
    public abstract class A {
       public abstract void metodo();
    }
    Questa è la classe "Compila" che appunto crea la classe B (derivata da A), la compila, la istanzia e ne esegue il metodo:
    codice:
    import java.io.*;
    public class Compila {
       public static void main(String[] args) throws Exception {
          PrintStream ps = new PrintStream( new FileOutputStream("B.java") );
          ps.println("public class B extends A {");
          ps.println("   public void metodo() {");
          ps.println("      System.out.println(\"Ciao dalla classe B\");");
          ps.println("   }");
          ps.println("}");
          ps.close();
    
          Runtime r = Runtime.getRuntime();
          r.exec("javac B.java");
    
          System.out.println("Attendo che la compilazione abbia termine");
    
          Thread.sleep( 5000 );
    
          Class c = Class.forName("B");
          A miaClasse = (A) c.newInstance();
          miaClasse.metodo();
       }
    }
    Per non complicarmi la vita a creare directory, ho evitato l'uso dei package, ma questo è solo un dettaglio per risparmiarmi il tempo...


    Ciao.
    "Perchè spendere anche solo 5 dollari per un S.O., quando posso averne uno gratis e spendere quei 5 dollari per 5 bottiglie di birra?" [Jon "maddog" Hall]
    Fatti non foste a viver come bruti, ma per seguir virtute e canoscenza

  8. #8
    Ovviamente ti ringrazio per quello che hai fatto sino ad adesso
    Il tuo codice funziona perfettamente, ma "in parte".
    Fino ad adesso io ho sempre usato Eclipse, considera che come ti ho detto ho creato un compilatore (12000 righe più o meno e innumerevoli classi) per cui impossibile senza Eclipse o simili. Ho provato il tuo codice su Eclipse (modificando ovviamente package e altro) ma nulla. Stesso problema. Cioè se provi esattamente il tuo con i package etc funziona ma è un "falso" funzionamento, in pratica nel tuo esempio la classe B stampa sempre la stessa cosa, ho provato quindi ad aggiungere la solita stringa che prende da input e stampa (andrebbe bene anche un random) in modo che ogni volta che il tutto viene lanciato differisce dalla volta precedente. Fattostà che non stampa mai la nuova stringa.

    Se faccio tutto ciò tramite console il tutto funziona magicamente, per cui ti ringrazio di nuovo

    Il problema quindi è che o Eclipse ha qualche specie di cache, ma mi sembra strano o non ne ho idea. In ogni caso i .class Eclipse li mette nella cartella "bin" e quindi bisogna stare attenti a ciò ma ho fatto tantissime prove ma nulla.

    Riusciresti a risolvermi il problema anche da li dentro?
    In ogni caso sei stato davvero mitico e ti ringrazio davvero tanto!!!

    Antonio

    P.S.

    Ti posto in ogni caso la classe Compila con la semplice modifica che chiede all'utente una Stringa (ovviamente deve essere diversa da qualla precedente)

    codice:
    import java.io.*;
    import java.io.FileOutputStream;
    import java.io.PrintStream;
    import java.util.Scanner;
    
    public class Compila {
       public static void main(String[] args) throws Exception {
          PrintStream ps = new PrintStream( new FileOutputStream("B.java") );
          System.out.println("scrivi la stringa che dovrà stampare classe B");
          Scanner in = new Scanner(System.in);
          String prova = in.nextLine();
    
          ps.println("public class B extends A {");
          ps.println("   public void metodo() {");
          ps.println("      System.out.println(\"Ciao dalla classe B\");");
          ps.println("      System.out.println(\" "+ prova +" \");");
          ps.println("   }");
          ps.println("}");
          ps.close();
    
          Runtime r = Runtime.getRuntime();
          r.exec("javac B.java");
    
          System.out.println("Attendo che la compilazione abbia termine");
    
          Thread.sleep( 5000 );
    
          Class c = Class.forName("B");
          A miaClasse = (A) c.newInstance();
          miaClasse.metodo();
       }
    }

  9. #9
    Moderatore di Programmazione L'avatar di LeleFT
    Registrato dal
    Jun 2003
    Messaggi
    17,328
    Anche con la tua modifica a me funziona perfettamente (sia eliminando i due file prodotti dall'esecuzione precedente, sia lasciandoli lì senza toccarli fra due esecuzioni consecutive).

    E' probabile che sia un "problema" di Eclipse. Evidentemente lui genera i .class in due posti diversi (uno per l'esecuzione e uno per la distribuzione del progetto).

    Evidentemente una delle due viene utilizzata dall'applicazione quando è in funzione e non viene toccata dalla compilazione effettuata da essa stessa.

    E' per questo che io preferisco sempre fare i test al di fuori dell'ambiente di sviluppo: l'applicazione alla fine dovrà girare senza di lui... tanto vale che i test vengano fatti senza di lui.


    Prova a portare il progetto compilato in una directory diversa (magari anche in una macchina diversa) e fai le prove lì, dove Eclipse non può intervenire.


    PS: io le applicazioni le avvio sempre a mano dal Prompt dei Comandi (o dalla shell se sono sotto Linux).

    Ciao.
    "Perchè spendere anche solo 5 dollari per un S.O., quando posso averne uno gratis e spendere quei 5 dollari per 5 bottiglie di birra?" [Jon "maddog" Hall]
    Fatti non foste a viver come bruti, ma per seguir virtute e canoscenza

  10. #10
    ciao,
    ovviamente da console con il tuo esempio funziona tutto.
    Il problema è che sono costretto ad usare eclipse, ora ti spiego. Il mio Compilatore dovrà "girare sul web" quindi faccio un war di tutto il progetto e lo deployo con Tomcat. Il war lo crea Eclipse. Quindi metto i package e tutto il resto. Il problema è che Tomcat non riesce a compilare ma lo riuscirebbe a fare qualora Eclipse lo facesse e nemmeno lui lo fa.
    L'errore secondo me sta nella cartella di base dove compilo, infatti da console posso compilare qualsiasi classe qualora questa non ne usi altre usando il path completo a partire da C o altri se mi trovo in altri punti. Se la classe fa uso di altre (come nel caso nostro dato che ci sta una classe astratta) per compilare da console devo andare fino al package precedente e fare uan cosa del tipo "javac cartella\classeA.java" e così compila sia l'astratta che quella che serve. Quindi molto probabielmente serve qualche istruzione che dica al metodo exec di Runtime.getRuntime() dove posizionarsi. Ho provato a mettere un array di istruzioni con la prima che posiziona il path ma nulla.
    Sapresti aiutarmi?

    ovviamente grazie in anticipo e sempre grazie per l'iuto datomi sino ad adesso
    Antonio

Permessi di invio

  • Non puoi inserire discussioni
  • Non puoi inserire repliche
  • Non puoi inserire allegati
  • Non puoi modificare i tuoi messaggi
  •  
Powered by vBulletin® Version 4.2.1
Copyright © 2025 vBulletin Solutions, Inc. All rights reserved.