JVM-JAVA基本类型
1 package javap.fload; 2 3 import static jdk.nashorn.internal.objects.Global.Infinity; 4 5 public class FloatTest { 6 public static void main(String[] args) { 7 System.out.println(+0.0F == -0.0F); 8 System.out.println(Float.intBitsToFloat(0x8000000) == -0.0F); 9 10 float res = (float) (1.2 / -0.0F); 11 System.out.println(1.2 / -0.0F); // -Infinity负无穷,任意正浮点数除以 -0.0F 得到的值 12 System.out.println(1.3 / 0.0F); // Infinity正无穷,任意正浮点数(不包括 +0.0F)除以 +0.0F 得到的值 13 System.out.println(0.0F / 0.0F); // Not-a-Number 14 15 /** 16 * 正无穷+1,还是等于正无穷 17 */ 18 System.out.println("Infinity+1=" + (Infinity+1)); 19 20 21 /** 22 * NaN 有一个有趣的特性:除了“!=”始终返回 true 之外,所有其他比较结果都会返回 false。 23 * 例来说,“NaN<1.0F”返回 false,而“NaN>=1.0F”同样返回 false。 24 * 对于任意浮点数 f,不管它是 0 还是 NaN,“f!=NaN”始终会返回 true,而“f==NaN”始终会返回 false。 25 */ 26 // 因此,我们在程序里做浮点数比较的时候,需要考虑上述特性。在本专栏的第二部分,我会介绍这个特性给向量化比较带来什么麻烦 27 float f = 1.0F; 28 if (f != Float.NaN) { // 返回true,其余比较返回false 29 System.out.println("f != Float.NaN"); 30 } 31 if (f < Float.NaN) { 32 System.out.println("f < Float.NaN"); 33 } 34 35 } 36 }
结果:
true
false
-Infinity
Infinity
NaN
Infinity+1=Infinity
Infinity
f != Float.NaN
asmtools.jar的使用方法:https://wiki.openjdk.java.net/display/CodeTools/Chapter+2
OpenJDK里的AsmTools简介 http://hengyunabc.github.io/openjdk-asmtools/ (修改.class字节码的工具)
1 MacBook-Pro-2:javap$ java -jar asmtools.jar 2 Usage: 3 to run an assembly tool: 4 $ java -jar asmtools.jar toolName [args...] 5 where toolName one of: jasm, jdis, jcoder, jdec, jcdec 6 to get the version: 7 $ java -jar asmtools.jar -version 8 to get this message 9 $ java -jar asmtools.jar -?|-h|-help 10 11 No arguments provided! See options above.
代码:(静态变量修改)
1 package javap.fload; 2 3 public class FooBoolean { 4 static boolean boolValue; 5 6 public static void main(String[] args) { 7 boolValue = true; // 将这个true替换为2或者3,再看看打印结果 8 if (boolValue) System.out.println("Hello, Java!"); 9 if (boolValue == true) System.out.println("Hello, JVM!"); 10 } 11 }
javap -p -v FooBoolean.class结果:
MacBook-Pro-2:fload$ javap -p -v FooBoolean.class Classfile /Users/wuxiong.wx/work/code/testDemo/src/main/java/javap/fload/FooBoolean.class Last modified 2020-11-16; size 668 bytes MD5 checksum 2693d7088f23a5890569763240da4915 Compiled from "FooBoolean.java" public class javap.fload.FooBoolean minor version: 0 major version: 52 flags: ACC_PUBLIC, ACC_SUPER Constant pool: #1 = Methodref #8.#25 // java/lang/Object."<init>":()V #2 = Fieldref #7.#26 // javap/fload/FooBoolean.boolValue:Z #3 = Fieldref #27.#28 // java/lang/System.out:Ljava/io/PrintStream; #4 = String #29 // Hello, Java! #5 = Methodref #30.#31 // java/io/PrintStream.println:(Ljava/lang/String;)V #6 = String #32 // Hello, JVM! #7 = Class #33 // javap/fload/FooBoolean #8 = Class #34 // java/lang/Object #9 = Utf8 boolValue #10 = Utf8 Z #11 = Utf8 <init> #12 = Utf8 ()V #13 = Utf8 Code #14 = Utf8 LineNumberTable #15 = Utf8 LocalVariableTable #16 = Utf8 this #17 = Utf8 Ljavap/fload/FooBoolean; #18 = Utf8 main #19 = Utf8 ([Ljava/lang/String;)V #20 = Utf8 args #21 = Utf8 [Ljava/lang/String; #22 = Utf8 StackMapTable #23 = Utf8 SourceFile #24 = Utf8 FooBoolean.java #25 = NameAndType #11:#12 // "<init>":()V #26 = NameAndType #9:#10 // boolValue:Z #27 = Class #35 // java/lang/System #28 = NameAndType #36:#37 // out:Ljava/io/PrintStream; #29 = Utf8 Hello, Java! #30 = Class #38 // java/io/PrintStream #31 = NameAndType #39:#40 // println:(Ljava/lang/String;)V #32 = Utf8 Hello, JVM! #33 = Utf8 javap/fload/FooBoolean #34 = Utf8 java/lang/Object #35 = Utf8 java/lang/System #36 = Utf8 out #37 = Utf8 Ljava/io/PrintStream; #38 = Utf8 java/io/PrintStream #39 = Utf8 println #40 = Utf8 (Ljava/lang/String;)V { static boolean boolValue; descriptor: Z flags: ACC_STATIC public javap.fload.FooBoolean(); descriptor: ()V flags: ACC_PUBLIC Code: stack=1, locals=1, args_size=1 0: aload_0 1: invokespecial #1 // Method java/lang/Object."<init>":()V 4: return LineNumberTable: line 3: 0 LocalVariableTable: Start Length Slot Name Signature 0 5 0 this Ljavap/fload/FooBoolean; public static void main(java.lang.String[]); descriptor: ([Ljava/lang/String;)V flags: ACC_PUBLIC, ACC_STATIC Code: stack=2, locals=1, args_size=1 0: iconst_1 1: putstatic #2 // Field boolValue:Z 4: getstatic #2 // Field boolValue:Z 7: ifeq 18 10: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream; 13: ldc #4 // String Hello, Java! 15: invokevirtual #5 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 18: getstatic #2 // Field boolValue:Z 21: iconst_1 22: if_icmpne 33 25: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream; 28: ldc #6 // String Hello, JVM! 30: invokevirtual #5 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 33: return LineNumberTable: line 7: 0 line 8: 4 line 9: 18 line 10: 33 LocalVariableTable: Start Length Slot Name Signature 0 34 0 args [Ljava/lang/String; StackMapTable: number_of_entries = 2 frame_type = 18 /* same */ frame_type = 14 /* same */ } SourceFile: "FooBoolean.java"
java -jar ../asmtools.jar jdis FooBoolean.class > FooBoolean.asm.1
1 MacBook-Pro-2:fload$ cat FooBoolean.asm.1 2 package javap/fload; 3 4 super public class FooBoolean 5 version 52:0 6 { 7 8 static Field boolValue:Z; 9 10 public Method "<init>":"()V" 11 stack 1 locals 1 12 { 13 aload_0; 14 invokespecial Method java/lang/Object."<init>":"()V"; 15 return; 16 17 } 18 19 public static Method main:"([Ljava/lang/String;)V" 20 stack 2 locals 1 21 { 22 iconst_1; // 将这个替换为iconst_2或iconst_3,然后保存结果为FooBoolean.asm.2或FooBoolean.asm.3 23 putstatic Field boolValue:"Z"; 24 getstatic Field boolValue:"Z"; 25 ifeq L18; 26 getstatic Field java/lang/System.out:"Ljava/io/PrintStream;"; 27 ldc String "Hello, Java!"; 28 invokevirtual Method java/io/PrintStream.println:"(Ljava/lang/String;)V"; 29 L18: stack_frame_type same; 30 getstatic Field boolValue:"Z"; 31 iconst_1; // 不替换,这里是true的int值 32 if_icmpne L33; 33 getstatic Field java/lang/System.out:"Ljava/io/PrintStream;"; 34 ldc String "Hello, JVM!"; 35 invokevirtual Method java/io/PrintStream.println:"(Ljava/lang/String;)V"; 36 L33: stack_frame_type same; 37 return; 38 39 } 40 41 } // end Class FooBoolean
输出结果:
$ java -jar ../asmtools.jar jasm FooBoolean.asm.1 $ java javap.fload.FooBoolean // 两行都打印输出 Hello, Java! Hello, JVM! $ java -jar ../asmtools.jar jasm FooBoolean.asm.2 $ java javap.fload.FooBoolean // 没有输出 $ java -jar ../asmtools.jar jasm FooBoolean.asm.3 $ java javap.fload.FooBoolean // 两行都打印输出 Hello, Java! Hello, JVM!
解释:
- 将局部变量区存到堆中(掩码):将boolean 保存在静态域中,指定了其类型为'Z',当修改为2时取低位最后一位为0,当修改为3时取低位最后一位为1,则说明boolean的掩码处理是取低位的最后一位
- 将堆中的数存到局部变量区(除了long、double外都将当做int型处理):
代码:(局部变量修改)
1 public class App{ 2 public static void main(String[] args) { 3 boolean flag = true; 4 if (flag) System.out.println("Hello, Java!"); 5 if (flag == true) System.out.println("Hello, JVM!"); 6 } 7 }
$ java -jar asmtools.jar jdis App.class > App.asm
1 super public class App 2 version 52:0 3 { 4 5 6 public Method "<init>":"()V" 7 stack 1 locals 1 8 { 9 aload_0; 10 invokespecial Method java/lang/Object."<init>":"()V"; 11 return; 12 13 } 14 15 public static Method main:"([Ljava/lang/String;)V" 16 stack 2 locals 2 17 { 18 iconst_1; // 此处替换为2或3,相应文件为App.asm.2或App.asm.3 19 istore_1; 20 iload_1; 21 ifeq L14; 22 getstatic Field java/lang/System.out:"Ljava/io/PrintStream;"; 23 ldc String "Hello, Java!"; 24 invokevirtual Method java/io/PrintStream.println:"(Ljava/lang/String;)V"; 25 L14: stack_frame_type append; 26 locals_map int; 27 iload_1; 28 iconst_1; 29 if_icmpne L27; 30 getstatic Field java/lang/System.out:"Ljava/io/PrintStream;"; 31 ldc String "Hello, JVM!"; 32 invokevirtual Method java/io/PrintStream.println:"(Ljava/lang/String;)V"; 33 L27: stack_frame_type same; 34 return; 35 36 } 37 38 } // end Class App
1 $ java -jar asmtools.jar jasm App.asm 2 $ java App // 输出全部 3 Hello, Java! 4 Hello, JVM! 5 $ java -jar asmtools.jar jasm App.asm.2 6 $ java App // 输出第一行 7 Hello, Java! 8 $ java -jar asmtools.jar jasm App.asm.3 9 $ java App // 输出第一行 10 Hello, Java!
参考文献:https://time.geekbang.org/column/article/11503