`

Class文件详解

阅读更多
我们都知道,Java编译器负责将.java文件编译成.class文件,class文件存储的是java字节码,与.java文件无关(只要你愿意写一个编译器,也可以将别的语言写的源代码编译成.class文件),本文准备详细解剖class文件的内部结构,并且把class文件结构读取并显示出来。
  
  Class文件的格式由JVM规范规定,一共有以下部分:
  
  1. magic number,必须是0xCAFEBABE,用于快速识别是否是一个class文件。
  
  2. version,包括major和minor,如果版本号超过了JVM的识别范围,JVM将拒绝执行。
  
  3. constant pool,常量池,存放所有用到的常量。
  
  4. access flag,定义类的访问权限。
  
  5. this class和super class,指示如何找到this class和super class。
  
  6. interfaces,存放所有interfaces。
  
  7. fields,存放所有fields。
  
  8. methods,存放所有methods。
  
  9. attributes,存放所有attributes。
  
  先写一个Test.java:
  
  package example.test;
  
  public final class TestClass {
  public int id = 1234567;
  public void test() {}
  }
  
  然后编译,放在C:\example\test\Test.class。
  
  我们用Java来读取和分析class,ClassAnalyzer的功能便是读取Test.class,分析结构,然后显示出来:
  
  package classfile.format;
  
  import java.io.*;
  
  public class ClassAnalyzer {
  
  public static void main(String[] args) {
  DataInputStream input = null;
  try {
  input = new DataInputStream(new BufferedInputStream(new FileInputStream(
  "C:\\example\\test\\TestClass.class"
  )));
  analyze(input);
  }
  catch(Exception e) {
  System.out.println("Analyze failed!");
  }
  finally {
  try { input.close(); } catch(Exception e) {}
  }
  }
  
  public static void analyze(DataInputStream input) throws IOException {
  // read magic number:
  int magic = input.readInt();
  if(magic==0xCAFEBABE)
  System.out.println("magic number = 0xCAFEBABE");
  else
  throw new RuntimeException("Invalid magic number!");
  // read minor version and major version:
  short minor_ver = input.readShort();
  short major_ver = input.readShort();
  System.out.println("Version = " + major_ver + "." + minor_ver);
  // read constant pool:
  short const_pool_count = input.readShort();
  System.out.println("constant pool size = " + const_pool_count);
  // read each constant:
  for(int i=1; i  analyzeConstant(input, i);
  }
  }
  
  public static void analyzeConstant(DataInputStream input, int index) throws IOException {
  byte flag = input.readByte();
  // for read:
  byte n8;
  short n16;
  int n32;
  long n64;
  float f;
  double d;
  byte[] buffer;
  System.out.println("\nconst index = " + index + ", flag = " + (int)flag);
  switch(flag) {
  case 1: // utf-8 string
  System.out.println(" const type = Utf8");
  n16 = input.readShort();
  System.out.println("   length = " + n16);
  buffer = new byte[n16];
  input.readFully(buffer);
  System.out.println("   value = " + new String(buffer));
  break;
  case 3: // integer
  System.out.println(" const type = Integer");
  n32 = input.readInt();
  System.out.println("   value = " + n32);
  break;
  case 4: // float
  System.out.println(" const type = Float");
  f = input.readFloat();
  System.out.println("   value = " + f);
  break;
  case 5: // long
  System.out.println(" const type = Long");
  n64 = input.readLong();
  System.out.println("   value = " + n64);
  break;
  case 6: // double
  System.out.println(" const type = Double");
  d = input.readDouble();
  System.out.println("   value = " + d);
  break;
  case 7: // class or interface reference
  System.out.println(" const type = Class");
  n16 = input.readShort();
  System.out.println("   index = " + n16 + " (where to find the class name)");
  break;
  case 8: // string
  System.out.println(" const type = String");
  n16 = input.readShort();
  System.out.println("   index = " + n16);
  break;
  case 9: // field reference
  System.out.println(" const type = Fieldref");
  n16 = input.readShort();
  System.out.println("class index = " + n16 + " (where to find the class)");
  n16 = input.readShort();
  System.out.println("nameAndType = " + n16 + " (where to find the NameAndType)");
  break;
  case 10: // method reference
  System.out.println(" const type = Methodref");
  n16 = input.readShort();
  System.out.println("class index = " + n16 + " (where to find the class)");
  n16 = input.readShort();
  System.out.println("nameAndType = " + n16 + " (where to find the NameAndType)");
  break;
  case 11: // interface method reference
  System.out.println(" const type = InterfaceMethodref");
  n16 = input.readShort();
  System.out.println("class index = " + n16 + " (where to find the interface)");
  n16 = input.readShort();
  System.out.println("nameAndType = " + n16 + " (where to find the NameAndType)");
  break;
  case 12: // name and type reference
  System.out.println(" const type = NameAndType");
  n16 = input.readShort();
  System.out.println(" name index = " + n16 + " (where to find the name)");
  n16 = input.readShort();
  System.out.println(" descripter = " + n16 + " (where to find the descriptor)");
  break;
  default:
  throw new RuntimeException("Invalid constant pool flag: " + flag);
  }
  }
  }
  
  输出结果为:
  
  magic number = 0xCAFEBABE
  Version = 48.0
  constant pool size = 22
  
  const index = 1, flag = 1
  const type = Utf8
  length = 22
  value = example/test/TestClass
  
  const index = 2, flag = 7
  const type = Class
  index = 1 (where to find the class name)
  
  const index = 3, flag = 1
  const type = Utf8
  length = 16
  value = java/lang/Object
  
  const index = 4, flag = 7
  const type = Class
  index = 3 (where to find the class name)
  
  const index = 5, flag = 1
  const type = Utf8
  length = 2
  value = id
  
  const index = 6, flag = 1
  const type = Utf8
  length = 1
  value = I
  
  const index = 7, flag = 1
  const type = Utf8
  length = 6
  value = <init></init>
  
  const index = 8, flag = 1
  const type = Utf8
  length = 3
  value = ()V
  
  const index = 9, flag = 1
  const type = Utf8
  length = 4
  value = Code
  
  const index = 10, flag = 12
  const type = NameAndType
  name index = 7 (where to find the name)
  descripter = 8 (where to find the descriptor)
  
  const index = 11, flag = 10
  const type = Methodref
  class index = 4 (where to find the class)
  nameAndType = 10 (where to find the NameAndType)
  
  const index = 12, flag = 3
  const type = Integer
  value = 1234567
  
  const index = 13, flag = 12
  const type = NameAndType
  name index = 5 (where to find the name)
  descripter = 6 (where to find the descriptor)
  
  const index = 14, flag = 9
  const type = Fieldref
  class index = 2 (where to find the class)
  nameAndType = 13 (where to find the NameAndType)
  
  const index = 15, flag = 1
  const type = Utf8
  length = 15
  value = LineNumberTable
  
  const index = 16, flag = 1
  const type = Utf8
  length = 18
  value = LocalVariableTable
  
  const index = 17, flag = 1
  const type = Utf8
  length = 4
  value = this
  
  const index = 18, flag = 1
  const type = Utf8
  length = 24
  value = Lexample/test/TestClass;
  
  const index = 19, flag = 1
  const type = Utf8
  length = 4
  value = test
  
  const index = 20, flag = 1
  const type = Utf8
  length = 10
  value = SourceFile
  
  const index = 21, flag = 1
  const type = Utf8
  length = 14
  value = TestClass.java
  
  我们暂时只读取到constant pool,后面的信息下次再继续 :)
  继续分析Class文件的结构。
  
  上次读取了constant pool,紧接着是这个类或接口的Access flags,JVM定义的关于class或interface的Access flags有:
  
  private static short ACC_PUBLIC  = 0x0001;
  private static short ACC_FINAL   = 0x0010;
  private static short ACC_SUPER   = 0x0020;
  private static short ACC_INTERFACE = 0x0200;
  private static short ACC_ABSTRACT = 0x0400;
  
  // read access flags:
  short access_flags = input.readShort();
  System.out.print("Access flags:");
  if((access_flags & ACC_PUBLIC) == ACC_PUBLIC)
  System.out.print(" public");
  if((access_flags & ACC_FINAL) == ACC_FINAL)
  System.out.print(" final");
  if((access_flags & ACC_SUPER) == ACC_SUPER)
  System.out.print(" super");
  if((access_flags & ACC_INTERFACE) == ACC_INTERFACE)
  System.out.print(" interface");
  if((access_flags & ACC_ABSTRACT) == ACC_ABSTRACT)
  System.out.print(" abstract");
  System.out.println();
  
  然后是this class和super class:
  
  // read this class and super class:
  short this_class_index = input.readShort();
  short super_class_index = input.readShort();
  System.out.println("This class = " + this_class_index);
  System.out.println("Super class = " + super_class_index);
  
  根据this class的index可以从constant pool中得到这个class的信息,super class也一样。每个class都有super class,只有Object的super class index=0。
  
  接下来是这个class继承了多少个interface和每个interface在constant pool中的index:
  
  // read interfaces count:
  short interfaces_count = input.readShort();
  System.out.println("Interfaces count = " + interfaces_count);
  // read each interface:
  for(int i=1; i<=interfaces_count; i++) {
  short interface_index = input.readShort();
  System.out.println("No. " + i + " interface index = " + interface_index);
  }
  
  结果如下:
  
  Access flags: public final super
  This class = 2
  Super class = 4
  Interfaces count = 0
分享到:
评论

相关推荐

    Eclipse中反编译Class文件详解

    【Eclipse中反编译Class文件详解】 在Java开发中,有时我们需要查看或理解某些库的内部实现,尤其是当我们遇到不公开源代码的类文件时。Eclipse作为主流的Java集成开发环境,提供了多种方式来查看编译后的Class文件...

    jvm 加载class文件

    ### JVM加载Class文件详解 #### 一、Java与JVM中的Class文件加载机制概述 Java作为一种动态性极强的解释型编程语言,在程序运行时,Java虚拟机(JVM)负责将编译生成的`.class`文件加载到内存中进行执行。在Java...

    在Eclipse中反编译Class文件完全详解

    在Java开发过程中,有时我们需要查看或理解某个JAR包中未提供源代码的Class文件的内部实现。本文详细介绍了如何在Eclipse环境中反编译Class文件,以便查看对应的源码。 首先,反编译Class文件是为了能理解那些无法...

    第2节: class文件及类加载详解-01

    第2节: class文件及类加载详解-01第2节: class文件及类加载详解-01第2节: class文件及类加载详解-01第2节: class文件及类加载详解-01第2节: class文件及类加载详解-01第2节: class文件及类加载详解-01第2节: ...

    Eclipse中反编译Class文件完全详解

    在IT行业中,开发人员经常会遇到需要查看Java字节码(Class文件)源代码的情况,例如在分析二进制库或解决兼容性问题时。本文将详细介绍如何在Eclipse集成开发环境中利用反编译工具实现这一目标,特别是针对Eclipse...

    class文件结构浅析

    ### Class文件结构浅析 #### 一、引言 在深入了解Class文件的结构之前,我们需要明确Class文件在Java生态系统中的重要地位。Java程序被编译器编译后生成的`.class`文件,实际上是字节码文件,它们是Java虚拟机...

    Java Class文件格式详解1

    Java Class文件是Java虚拟机(JVM)运行的基础,它是编译后Java源代码的二进制表示形式。在深入讲解Class文件格式之前,我们需要理解Java字节码的概念,它是一种平台无关的中间语言,使得Java程序可以在任何支持JVM...

    运行java的class文件方法详解.docx

    Java Class 文件运行方法详解 在 Java 开发中,运行 Class 文件是非常重要的一步骤。下面将详细介绍运行 Java 的 Class 文件方法的相关知识点。 一、运行 Class 文件 要运行 Class 文件,需要使用 Java 命令,...

    么把.class文件反编译成.java 经修改后再编译成.class

    下面将详细介绍.class 文件反编译到.java 文件的过程,包括反编译工具的使用和反编译后的修改、再编译等步骤。 一、反编译工具的选择 在反编译.class 文件时,需要使用专门的反编译工具。目前有多种反编译工具可供...

    ClassFinal是一款java class文件安全加密工具

    总的来说,ClassFinal作为一款Java class文件安全加密工具,为开发者提供了一种简单、高效的代码保护方案,尤其适合于那些重视代码安全但又不想改动大量代码的企业级项目。其兼容性和易用性使其在Java开发领域具有...

    class文件结构组成.doc

    ### Class文件结构组成详解 #### 一、Class文件概述 Class文件是Java程序编译后的产物,由编译器生成并被Java虚拟机(JVM)加载执行。它以8位字节流的形式组织数据,共包含15个有意义的组成部分。每个部分紧密相连,...

    hibernate配置文件详解

    Hibernate 配置文件详解 Hibernate 是一个流行的 ORM(Object-Relational Mapping)框架,用于简化 Java 应用程序中的数据库交互。 Hibernate 的配置文件是其核心组件之一,用于定义 Hibernate 的运行期参数。下面...

    spring所有配置文件详解

    ### Spring配置文件详解 #### 一、引言 在Java Web开发领域,Spring框架因其强大的功能和灵活性而受到广泛欢迎。对于初学者来说,理解Spring的配置方式是至关重要的第一步。本文将详细介绍Spring中常见的配置文件...

    Class文件格式

    ### Class文件格式详解 #### 一、概述 在Java编程语言中,编译后的源代码会生成`.class`文件,这种文件格式对于Java程序的执行至关重要。本文将深入探讨Class文件格式的基本结构、组成部分以及其如何支持Java...

    jadeclipse【Eclipse下查看class文件源码】附配制详解

    在Java开发过程中,有时我们需要查看已编译的`.class`文件的源代码,这对于调试、学习或者理解已有的代码库非常有帮助。Jadeclipse就是这样一款插件,它允许我们在Eclipse集成开发环境中直接查看`.class`文件的源码...

    spring mvc的配置文件详解

    ### Spring MVC 的配置文件详解 #### 一、配置分发器 (DispatcherServlet) Spring MVC 的核心组件之一就是 DispatcherServlet,它作为整个框架的入口,负责处理所有进入 Spring Web 应用程序的请求。为了使 ...

    .class 文件反编译工具

    在Java编程领域,.class文件是Java源代码经过编译后的二进制形式,它包含了程序的字节码,是Java虚拟机(JVM)执行的基石。然而,由于.class文件是二进制格式,普通用户无法直接阅读其内容。这时,我们就需要借助于...

    Java字节码(.class文件)格式详解((转载)

    Java字节码是Java程序编译后的产物,它以`.class`文件的形式存在,是Java虚拟机(JVM)能够理解和执行的二进制代码。本文将深入解析Java字节码的格式,帮助你理解其背后的运行机制。 1. **Java字节码结构** Java...

    MANIFEST.MF 文件内容详解(转)

    标题中的"MANIFEST.MF 文件内容详解(转)"是指一篇关于理解Java应用程序的MANIFEST.MF文件的文章。MANIFEST.MF文件是Java档案(JAR)文件格式的一部分,它包含了有关JAR文件元数据的重要信息。这篇博文可能是从其他...

Global site tag (gtag.js) - Google Analytics