2009-01-27 68 views

回答

36

(感谢阿列克西)此代码:

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 

请注意,示例类不在包中。完整的binary name是必需的。

二进制名称的一个例子就是做这将是使用instrumentation API写一个Java代理"java.security.KeyStore$Builder$FileBuilder$1"

25

您可以使用的ClassLoader findLoadedClass(String)方法。如果类未加载,它将返回null。

+1

不幸的是,findLoadedClasses是受保护的,这意味着您必须继承ClassLoader才能访问它。 – staffan 2009-01-27 08:40:03

+0

是否可以通过反射调用此方法? (禁止安全检查) – 2009-01-27 10:02:04

+1

是的,您可以使用反射 – Elbek 2012-10-02 01:32:45

5

如果你是在控制你感兴趣的类是否加载或不加载(我怀疑,但你没有在你的问题中说明),那么你可以注册你的负载在一个静态初始化器中。

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 
+0

谢谢。这真的是一个很好的方式来使用我自己的类。但我希望找到更通用的东西,以防我不控制课程。 – 2009-01-27 10:36:56

7

的一种方式。这将允许您记录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<ClassLoader, Set<String>> classMap = new WeakHashMap<ClassLoader, Set<String>>(); 

    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<String> set = classMap.get(loader); 
      if (set == null) { 
       set = new HashSet<String>(); 
       classMap.put(loader, set); 
      } 
      set.add(className); 
     } 
    } 

    private boolean isLoaded(String className, ClassLoader loader) { 
     synchronized (classMap) { 
      Set<String> 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 
2

我有一个类似的问题最近,我怀疑我的用户正在加载类(可能是通过-classpath或类似的方式),这些类与我稍后加载到我自己的类加载器中的类冲突。

在尝试了几个这里提到的事情之后,以下似乎对我有用。我不确定它是否适用于任何情况,它可能只适用于从jar文件加载的java类。

InputStream is = getResourceAsStream(name); 

哪里name是路径类文件,如com/blah/blah/blah/foo.class

getResourceAsStream返回null当类没有被加载到我的类加载器或系统类加载器,并且当类已经被加载时返回非null。

相关问题