Java字节码深入解析

本文涉及的产品
云解析 DNS,旗舰版 1个月
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介:

一:Java字节代码的组织形式

  类文件{

  OxCAFEBABE,小版本号,大版本号,常量池大小,常量池数组,访问控制标记,当前类信息,父类信息,实现的接口个数,实现的接口信息数组,域个数,域信息数组,方法个数,方法信息数组,属性个数,属性信息数组

  }

  二:查看方法 --- javap命令

  例子:有一个Java类Demo.java

public class Demo {      private String str1;      private String str2;      private int num1;      private int num2;      public static final String STATIC_DATA = "hello world"           private void sayHello1(){          System.out.println("this is method1...");      }      private void sayHello2(){          System.out.println("this is method2...");      }      public void sayHello3(){          System.out.println("this is method3...");      }  }

  通过jdk自带的反编译工具命令 javap 可以查看class文件的字节码信息

D:\>javap -verbose Demo >> Demo.txt

  Demo.txt:

Compiled from "Demo.java"  public class Demo extends java.lang.Object    SourceFile: "Demo.java"    minor version: 0    major version: 49         Constant pool:  const #1 = class      #2;   //  Demo  const #2 = Asciz     Demo;  const #3 = class      #4;   //  java/lang/Object  const #4 = Asciz     java/lang/Object;  const #5 = Asciz     str1;  const #6 = Asciz     Ljava/lang/String;;  const #7 = Asciz     str2;  const #8 = Asciz     num1;  const #9 = Asciz     I;  const #10 = Asciz   num2;  const #11 = Asciz   STATIC_DATA;  const #12 = Asciz   ConstantValue;  const #13 = String  #14//  hello world  const #14 = Asciz   hello world;  const #15 = Asciz   <init>;  const #16 = Asciz   ()V;  const #17 = Asciz   Code;  const #18 = Method       #3.#19;   //  java/lang/Object."<init>":()V  const #19 = NameAndType    #15:#16;//  "<init>":()V  const #20 = Asciz   LineNumberTable;  const #21 = Asciz   LocalVariableTable;  const #22 = Asciz   this const #23 = Asciz   LDemo;;  const #24 = Asciz   sayHello1;  const #25 = Field   #26.#28;  //  java/lang/System.out:Ljava/io/PrintStream;  const #26 = class    #27//  java/lang/System  const #27 = Asciz   java/lang/System;  const #28 = NameAndType    #29:#30;//  out:Ljava/io/PrintStream;  const #29 = Asciz   out;  const #30 = Asciz   Ljava/io/PrintStream;;  const #31 = String  #32//  this is method1...  const #32 = Asciz   this is method1...;  const #33 = Method       #34.#36;  //  java/io/PrintStream.println:(Ljava/lang/String;)V  const #34 = class    #35//  java/io/PrintStream  const #35 = Asciz   java/io/PrintStream;  const #36 = NameAndType    #37:#38;//  println:(Ljava/lang/String;)V  const #37 = Asciz   println;  const #38 = Asciz   (Ljava/lang/String;)V;  const #39 = Asciz   sayHello2;  const #40 = String  #41//  this is method2...  const #41 = Asciz   this is method2...;  const #42 = Asciz   sayHello3;  const #43 = String  #44//  this is method3...  const #44 = Asciz   this is method3...;  const #45 = Asciz   SourceFile;  const #46 = Asciz   Demo.java;     public static final java.lang.String STATIC_DATA;    Constant value: String hello world  public Demo();    Code:     Stack=1, Locals=1, Args_size=1     0:      aload_0     1:      invokespecial  #18//Method java/lang/Object."<init>":()V     4:      return    LineNumberTable:     line 20    LocalVariableTable:     Start  Length  Slot  Name   Signature     0      5      0    this       LDemo;     public void sayHello3();    Code:     Stack=2, Locals=1, Args_size=1     0:      getstatic   #25//Field java/lang/System.out:Ljava/io/PrintStream;     3:      ldc   #43//String this is method3...     5:      invokevirtual  #33//Method java/io/PrintStream.println:(Ljava/lang/String;)V     8:      return    LineNumberTable:     line 170     line 188    LocalVariableTable:     Start  Length  Slot  Name   Signature     0      9      0    this       LDemo;  }

解析:

  1、版本号 major version: 49 //java版本 jdk1.6显示的是50, jdk1.5显示的是49,jdk1.4显示的是58 , 高版本能执行低版本的class文件

  2、常量池Constant pool

  Method:方法

  Field:字段

  String:字符串

  Asciz:签名如<init>由jvm调用,其他是不能够去调用它的

  NameAndType:变量名的类型

  Class:类

  通过字节码,我们可以看到Demo类 继承于java.lang.Object,如果类中没有显式声明构造函数的话,编译器会插入一个缺省无参的构造函数(构造函数在JVM级别是显示成<init>的普通函数)。

  三:检测代码的效率问题

  学习Java的过程中,都会了解到字符串合并时要用到StringBuffer 来代替String,那下面就来通过Java字节码来验证两种方式的效率性。

  例子:一个Java类 TestString.java

<strong>public class TestString {      public String testString(String str1, String str2){         return str1 + str2;      }      public String testStringBuffer(StringBuffer sb, String str){         return sb.append(str).toString();      }   </strong>

  javap –c TestString 后字节码信息:

Compiled from "TestString.java"  public class TestString extends java.lang.Object{  public TestString();    Code:     0:      aload_0     1:      invokespecial  #8//Method java/lang/Object."<init>":()V     4:      return     public java.lang.String testString(java.lang.String, java.lang.String);    Code:     0:      new #16//class java/lang/StringBuilder     3:      dup     4:      aload_1     5:      invokestatic    #18//Method java/lang/String.valueOf:(Ljava/lang/Object;)Ljava/lang/String;     8:      invokespecial  #24//Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V     11:     aload_2     12:    invokevirtual  #27//Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;     15:    invokevirtual  #31//Method java/lang/StringBuilder.toString:()Ljava/lang/String;     18:    areturn     public java.lang.String testStringBuffer(java.lang.StringBuffer, java.lang.String);    Code:     0:      aload_1     1:      aload_2     2:      invokevirtual  #40//Method java/lang/StringBuffer.append:(Ljava/lang/String;)Ljava/lang/StringBuffer;     5:      invokevirtual  #45//Method java/lang/StringBuffer.toString:()Ljava/lang/String;     8:      areturn  }

  从上面编译后的字节码信息可以看出来,方法testString 调用了五个方法:new 、invokestatic 、invokespecial 和两个invokevirtual ; 而testStringBuffer 方法只调用了两个invokevirtual 方法。第一个方法比第二个方法多做了好多工作,其效率当然是要低的。而且我们从java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;

  可以看出来其实对于String字符串合并,内部还是转化为StringBuilder的方法调用,这是因为String是长度不可变的,所以不如直接采用StringBuilder(与StringBuffer 长度都是可变的,只不过前者是非线程安全,后者是线程安全)进行字符串合并。


本文出自seven的测试人生公众号最新内容请见作者的GitHub页:http://qaseven.github.io/

目录
相关文章
|
11天前
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
39 2
|
15天前
|
Java
轻松上手Java字节码编辑:IDEA插件VisualClassBytes全方位解析
本插件VisualClassBytes可修改class字节码,包括class信息、字段信息、内部类,常量池和方法等。
66 6
|
2天前
|
数据采集 存储 Web App开发
Java爬虫:深入解析商品详情的利器
在数字化时代,信息处理能力成为企业竞争的关键。本文探讨如何利用Java编写高效、准确的商品详情爬虫,涵盖爬虫技术概述、Java爬虫优势、开发步骤、法律法规遵守及数据处理分析等内容,助力电商领域市场趋势把握与决策支持。
|
6天前
|
存储 安全 Java
Java多线程编程中的并发容器:深入解析与实战应用####
在本文中,我们将探讨Java多线程编程中的一个核心话题——并发容器。不同于传统单一线程环境下的数据结构,并发容器专为多线程场景设计,确保数据访问的线程安全性和高效性。我们将从基础概念出发,逐步深入到`java.util.concurrent`包下的核心并发容器实现,如`ConcurrentHashMap`、`CopyOnWriteArrayList`以及`BlockingQueue`等,通过实例代码演示其使用方法,并分析它们背后的设计原理与适用场景。无论你是Java并发编程的初学者还是希望深化理解的开发者,本文都将为你提供有价值的见解与实践指导。 --- ####
|
7天前
|
Java 测试技术 API
Java 反射机制:深入解析与应用实践
《Java反射机制:深入解析与应用实践》全面解析Java反射API,探讨其内部运作原理、应用场景及最佳实践,帮助开发者掌握利用反射增强程序灵活性与可扩展性的技巧。
|
12天前
|
存储 算法 Java
Java Set深度解析:为何它能成为“无重复”的代名词?
Java的集合框架中,Set接口以其“无重复”特性著称。本文解析了Set的实现原理,包括HashSet和TreeSet的不同数据结构和算法,以及如何通过示例代码实现最佳实践。选择合适的Set实现类和正确实现自定义对象的hashCode()和equals()方法是关键。
23 4
|
15天前
|
Java 编译器 数据库连接
Java中的异常处理机制深度解析####
本文深入探讨了Java编程语言中异常处理机制的核心原理、类型及其最佳实践,旨在帮助开发者更好地理解和应用这一关键特性。通过实例分析,揭示了try-catch-finally结构的重要性,以及如何利用自定义异常提升代码的健壮性和可读性。文章还讨论了异常处理在大型项目中的最佳实践,为提高软件质量提供指导。 ####
|
8天前
|
Java 开发者
Java多线程编程中的常见误区与最佳实践####
本文深入剖析了Java多线程编程中开发者常遇到的几个典型误区,如对`start()`与`run()`方法的混淆使用、忽视线程安全问题、错误处理未同步的共享变量等,并针对这些问题提出了具体的解决方案和最佳实践。通过实例代码对比,直观展示了正确与错误的实现方式,旨在帮助读者构建更加健壮、高效的多线程应用程序。 ####
|
16天前
|
安全 Java 测试技术
Java并行流陷阱:为什么指定线程池可能是个坏主意
本文探讨了Java并行流的使用陷阱,尤其是指定线程池的问题。文章分析了并行流的设计思想,指出了指定线程池的弊端,并提供了使用CompletableFuture等替代方案。同时,介绍了Parallel Collector库在处理阻塞任务时的优势和特点。
|
7天前
|
安全 Java 开发者
Java 多线程并发控制:深入理解与实战应用
《Java多线程并发控制:深入理解与实战应用》一书详细解析了Java多线程编程的核心概念、并发控制技术及其实战技巧,适合Java开发者深入学习和实践参考。
下一篇
无影云桌面