确定.class文件中引用的类

(以编程方式)解析已编译的Java(.class)文件并生成它引用的任何和所有其他Java类的列表的最佳方法是什么?

如果您了解规格,这很容易自己做。

下面是一个快速而又脏的演示程序如何做到这一点:

package test; import java.io.DataInputStream; import java.io.IOException; import java.io.InputStream; import java.util.*; public class Main { private static Map strings = new HashMap(); private static Set classes = new HashSet(); private static int indexCorrection = 0; // for correcting indexes to constant pools with long and double entries public static void main(String[] args) throws Exception { printReferencedClassesFromClass(String.class); } private static void printReferencedClassesFromClass(Class c) throws IOException { saveReferencedClassesFromStream(c.getResourceAsStream(c.getSimpleName() + ".class")); printReferencedClasses(); } private static void printReferencedClasses() { for (Integer index : classes) System.out.println(strings.get(index)); } private static void saveReferencedClassesFromStream(InputStream stream) throws IOException { DataInputStream dataStream = new DataInputStream(stream); skipHeader(dataStream); saveReferencedClassesFromConstantPool(dataStream); } private static void skipHeader(DataInputStream dataInputStream) throws IOException { readU4(dataInputStream); // magic byte readU2(dataInputStream); // minor version readU2(dataInputStream); // major version } private static void saveReferencedClassesFromConstantPool(DataInputStream stream) throws IOException { int poolSize = readU2(stream); for (int n = 1; n < poolSize - indexCorrection; n++) savePoolEntryIfIsClassReference(n, stream); } private static void savePoolEntryIfIsClassReference(int index, DataInputStream stream) throws IOException { int tag = readU1(stream); switch (tag) { case 1: // Utf8 saveStringFromUtf8Entry(index, stream); break; case 7: // Class saveClassEntry(stream); break; case 8: // String case 16: // MethodType readU2(stream); break; case 3: // Integer case 4: // Float readU4(stream); break; case 5: // Long case 6: // Double readU4(stream); readU4(stream); indexCorrection++; break; case 9: // Fieldref case 10: // Methodref case 11: // InterfaceMethodref case 12: // NameAndType case 18: // InvokeDynmaic readU2(stream); readU2(stream); break; case 15: // MethodHandle readU1(stream); readU2(stream); break; } } private static void saveClassEntry(DataInputStream stream) throws IOException { classes.add(readU2(stream)); } private static void saveStringFromUtf8Entry(int index, DataInputStream stream) throws IOException { strings.put(index + indexCorrection, readString(stream)); } private static String readString(DataInputStream stream) throws IOException { return stream.readUTF(); } private static int readU1(DataInputStream stream) throws IOException { return stream.readUnsignedByte(); } private static int readU2(DataInputStream stream) throws IOException { return stream.readUnsignedShort(); } private static int readU4(DataInputStream stream) throws IOException { return stream.readInt(); } } 

输出是:

 test/Main java/lang/Object java/io/BufferedInputStream java/util/Iterator java/io/FileInputStream java/lang/System java/lang/Integer java/lang/Exception java/lang/String java/io/File java/util/Map java/util/HashMap java/io/IOException java/util/Set java/io/DataInputStream java/io/PrintStream java/util/HashSet java/lang/Throwable 

你试过JDepend吗? 它分析类文件以确定引用。

这可以与Apache的BCEL一起使用 。

我不知道最好的方法是什么。 我知道有2个API可能有所帮助。

您可以尝试使用jclasslib来检查.class文件
http://www.ej-technologies.com/products/jclasslib/resources.html
或BCEL(字节码工程库),用于分析和操作.class文件。
http://jakarta.apache.org/bcel/

我的理解是在.class中使用的任何类(直到字段,参数,返回类型等)都在constant_pool中定义。 所以你可能想读一下。
http://java.sun.com/docs/books/jvms/second_edition/html/ClassFile.doc.html

我想你可以使用我的Java Dependency Resolver项目,它不仅可以找到引用的java文件,还可以找到项目中特定类的jar文件