【问题标题】:Dynamic Class Loading in Java (Enumeration)Java中的动态类加载(枚举)
【发布时间】:2010-11-19 11:51:24
【问题描述】:

我有一个问题,我希望在运行时使用反射来生成一组类中的一个的实例。然而,我遇到了一个障碍。我想让所有涉及的类都注册自己,以便可以从 GUI 中选择适当的类。我可以使用每个文件中的静态代码块来执行此操作,它提供了一个整洁的 OO 解决方案。但是,java 类加载器会在需要时专门加载类,因此如果需要的类尚未使用,则不会注册。

没有直接提供静态名称列表,或者运行底层类/java文件(无论如何打包到jar中都会中断),有没有办法强制加载某些包的类?

基本上,我希望能够从指定的超类添加新类,而无需更改/添加任何其他代码。

【问题讨论】:

标签: java reflection oop


【解决方案1】:

澄清一下,您的问题不在于“Java 中的动态类加载”,而在于动态类枚举——您知道如何加载类,只是不知道您使用什么类想要。

Google 很快想到了这个页面:http://forums.sun.com/thread.jspa?threadID=341935&start=0&tstart=0

取自该页面,下面是一些应该可以工作的示例代码:

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

【讨论】:

  • @Hubris:哦,不……那是 a) 在文件系统中运行,它很难看,而且会破坏 DRY……:stackoverflow.com/questions/1275113/…
  • @Daniel:以防万一你没有注意到你发现你正在加载类: classes.add( Class.forName( .....
【解决方案2】:

Spring Framework 根据注解进行组件扫描。

ClassPathScanningCandidateComponentProvider 类为例。您可以基于接口/基类做同样的事情,它应该适用于所有 LOCAL 类。对于 java 中的 ALL 类,没有办法做到这一点。

【讨论】:

    【解决方案3】:

    Class.forName("这里的类名");

    您将拥有一个带有类名的字符串变量。 假设您有一个包含所有要加载的类名的字符串列表(并使用静态代码块自动注册:

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

    【讨论】:

    • 我想你误会了...我不想提供静态名称。
    • 它不是静态的。我向您展示了如何(编辑后)。如果要列出包中的每个类,不遍历文件系统是不可能的。按照设计,Java 中的类加载器不能列出类(考虑基于 HTTP 的类加载器),但如果您知道将使用默认的类加载器,则可以浏览所有文件夹和所有 jar(它们是 zip 文件)对于属于您的包的类。无论如何,提供类列表作为程序的配置/输入更安全,更易于实现。
    【解决方案4】:

    通过这个例子:

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

    【讨论】:

    • 是的,这行得通,但为了做到这一点,你必须有一个静态的类名列表......
    【解决方案5】:

    如果你的类在文件系统中的 jars 中是有可能的(这可能听起来很荒谬,但我已经看到从 ldaps 加载的类)

    所以,如果你的类在 jars 中的文件系统中,你可以执行以下操作:

    下面的伪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.
    

    我很久以前就做过类似的事情。

    我曾经使用这种方法在不到一秒的时间内加载大约 70k+ 类名称。就我而言,我正在动态寻找大约 10 个类,所以整个过程花了我大约 1.1 秒。

    【讨论】:

      【解决方案6】:

      【讨论】:

        【解决方案7】:

        我建议将所有“动态”类放入一个包中。扫描该目录以提取每个文件名,然后在 Class.forName() 中使用该文件名来加载和注册每个类。

        我昨天刚问了一个类似的问题,得到了一些很好的反馈。

        Create new class from a Variable in Java

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-02-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多