`
zhb8015
  • 浏览: 378797 次
  • 性别: Icon_minigender_1
  • 来自: 北京
博客专栏
Group-logo
Spring Roo杂谈
浏览量:0
社区版块
存档分类
最新评论

字节码学习(转)

    博客分类:
  • java
阅读更多

一直在学习Java,碰到了很多问题,碰到了很多关于i++和++i的难题,以及最经典的String str = "abc" 共创建了几个对象的疑难杂症。 知道有一日知道了java的反汇编 命令  javap。现将学习记录做一小结,以供自己以后翻看。如果有错误的地方,请指正

1.javap是什么:

 

 where options include:
-c Disassemble the code
-classpath <pathlist> Specify where to find user class files
-extdirs <dirs> Override location of installed extensions
-help Print this usage message
-J<flag> Pass <flag> directly to the runtime system
-l Print line number and local variable tables
-public Show only public classes and members
-protected Show protected/public classes and members
-package Show package/protected/public classes
and members (default)
-private Show all classes and members
-s Print internal type signatures
-bootclasspath <pathlist> Override location of class files loaded
by the bootstrap class loader
-verbose Print stack size, number of locals and args for met
hods
If verifying, print reasons for failure 

以上为百度百科里对它的描述,只是介绍了javap的一些参数和使用方法,而我们要用的就是这一个:-c Disassemble the code。

明确一个问题:javap是什么?网上有人称之为 反汇编器,可以查看java编译器为我们生成的字节码。通过它,我们可以对照源代码和字节码,从而了解很多编译器内部的工作。

2.初步认识javap

从一个最简单的例子开始:

 

 这个例子中,我们只是简单的声明了两个int型变量并赋上初值。下面我们看看javap给我们带来了什么:(当然执行javap命令前,你得首先配置好自己的环境,能用javac编译通过了,即:javac TestJavap.java )

我们只看(方便起见,将注释写到每句后面)

  Code:
   0:   iconst_2
    //把2放到栈顶
   1:   istore_1    //把栈顶的值放到局部变量1中,即i中
   2:   iconst_3    //把3放到栈顶
   3:   istore_2    //把栈顶的值放到局部变量1中,即j中
   4:   return

 

是不是很简单?(当然,估计需要点数据结构的知识) ,那我们就补点java的关于堆栈的知识:

对于 int i = 2;首先它会在栈中创建一个变量为i的引用,然后查找有没有字面值为2的地址,没找到,就开辟一个存放2这个字面值的地址,然后将i指向2的地址。

看了这段话,再比较下上面的注释,是不是完全吻合?

为了验证上面这一说法,我们继续实验:

我们将 i 和 j的值都设为2。按照以上理论,在声明j的时候,会去栈中招有没有字面值为2的地址,由于在栈中已经有2这个字面值,便将j直接指向2的地址。这样,就出现了i与j同时均指向2的情况。

 拿出javap -c进行反编译:结果如下:

  Code:
   0:   iconst_2    //把2放到栈顶
   1:   istore_1    //把栈顶的值放到局部变量1中,即i中
   2:   iconst_2    //把2放到栈顶
   3:   istore_2    //把栈顶的值放到局部变量2中,即j中(i 和 j同时指向2)
   4:   return

 

虽然这里说i和j同时指向2,但这里不等于说i和j指向同一块地址(java是不允许程序员直接修改堆栈中的数据的,所以就不要想着,我是不是可以修改栈中的2,那样岂不是i和j的值都会变化。另:在编译器内部,遇到j=2;时,它就会重新搜索栈中是否有2的字面值,如果没有,重新开辟地址存放2的值;如果已经有了,则直接将j指向这个地址。因此,就算j另被赋值为其他值,如j=4,j值的改变不会影响到i的值。)

再来一个例子:

还是javap -c

  Code:
   0:   iconst_2    //把2放到栈顶
   1:   istore_1    //把栈顶的值放到局部变量1中,即i中
   2:   iload_1     //把i的值放到栈顶,也就是说此时栈顶的值是2
   3:   istore_2    //把栈顶的值放到局部变量2中,即j中
   4:   return

看到这里是不是有点明确了?

 

 

既然我们对javap有了一定的了解,那我们就开始用它来解决一些实际的问题:

1.i++和++i的问题

反编译结果为

 Code:
  0:   iconst_1
  1:   istore_1
  2:   iinc    1, 1 //这个个指令,把局部变量1,也就是i,增加1,这个指令不会导致栈的变化,i此时变成2了
  5:   iconst_1
  6:   istore_2
  7:   iinc    2, 1//这个个指令,把局部变量2,也就是j,增加1,这个指令不会导致栈的变化,j此时变成2了
  10:  return

 

可以看出,++在前在后,在这段代码中,没有任何不同。

我们再看另一段代码:

反编译结果:

  Code:
   0:   iconst_1
   1:   istore_1
   2:   iload_1
   3:   iinc    1, 1  //局部变量1(即i)加1变为2,注意这时栈中仍然是1,没有改变
   6:   istore_1    //把栈顶的值放到局部变量1中,即i这时候由2变成了1
   7:   iconst_1
   8:   istore_2
   9:   iinc    2, 1 //局部变量2(即j)加1变为2,注意这时栈中仍然是1,没有改变
   12:  iload_2    //把局部变量2(即j)的值放到栈顶,此时栈顶的值变为2
   13:  istore_2   //把栈顶的值放到局部变量2中,即j这时候真正由1变成了2
   14:  return

是否看明白了? 如果这个看明白了,那么下面的一个问题应该就是迎刃而解了:

m = m ++;这句话,java虚拟机执行时是这样的: m的值加了1,但这是栈中的值还是0, 马上栈中的值覆盖了m,即m变成0,因此不管循环多少次,m都等于0。

如果改为m = ++m; 程序运行结果就是100了。。。

 

分享到:
评论

相关推荐

    C2j-Compiler:将C语言转换为Java字节码或可以直接解释执行的编译器(将C语言编译成Java字节码的编译器,也可以选择直接解释执行)

    将C语言转换为Java字节码或可以直接解释执行的编译器 作为一个学习项目 可以解释为执行大多数C或编译为Java字节码 玩具级,未添加许多功能,也没有优化 支持的 支持所有基本陈述 解释器:支持指针,数组,结构和...

    java学习全PPT

    用Java语言编辑的源程序的执行方法是采用先经过编译器编译、再利用解释器... Java源程序经过编译器编译,会被转换成一种我们将它称之为“字节码(byte_codes)”的目标程序。“字节码”的最大特点便是可以跨平台运行。

    c#中的类型转换详解

    其内容涉及 C# 的装箱/拆箱/别名、数值类型间相互转换、字符的 ASCII 码和 Unicode 码、数值字符串和数值之 间的转换、字符串和字符数组/字节数组之间的转换、各种数值类型和字节数组之间的转换、十六进制数输出以及...

    js实现unicode码字符串与utf8字节数据互转详解

    主要介绍了js实现unicode码字符串与utf8字节数据互转,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

    Java学习笔记(一)

    程序代码经过编译之后转换成一种称为Java字节码的中间语言,Java虚拟机(JVM)将对字节码进行解释和运行。编译只进行一次,而解释在每次运行程序都会进行。编译后的字节码采用一种针对JVM优化过的机器码形式保存,...

    java技术学习文档.docx

    Java基础知识 Java是一种面向对象的编程语言,它支持封装、继承和多态等面向对象的基本概念。Java具有静态类型检查机制,需要在编译时指定变量的...JVM是Java程序的运行环境,它可以将Java字节码转换为机器码并执行。

    java基础学习笔记 java整合技术 java工具类.rar

    DOS操作 切换盘符: d: 进入文件夹:cd 文件夹名 命令提示: tab 一次性进入多个文件夹: cd\文件夹\文件夹 ...javac xx.java文件名 进行编译,将源程序转成字节码 java xx文件名(不要后缀) 运行编译后的java程序

    Python 面试题汇总及答案详解完整版

    14:字节码和机器码的区别 15:三元运算写法和应用场景 16:Python3 和 Python2 的区别 17:用一行代码实现数值交换 18:Python3 和 Python2 中 int 和 long 区别 19:xrange 和 range 的区别 20:文件操作时:...

    Java zxing生成条形码和二维吗代码实例

    主要介绍了java zxing生成条形码和二维吗代码实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下

    cvm_compiler_v2:CVM编译器的第二次迭代

    这就是为什么在使用CVM进行编程之前学习CVM字节码的基础非常重要的原因。 CVM字节码只有9条指令,而OP指令具有9种子操作。 在CVM中,寄存器的大小在0到255之间。它们的作用类似于无符号字节的Vector,最大容量为255...

    GradleforAndroid系列:为什么Gradle这么火

    主要的资源文件(layout,values等)都被aapt编译,并且在一个R文件中引用2.Java代码被Java编译器编译成JVM字节码(.class文件)3.JVM字节码再被dex工具转换成dalvik字节码(.dex文件)4.然后这些.dex文件、编译过的资源...

    字符串 Hex 转换 输出

    2.可以格式化显示输出这个功能类似printf,但是是一个指定字节大小为单位的'值'来进行输出的。 3.可以通过Hex输入查看原字符串 4.字符统计功能 5.输入的字符串Asc&Unicode或者Hex在内存中的数据呈现。 6.支持托盘,...

    Python2.x中str与unicode相关问题的解决方法

    str与字节码 首先,我们完全不谈unicode。   s = "人生苦短" s是个字符串,它本身存储的就是字节码。那么这个字节码是什么格式的? 如果这段代码是在解释器上输入的,那么这个s的格式就是解释器的编码格式,对于...

    matlab代码转java-gradle-study:学习gradle!

    groovy不仅可以源文件编译成字节码文件通过交给JVM执行还可以像js一样解释执行~ 结合了Python、Ruby、Smalltalk的许多强大特性 groovy可以与java完美结合,并且可以使用java所有的库! groovy特性 语法上支持动态...

    Java之IO流学习总结

    Java IO流学习总结 Java流操作有关的类或接口: Java流类图结构: 流的概念和作用 流是一组有顺序的,有起点和终点的字节集合,是对数据传输的总称或抽象。即数据在两设备间的传输称为流,流的本质是数据...

    计算机应用基础-数制转换.doc

    二进制数表示简单,学习容易 D.最早设计计算机的人随意决定的 2、计算机内部对数据进行处理时,采用( ) A.二进制 B.八进制 C.十进制 D.十六进制 3、在计算机中,只有二进制的0和1两个不同值表示的信息量叫( ) A....

    springlearning:Spring学习

    前言 Spring 框架学习,完全弃用 XML 配置。...@Retention(RetentionPolicy.SOURCE) 注解仅存在于源码中,不包含在 class 字节码中 @Retention(RetentionPolicy.CLASS) 默认的保留策略,注解在 class 字节

    HotSpot实战

    Klass对象表示系统、链接、运行时数据区、方法区、常量池和常量池Cache、Perf Data、Crash分析方法、转储分析方法、垃圾收集器的设计演进、CMS和G1收集器、栈、JVM对硬件寄存器的利用、栈顶缓存技术、解释器、字节...

Global site tag (gtag.js) - Google Analytics