当前位置:  开发笔记 > 编程语言 > 正文

在Java中,是否可以知道是否已经加载了一个类?

如何解决《在Java中,是否可以知道是否已经加载了一个类?》经验,为你挑选了4个好方法。

是否可以知道是否已加载Java类而不尝试加载它?Class.forName试图加载该类,但我不希望这种副作用.还有另外一种方法吗?

(我不想覆盖类加载器.我正在寻找一种相对简单的方法.)



1> Stephen Denn..:

(感谢Aleksi)这段代码:

public class TestLoaded {
     public static void main(String[] args) throws Exception {
          java.lang.reflect.Method m = ClassLoader.class.getDeclaredMethod("findLoadedClass", new Class[] { String.class });
          m.setAccessible(true);
          ClassLoader cl = ClassLoader.getSystemClassLoader();
          Object test1 = m.invoke(cl, "TestLoaded$ClassToTest");
          System.out.println(test1 != null);
          ClassToTest.reportLoaded();
          Object test2 = m.invoke(cl, "TestLoaded$ClassToTest");
          System.out.println(test2 != null);
     }
     static class ClassToTest {
          static {
               System.out.println("Loading " + ClassToTest.class.getName());
          }
          static void reportLoaded() {
               System.out.println("Loaded");
          }
     }
}

生产:

false
Loading TestLoaded$ClassToTest
Loaded
true

请注意,示例类不在包中.完整的二进制名称是必需的.

二进制名称的一个例子是 "java.security.KeyStore$Builder$FileBuilder$1"


谢谢你补充说明.虽然您确实需要包,但它是所需的"二进制名称".示例中显示的类的规范名称是"TestLoaded.ClassToTest",它与二进制名称不同......我将编辑澄清/链接的答案.
这将停止未经许可非法访问的Java平台模块系统的使用。

2> Aleksi Yrtti..:

您可以在ClassLoader中使用findLoadedClass(String)方法.如果未加载类,则返回null.


`方法m = ClassLoader.class.getDeclaredMethod("findLoadedClass",new array [] {String.class}); m.setAccessible(真); m.invoke(t,"Stirng");`

3> McDowell..:

一种方法是使用instrumentation API编写Java代理.这将允许您记录JVM的类加载.

public class ClassLoadedAgent implements ClassFileTransformer {

    private static ClassLoadedAgent AGENT = null;

    /** Agent "main" equivalent */
    public static void premain(String agentArguments,
            Instrumentation instrumentation) {
        AGENT = new ClassLoadedAgent();
        for (Class clazz : instrumentation.getAllLoadedClasses()) {
            AGENT.add(clazz);
        }
        instrumentation.addTransformer(AGENT);
    }

    private final Map> classMap = new WeakHashMap>();

    private void add(Class clazz) {
        add(clazz.getClassLoader(), clazz.getName());
    }

    private void add(ClassLoader loader, String className) {
        synchronized (classMap) {
            System.out.println("loaded: " + className);
            Set set = classMap.get(loader);
            if (set == null) {
                set = new HashSet();
                classMap.put(loader, set);
            }
            set.add(className);
        }
    }

    private boolean isLoaded(String className, ClassLoader loader) {
        synchronized (classMap) {
            Set set = classMap.get(loader);
            if (set == null) {
                return false;
            }
            return set.contains(className);
        }
    }

    @Override
    public byte[] transform(ClassLoader loader, String className,
            Class classBeingRedefined, ProtectionDomain protectionDomain,
            byte[] classfileBuffer) throws IllegalClassFormatException {
        add(loader, className);
        return classfileBuffer;
    }

    public static boolean isClassLoaded(String className, ClassLoader loader) {
        if (AGENT == null) {
            throw new IllegalStateException("Agent not initialized");
        }
        if (loader == null || className == null) {
            throw new IllegalArgumentException();
        }
        while (loader != null) {
            if (AGENT.isLoaded(className, loader)) {
                return true;
            }
            loader = loader.getParent();
        }
        return false;
    }

}

META-INF/MANIFEST.MF:

Manifest-Version: 1.0 
Premain-Class: myinstrument.ClassLoadedAgent

缺点是您必须在启动JVM时加载代理:

java -javaagent:myagent.jar ....etcetera



4> Stephen Denn..:

如果您控制着对它们是否要加载感兴趣的类的源(我对此表示怀疑,但您没有在问题中陈述),那么可以在静态初始化器中注册您的加载。

public class TestLoaded {
    public static boolean loaded = false;
    public static void main(String[] args) throws ClassNotFoundException {
        System.out.println(loaded);
        ClassToTest.reportLoaded();
        System.out.println(loaded);
    }
    static class ClassToTest {
        static {
            System.out.println("Loading");
            TestLoaded.loaded = true;
        }
        static void reportLoaded() {
            System.out.println("Loaded");
        }
    }
}

输出:

false
Loading
Loaded
true


您会混淆类的加载和初始化。当您执行“对象o = ClassToTest.class;”之类的操作时,该类将被加载但未初始化。我猜,OP不在乎;只是想弄清楚它。
推荐阅读
拾味湖
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有