2009-08-13 8 views
4

J'ai un problème, je souhaite utiliser la réflexion pour générer des instances d'un ensemble de classes au moment de l'exécution. Cependant, j'ai rencontré un problème. Je veux que toutes les classes impliquées s'inscrivent pour que la classe appropriée puisse être choisie à partir d'une interface graphique. Je peux le faire en utilisant un bloc de code statique dans chaque fichier qui fournit une solution OO bien rangé. Cependant, le chargeur de classes Java charge spécifiquement les classes lorsqu'elles sont requises. Par conséquent, si une classe nécessaire n'a pas encore été utilisée, elle n'est pas enregistrée. À moins de fournir directement une liste statique de noms, ou de parcourir les fichiers sous-jacents de classe/java (qui se casseraient quand ils sont empaquetés dans un pot de toute façon), est-il possible de forcer le chargement de certaines classes?Chargement de classe dynamique en Java (énumération)

Fondamentalement, je veux la possibilité d'ajouter de nouvelles classes, à partir d'une superclasse spécifiée, sans avoir à changer/ajouter un autre code.

+0

Il semble qu'il y ait eu un certain nombre de messages qui couvrent cela dans une certaine mesure, mais aucun ne semble fournir un moins-que-ex méthode extrêmement complexe ou satisfaisante de le faire. Voir: http://stackoverflow.com/questions/205573/java-at-runtime-find-all-classes-in-app-that-extend-a-base-class http: // stackoverflow. com/questions/176527/how-can-i-énumérer-toutes-classes-dans-un-paquet-et-ajouter-les-à-une-liste # 189525 – Hubris

+0

ou http://stackoverflow.com/questions/205573/java-at-runtime-find-all-classes-dans-app-that-extend-a-base-class – Hubris

+0

Je modifierais le titre de votre question, puisque vous demandez vraiment d'énumérer les classes disponibles, pas dynamiquement les charger. –

Répondre

3

Pour clarifier, votre problème ne concerne pas le "chargement de classe dynamique en Java", il s'agit de l'énumération de classe dynamique - vous savez comment charger des classes, vous ne savez pas quelles classes vous voulez.

Un rapide Google est venu avec cette page: http://forums.sun.com/thread.jspa?threadID=341935&start=0&tstart=0

Tiré de cette page, voici quelques exemples de code qui devrait fonctionner:

public static Class[] getClasses(String pckgname) 
     throws ClassNotFoundException { 
    ArrayList<Class> classes = new ArrayList<Class>(); 
    // Get a File object for the package 
    File directory = null; 
    try { 
     ClassLoader cld = Thread.currentThread().getContextClassLoader(); 
     if (cld == null) { 
      throw new ClassNotFoundException("Can't get class loader."); 
     } 
     String path = '/' + pckgname.replace('.', '/'); 
     URL resource = cld.getResource(path); 
     if (resource == null) { 
      throw new ClassNotFoundException("No resource for " + path); 
     } 
     directory = new File(resource.getFile()); 
    } catch (NullPointerException x) { 
     throw new ClassNotFoundException(pckgname + " (" + directory 
       + ") does not appear to be a valid package"); 
    } 
    if (directory.exists()) { 
     // Get the list of the files contained in the package 
     String[] files = directory.list(); 
     for (int i = 0; i < files.length; i++) { 
      // we are only interested in .class files 
      if (files[i].endsWith(".class")) { 
       // removes the .class extension 
       classes.add(Class.forName(pckgname + '.' 
         + files[i].substring(0, files[i].length() - 6))); 
      } 
     } 
    } else { 
     throw new ClassNotFoundException(pckgname 
       + " does not appear to be a valid package"); 
    } 
    Class[] classesA = new Class[classes.size()]; 
    classes.toArray(classesA); 
    return classesA; 
} 
+1

@Hubris: Ohh noooo .. c'est a) courir à travers le système de fichiers et c'est moche et se brise DRY .. .: http://stackoverflow.com/questions/1275113/dynamic-class-loading-in-java-enumeration/1275224#1275224 – OscarRyz

+1

@Daniel: Juste au cas où vous ne l'auriez pas remarqué dans votre découverte, vous chargez les classes de toute façon avec: classes.add (Class.forName (..... – OscarRyz

1

Classe.forName ("nom de la classe ici");

Vous aurez une variable String avec le nom de la classe. En supposant que vous avez une liste de chaînes contenant tous les noms de classe que vous voulez charger (et automatiquement enregistré à l'aide de blocs de code statiques:

pour (String className: classesToBeLoaded) Class.forName (className);

+0

Je pense que vous vous méprenez ... Je ne veux pas fournir un nom statique. – Hubris

+0

Ce n'est pas statique. Je vous ai montré comment (après l'édition). Si vous souhaitez répertorier chaque classe dans un package, cela est impossible si vous ne parcourez pas le système de fichiers. De par leur conception, les chargeurs de classes en Java ne peuvent pas lister les classes (pensez à un chargeur de classe HTTP), mais si vous savez que vous utiliserez le chargeur de classe par défaut, vous pouvez parcourir tous les dossiers et tous les fichiers. pour les classes appartenant à vos paquets. Quoi qu'il en soit, fournir la liste des classes comme configuration/entrée pour votre programme est plus sûr et plus facile à implémenter. – Marian

1

Go A travers cet exemple.

public class MainClass { 

    public static void main(String[] args){ 

    ClassLoader classLoader = MainClass.class.getClassLoader(); 

    try { 
     Class aClass = classLoader.loadClass("com.jenkov.MyClass"); 
     System.out.println("aClass.getName() = " + aClass.getName()); 
    } catch (ClassNotFoundException e) { 
     e.printStackTrace(); 
    } 

} 
+0

Oui, cela fonctionne, mais pour ce faire, vous devez avoir une liste statique de noms de classes ... – Hubris

0

Je suggère de mettre toutes les classes « dynamiques » dans un seul paquet parcourir ce répertoire pour retirer chaque nom de fichier et ensuite utiliser que dans Class.forName() pour charger et enregistrer chaque classe.

Je viens de poser une question similaire hier, et j'ai eu de bons commentaires.

Create new class from a Variable in Java

2

Spring Framework ne analyse composants à base sur les annotations.

Jetez un oeil à ClassPathScanningCandidateComponentProvider classe, par exemple. Vous pouvez faire la même chose en fonction de la classe interface/base et cela devrait fonctionner pour toutes les classes LOCAL. Il n'y a aucun moyen de le faire pour toutes les classes en java.

1

Il y a une chance si vos classes sont dans des pots dans le système de fichiers (cela peut sembler ridicule mais j'ai vu les classes chargées de ldaps)

Donc, encore une fois si vos classes sont dans le système de fichiers à l'intérieur des pots, vous pouvez procédez comme suit:

Pseudo-java ci-dessous:

String classPath = System.getClassPath(); 
    String [] classPathParts = classpath.split(";"); // or : 

    String [] allTheClasses = [] 

    for each (file in classPathParts) { 
     if(file is directory) { 
      allTheClasses.addAll(file.contents); 
     } else if (file is ".jar") { 
      allTheClasses.addAll(getZippedNamesFrom(file)); 

     } 
} 

// At this point you would have all the classes in the array (list) . 

String [] packageNames = {"a.b.c", "d.e.f" }; 
for each (String clazzName in allTheClasses) { 
     if (packageNames.contains(clazzName.getPackageName())) { 
      Class.forName(clazzName); // load it and have the static block run 
      // Or run it your self 
     } 
} 

// End of the story. 

Je l'ai fait pour une chose semblable il y a longtemps.

J'utilise pour charger environ 70k + noms de classes en utilisant cette approche en moins d'une seconde. Dans mon cas, je recherchais dynamiquement environ 10 classes, ce qui m'a pris environ 1,1 seconde.

Questions connexes