Программа просмотра Java-классов (Java Class Viewer) - Получение информации о файле класса

ОГЛАВЛЕНИЕ

2. Получение информации о файле класса

Как только мы успешно получим экземпляр ClassFile, мы можем получить информацию о файле класса посредством методов getXxxxx.

Вот пример вывода информации всех компонент файла класса:

// ArticleCodeDemo.src.zip - org.freeinternals.demo.jCFL_CodeDemo.printClassFile()
 // Версии Minor и Major
MinorVersion minorVersion = classfile.getMinorVersion();
System.out.println("Class File Minor Version: " + minorVersion.getValue());
 MajorVersion majorVersion = classfile.getMajorVersion();
System.out.println("Class File Major Version: " + majorVersion.getValue());
 // Набор констант
CPCount cpCount = classfile.getCPCount();
System.out.println("Constant Pool size: " + cpCount.getValue());
 AbstractCPInfo[] cpArray = classfile.getConstantPool();
for (int i = 1; i < cpCount.getValue(); i++) {
    System.out.println(
            String.format("Constant Pool [%d]: %s", i, classfile.getCPDescription(i)));
    short tag = cpArray[i].getTag();
    if ((tag == AbstractCPInfo.CONSTANT_Double) ||
            (tag == AbstractCPInfo.CONSTANT_Long)) {
        i++;
    }
}
 // Флаг доступа, this и супер-класс
AccessFlags accessFlags = classfile.getAccessFlags();
System.out.println("Class Modifier: " + accessFlags.getModifiers());
 ThisClass thisClass = classfile.getThisClass();
System.out.println("This Class Name Index: " + thisClass.getValue());
System.out.println("This Class Name: " +
    classfile.getCPDescription(thisClass.getValue()));
 SuperClass superClass = classfile.getSuperClass();
System.out.println("Super Class Name Index: " + superClass.getValue());
if (superClass.getValue() == 0) {
    System.out.println("Super Class Name: java.lang.Object");
} else {
    System.out.println("Super Class Name: " +
        classfile.getCPDescription(superClass.getValue()));
}
 // Интерфейсы
InterfaceCount interfactCount = classfile.getInterfacesCount();
System.out.println("Interface Count: " + interfactCount.getValue());
 if (interfactCount.getValue() > 0) {
    Interface[] interfaceArray = classfile.getInterfaces();
    for (int i = 0; i < interfaceArray.length; i++) {
        System.out.println(
                String.format("Interface [%d] Name Index: %d", i,
                interfaceArray[i].getValue()));
        System.out.println(
                String.format("Interface [%d] Name: %s", i,
        classfile.getCPDescription(interfaceArray[i].getValue())));
    }
}
 // Поля
FieldCount fieldCount = classfile.getFieldCount();
System.out.println("Field count: " + fieldCount.getValue());
 if (fieldCount.getValue() > 0) {
    FieldInfo[] fieldArray = classfile.getFields();
    for (int i = 0; i < fieldArray.length; i++) {
        System.out.println(String.format("Field [%d]: %s", i,
                fieldArray[i].getDeclaration()));
    }
}
 // Методы
MethodCount methodCount = classfile.getMethodCount();
System.out.println("Method count: " + methodCount.getValue());
 if (methodCount.getValue() > 0) {
    MethodInfo[] methodArray = classfile.getMethods();
    for (int i = 0; i < methodArray.length; i++) {
        System.out.println(String.format("Method [%d]: %s", i,
                methodArray[i].getDeclaration()));
    }
}
 // Атрибуты
AttributeCount attributeCount = classfile.getAttributeCount();
System.out.println("Attribute count: " + attributeCount.getValue());
 AttributeInfo[] attributeArray = classfile.getAttributes();
for (int i = 0; i < attributeArray.length; i++) {
    System.out.println(String.format("Attribute [%d]: %s", i,
                attributeArray[i].getName()));
}

Вот некоторые заметки по поводу указанного выше кода. 

Набор констант: это набор констант (Сonstant pool) начиная с индекса 1 до (constant_pool_count-1); также CONSTANT_Long_info и CONSTANT_Double_info получат две позиции индексов, в то время как другие типы всего лишь получат одну позицию. 

Суперкласс: индекс суперкласса будет равен нулю только тогда, когда текущим классом будет java.lang.Object. В противном случае, он должен быть элементом в наборе констант. 

Интерфейсы и поля: класс может не иметь ни интерфейсов, ни полей, потому нам необходимо проверить переменные InterfaceCount и FieldCount до того, как мы получим массив интерфейса/поля.

Методы: если класс не является внутренним, то он должен иметь хотя бы один метод, который будет являться конструктором экземпляров по умолчанию, созданным javac; но для внутреннего класса методы нет возможности создать. Потому нам необходимо проверить равенство переменной MethodCount нулю. 

Атрибуты: один класс должен иметь хотя бы один атрибут - SourceFile; нам не нужно добавлять логику для него.

Используя код, похожий на тот, что указан выше, вам не составит труда написать визуальный элемент управления интерфейсом для файла класса. А также будет легко написать любое приложение по анализу мета-данных в классе.