简体   繁体   English

Java中的动态类加载(枚举)

[英]Dynamic Class Loading in Java (Enumeration)

I have a problem, I wish to use reflection to generate instances of one of a set of classes at runtime. 我有一个问题,我希望使用反射在运行时生成一组类中的一个的实例。 However, I have hit a snag. 但是,我遇到了麻烦。 I want to get all of the classes involved to register themselves so the appropriate class can be chosen from a GUI. 我想让所有涉及的类都注册自己,这样就可以从GUI中选择合适的类。 I can do this using a static code block in each file which provides a tidy OO solution. 我可以在每个文件中使用静态代码块来提供整洁的OO解决方案。 However, the java class loader specifically loads classes when they are required, hence if a needed class has not yet been used, it is not registered. 但是,java类加载器在需要时专门加载类,因此如果尚未使用所需的类,则不会注册它。

Short of directly providing a static list of names, or running through the underlying class/java files (which would break when packaged into a jar anyway), is there any way to force classes of certain packages to be loaded? 如果没有直接提供静态名称列表,或者运行底层的类/ java文件(无论如何打包到jar中都会破坏),有没有办法强制加载某些包的类?

Basically, I want the ability to add new classes, from a specified superclass, without having to change/add any other code. 基本上,我希望能够从指定的超类添加新类,而无需更改/添加任何其他代码。

To clarify, your problem isn't about "dynamic class loading in Java", it's about dynamic class enumeration -- you know how to load classes, you just don't know what classes you want. 澄清一下,你的问题不是关于“Java中的动态类加载”,而是关于动态类枚举 - 你知道如何加载类,你只是不知道你想要什么类。

A quick Google came up with this page: http://forums.sun.com/thread.jspa?threadID=341935&start=0&tstart=0 谷歌快速推出了这个页面: http//forums.sun.com/thread.jspa?threadID = 341935&start = 0&tstart = 0

Taken from that page, here's some sample code that ought to work: 从该页面开始,这里有一些应该有效的示例代码:

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;
}

Spring Framework does component scanning based on annotations. Spring Framework基于注释进行组件扫描。

Take a look at ClassPathScanningCandidateComponentProvider class, for example. 例如,查看ClassPathScanningCandidateComponentProvider类。 You can do the same thing based on interface / base class and it should work for all LOCAL classes. 您可以基于接口/基类执行相同的操作,它应该适用于所有LOCAL类。 There is no way to do this for ALL classes in java. 对于java中的所有类,无法执行此操作。

Class.forName("class name here"); Class.forName(“class name here”);

You'll have a String variable with the class name. 你将拥有一个带有类名的String变量。 Assuming you have a List of Strings containing all class names you want to be loaded (and automatically registered using static code blocks: 假设您有一个字符串列表,其中包含您要加载的所有类名(并使用静态代码块自动注册:

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

Go through this example: 通过这个例子:

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();
    }

}

There is a chance if your classes are in jars in the filesystem ( this may sound ridiculous but I've seen classes loaded from ldaps ) 如果您的类在文件系统中的jar中有可能(这可能听起来很荒谬,但我看过从ldaps加载的类)

So, again if your classes are in the filesystem inside jars you can do the following: 因此,如果您的类位于jar中的文件系统中,您可以执行以下操作:

Pseudo-java below: 下面的伪java:

  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.

I did this for a similar thing a long while ago. 我很久以前就做过类似的事情。

I use to load about 70k+ classes names using this approach in less than a second. 我用不到一秒钟就可以使用这种方法加载大约70k +类名。 In my case I was dynamically looking for about 10 classes so the whole process took me about 1.1 second. 在我的情况下,我动态地寻找大约10个类,所以整个过程花了我大约1.1秒。

I would suggest putting all the "dynamic" classes into one package. 我建议将所有“动态”类放入一个包中。 Scan that directory to pull out each filename and then use that in Class.forName() to load and register each class. 扫描该目录以获取每个文件名,然后在Class.forName()中使用它来加载和注册每个类。

I just asked a similar question yesterday, and got some good feedback. 我昨天刚问了一个类似的问题,得到了一些很好的反馈。

Create new class from a Variable in Java 从Java中的Variable创建新类

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM