先看一段demo:
package com.onlyou; /** * Created by cd_huang on 2017/5/25. */ public class Test { public static void main(String args[]) { intTest(); } public static String intTest(){ int aa =100; Integer bb =100; System.out.println(aa==bb); Integer cc =100; System.out.println(bb==cc); int dd =1000; Integer ee =1000; System.out.println(dd==ee); Integer ff =1000; System.out.println(ee==ff); Integer gg =null; System.out.println(bb==gg); System.out.println(aa==gg); return null; } }
然后看运行结果:
true true true false false Exception in thread "main" java.lang.NullPointerException at com.onlyou.Test.intTest(Test.java:23) at com.onlyou.Test.main(Test.java:8)
第一个对比是int和Integer的对比,在编译期会处理成int100和Integer.intVal
ue获得int100,两个int100的对比,所以是true。
第二个对比是Integer和Integer的对比,所以纯粹是两个对象,如果指向同一个内存位置就会为true,这里理论上是false。但是编译期做了优化,Integer bb =100,其实等同于Integer bb =Integer.valueOf(100),这两种写法编译后的字节码是一样的。Integer.valueOf方法代码如下:
public static Integer valueOf(int i) { assert IntegerCache.high >= 127; if (i >= IntegerCache.low && i <= IntegerCache.high) return IntegerCache.cache[i + (-IntegerCache.low)]; return new Integer(i); }
代码对-127到127之间的Integer对象做了缓存,所以这里会是同一个对象,所以是true。
第三个对比是int和Integer的对比,是true的原因同第一个对比。
第四个对比是Integer和Integer的对比,是false的原因是1000不在-127到127之间,没有缓存,所以是两个对象。
第五个对比是Integer和Integer的对比,Integer100和null肯定是false。
第六个对比是int和Integer的对比,在编译期会处理成int和Integer.intVal来进行两个int的对比,Integer为空,所以这里直接报空指针异常。
所以,上面那段代码其实相当于下面这段代码。
package com.onlyou; /** * Created by cd_huang on 2017/5/25. */ public class Test { public static void main(String args[]) { intTest(); } public static String intTest(){ int aa =100; Integer bb =Integer.valueOf(100); System.out.println(aa==bb.intValue()); Integer cc =Integer.valueOf(100); System.out.println(bb==cc); int dd =1000; Integer ee =Integer.valueOf(1000); System.out.println(dd==ee.intValue()); Integer ff =Integer.valueOf(1000); System.out.println(ee==ff); Integer gg =null; System.out.println(bb==gg); System.out.println(aa==gg.intValue()); return null; } }
解释完了后我们来看编译后的指令是什么样子的。
C:\Users\hcd>javac c:\Test.java C:\Users\hcd>javap -v c:\Test.class Classfile /c:/Test.class Last modified 2017-5-25; size 1037 bytes MD5 checksum c36ad2112f8e55c60615146d0a116c8d Compiled from "Test.java" public class com.onlyou.Test SourceFile: "Test.java" minor version: 0 major version: 51 flags: ACC_PUBLIC, ACC_SUPER Constant pool: #1 = Methodref #8.#22 // java/lang/Object."<init>":()V #2 = Methodref #7.#23 // com/onlyou/Test.intTest:()Ljava/la ng/String; #3 = Methodref #24.#25 // java/lang/Integer.valueOf:(I)Ljava /lang/Integer; #4 = Fieldref #26.#27 // java/lang/System.out:Ljava/io/Prin tStream; #5 = Methodref #24.#28 // java/lang/Integer.intValue:()I #6 = Methodref #29.#30 // java/io/PrintStream.println:(Z)V #7 = Class #31 // com/onlyou/Test #8 = Class #32 // java/lang/Object #9 = Utf8 <init> #10 = Utf8 ()V #11 = Utf8 Code #12 = Utf8 LineNumberTable #13 = Utf8 main #14 = Utf8 ([Ljava/lang/String;)V #15 = Utf8 intTest #16 = Utf8 ()Ljava/lang/String; #17 = Utf8 StackMapTable #18 = Class #33 // java/lang/Integer #19 = Class #34 // java/io/PrintStream #20 = Utf8 SourceFile #21 = Utf8 Test.java #22 = NameAndType #9:#10 // "<init>":()V #23 = NameAndType #15:#16 // intTest:()Ljava/lang/String; #24 = Class #33 // java/lang/Integer #25 = NameAndType #35:#36 // valueOf:(I)Ljava/lang/Integer; #26 = Class #37 // java/lang/System #27 = NameAndType #38:#39 // out:Ljava/io/PrintStream; #28 = NameAndType #40:#41 // intValue:()I #29 = Class #34 // java/io/PrintStream #30 = NameAndType #42:#43 // println:(Z)V #31 = Utf8 com/onlyou/Test #32 = Utf8 java/lang/Object #33 = Utf8 java/lang/Integer #34 = Utf8 java/io/PrintStream #35 = Utf8 valueOf #36 = Utf8 (I)Ljava/lang/Integer; #37 = Utf8 java/lang/System #38 = Utf8 out #39 = Utf8 Ljava/io/PrintStream; #40 = Utf8 intValue #41 = Utf8 ()I #42 = Utf8 println #43 = Utf8 (Z)V { public com.onlyou.Test(); 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 6: 0 public static void main(java.lang.String[]); flags: ACC_PUBLIC, ACC_STATIC Code: stack=1, locals=1, args_size=1 0: invokestatic #2 // Method intTest:()Ljava/lang/Str ing; 3: pop 4: return LineNumberTable: line 8: 0 line 9: 4 public static java.lang.String intTest(); flags: ACC_PUBLIC, ACC_STATIC Code: stack=3, locals=7, args_size=0 0: bipush 100 2: istore_0 3: bipush 100 5: invokestatic #3 // Method java/lang/Integer.valueO f:(I)Ljava/lang/Integer; 8: astore_1 9: getstatic #4 // Field java/lang/System.out:Ljav a/io/PrintStream; 12: iload_0 13: aload_1 14: invokevirtual #5 // Method java/lang/Integer.intVal ue:()I 17: if_icmpne 24 20: iconst_1 21: goto 25 24: iconst_0 25: invokevirtual #6 // Method java/io/PrintStream.prin tln:(Z)V 28: bipush 100 30: invokestatic #3 // Method java/lang/Integer.valueO f:(I)Ljava/lang/Integer; 33: astore_2 34: getstatic #4 // Field java/lang/System.out:Ljav a/io/PrintStream; 37: aload_1 38: aload_2 39: if_acmpne 46 42: iconst_1 43: goto 47 46: iconst_0 47: invokevirtual #6 // Method java/io/PrintStream.prin tln:(Z)V 50: sipush 1000 53: istore_3 54: sipush 1000 57: invokestatic #3 // Method java/lang/Integer.valueO f:(I)Ljava/lang/Integer; 60: astore 4 62: getstatic #4 // Field java/lang/System.out:Ljav a/io/PrintStream; 65: iload_3 66: aload 4 68: invokevirtual #5 // Method java/lang/Integer.intVal ue:()I 71: if_icmpne 78 74: iconst_1 75: goto 79 78: iconst_0 79: invokevirtual #6 // Method java/io/PrintStream.prin tln:(Z)V 82: sipush 1000 85: invokestatic #3 // Method java/lang/Integer.valueO f:(I)Ljava/lang/Integer; 88: astore 5 90: getstatic #4 // Field java/lang/System.out:Ljav a/io/PrintStream; 93: aload 4 95: aload 5 97: if_acmpne 104 100: iconst_1 101: goto 105 104: iconst_0 105: invokevirtual #6 // Method java/io/PrintStream.prin tln:(Z)V 108: aconst_null 109: astore 6 111: getstatic #4 // Field java/lang/System.out:Ljav a/io/PrintStream; 114: aload_1 115: aload 6 117: if_acmpne 124 120: iconst_1 121: goto 125 124: iconst_0 125: invokevirtual #6 // Method java/io/PrintStream.prin tln:(Z)V 128: getstatic #4 // Field java/lang/System.out:Ljav a/io/PrintStream; 131: iload_0 132: aload 6 134: invokevirtual #5 // Method java/lang/Integer.intVal ue:()I 137: if_icmpne 144 140: iconst_1 141: goto 145 144: iconst_0 145: invokevirtual #6 // Method java/io/PrintStream.prin tln:(Z)V 148: aconst_null 149: areturn LineNumberTable: line 11: 0 line 12: 3 line 13: 9 line 14: 28 line 15: 34 line 16: 50 line 17: 54 line 18: 62 line 19: 82 line 20: 90 line 21: 108 line 22: 111 line 23: 128 line 24: 148 StackMapTable: number_of_entries = 12 frame_type = 255 /* full_frame */ offset_delta = 24 locals = [ int, class java/lang/Integer ] stack = [ class java/io/PrintStream ] frame_type = 255 /* full_frame */ offset_delta = 0 locals = [ int, class java/lang/Integer ] stack = [ class java/io/PrintStream, int ] frame_type = 255 /* full_frame */ offset_delta = 20 locals = [ int, class java/lang/Integer, class java/lang/Integer ] stack = [ class java/io/PrintStream ] frame_type = 255 /* full_frame */ offset_delta = 0 locals = [ int, class java/lang/Integer, class java/lang/Integer ] stack = [ class java/io/PrintStream, int ] frame_type = 255 /* full_frame */ offset_delta = 30 locals = [ int, class java/lang/Integer, class java/lang/Integer, int, class java/lang/Integer ] stack = [ class java/io/PrintStream ] frame_type = 255 /* full_frame */ offset_delta = 0 locals = [ int, class java/lang/Integer, class java/lang/Integer, int, class java/lang/Integer ] stack = [ class java/io/PrintStream, int ] frame_type = 255 /* full_frame */ offset_delta = 24 locals = [ int, class java/lang/Integer, class java/lang/Integer, int, class java/lang/Integer, class java/lang/Integer ] stack = [ class java/io/PrintStream ] frame_type = 255 /* full_frame */ offset_delta = 0 locals = [ int, class java/lang/Integer, class java/lang/Integer, int, class java/lang/Integer, class java/lang/Integer ] stack = [ class java/io/PrintStream, int ] frame_type = 255 /* full_frame */ offset_delta = 18 locals = [ int, class java/lang/Integer, class java/lang/Integer, int, class java/lang/Integer, class java/lang/Integer, class java/lang/Integer ] stack = [ class java/io/PrintStream ] frame_type = 255 /* full_frame */ offset_delta = 0 locals = [ int, class java/lang/Integer, class java/lang/Integer, int, class java/lang/Integer, class java/lang/Integer, class java/lang/Integer ] stack = [ class java/io/PrintStream, int ] frame_type = 82 /* same_locals_1_stack_item */ stack = [ class java/io/PrintStream ] frame_type = 255 /* full_frame */ offset_delta = 0 locals = [ int, class java/lang/Integer, class java/lang/Integer, int, class java/lang/Integer, class java/lang/Integer, class java/lang/Integer ] stack = [ class java/io/PrintStream, int ] }
上面就是intTest()方法编译后的二进制指令。这边简单的解释下二进制指令怎么看。
首先简单介绍下jvm内存模型。
没花太多时间找到更合适的图片了。在我的理解里,更希望以线程私有还是线程共享来区分上图的每个部分,感觉会更清楚。上图转自http://blog.csdn.net/u012152619/article/details/46968883,对内存模型没什么了解的可以先看链接里的内容,当然,最好是看一下周志明老师的《深入理解Java虚拟机》,最经典的虚拟机学习书本。上图中方法区和堆是线程共享的,即每个线程都可以访问,所以存在线程安全的问题。而虚拟机栈,本地方法栈,程序计数器是线程独有的。程序的执行,调用一个方法时,就相当于把方法进栈,在方法执行结束后出栈,符合后进先出。
因为二进制指令主要是描述java代码的执行,所以主要关注虚拟机栈内的局部变量表和操作数栈。操作数栈是执行的真正工作区,是重中之重。二进制指令可以对照http://www.blogjava.net/DLevin/archive/2011/09/13/358497.html查看含义。注意每次操作数栈的内容使用完后都会出栈。下面是我给二进制指令加了些注释,以及写了在每一条指令执行完后,操作数栈和本地变量表的变化。
public static java.lang.String intTest(); flags: ACC_PUBLIC, ACC_STATIC Code: stack=3, locals=7, args_size=0(操作数栈长度为3,本地常量表的长度为7,因为是静态方法,所以方法的参数个位为0) 0: bipush 100 //valuebyte值带符号扩展成int值入栈。 (此时操作数栈内容为:100,null,null,局部变量表为:null,null,null,null,null,null,null) 2: istore_0 //将栈顶int类型值保存到局部变量0中。 (此时操作数栈内容为:null,null,null,局部变量表为:100,null,null,null,null,null,null) 3: bipush 100 //valuebyte值带符号扩展成int值入栈。 (此时操作数栈内容为:100,null,null,局部变量表为:100,null,null,null,null,null,null) 5: invokestatic #8 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer; //调用静态方法Integer.valueOf (此时操作数栈内容为:Integer(100)的引用,null,null,局部变量表为:100,null,null,null,null,null,null) 8: astore_1 //将栈顶引用类型值保存到局部变量1中。 (此时操作数栈内容为:null,null,null,局部变量表为:100,Integer(100)的引用,null,null,null,null,null) 9: getstatic #4 // Field java/lang/System.out:Ljav a/io/PrintStream; (此时操作数栈内容为:PrintStream的引用,null,null,局部变量表为:100,Integer(100)的引用,null,null,null,null,null) 12: iload_0 //从局部变量0中装载int类型值入栈。 (此时操作数栈内容为:100,PrintStream的引用,null,局部变量表为:100,Integer(100)的引用,null,null,null,null,null) 13: aload_1 //从局部变量1中装载引用类型值入栈。 (此时操作数栈内容为:Integer(100)的引用,100,PrintStream的引用,局部变量表为:100,Integer(100)的引用,null,null,null,null,null) 14: invokevirtual #9 // Method java/lang/Integer.intVal ue:()I (此时操作数栈内容为:100,100,PrintStream的引用,局部变量表为:100,Integer(100)的引用,null,null,null,null,null) 17: if_icmpne 24 //若栈顶两int类型值不相等则跳转。(跳转到24,即'24: iconst_0'这行) (此时操作数栈内容为:PrintStream的引用,null,null,局部变量表为:100,Integer(100)的引用,null,null,null,null,null) 20: iconst_1 //1(int)值入栈。 (此时操作数栈内容为:1,PrintStream的引用,null,局部变量表为:100,Integer(100)的引用,null,null,null,null,null) 21: goto 25 //无条件跳转到指定位置。(因为执行了20: iconst_1,所以跳过了24: iconst_0,直接跳到25: invokevirtual) 24: iconst_0 //0(int)值入栈。 (此时操作数栈内容为:0,PrintStream的引用,null,局部变量表为:100,Integer(100)的引用,null,null,null,null,null) 25: invokevirtual #5 // Method java/io/PrintStream.prin tln:(Z)V (此时操作数栈内容为:null,null,null,局部变量表为:100,Integer(100)的引用,null,null,null,null,null) 28: bipush 100 (此时操作数栈内容为:100,null,null,局部变量表为:100,Integer(100)的引用,null,null,null,null,null) 30: invokestatic #8 // Method java/lang/Integer.valueO f:(I)Ljava/lang/Integer; (此时操作数栈内容为:Integer(100)的引用,null,null,局部变量表为:100,Integer(100)的引用,null,null,null,null,null) 33: astore_2 (此时操作数栈内容为:null,null,null,局部变量表为:100,Integer(100)的引用,Integer(100)的引用,null,null,null,null) 34: getstatic #4 // Field java/lang/System.out:Ljav a/io/PrintStream; (逻辑同上面。。这里就不再重述了) 37: aload_1 38: aload_2 39: if_acmpne 46 42: iconst_1 43: goto 47 46: iconst_0 47: invokevirtual #5 // Method java/io/PrintStream.prin tln:(Z)V 50: sipush 1000 53: istore_3 54: sipush 1000 57: invokestatic #8 // Method java/lang/Integer.valueO f:(I)Ljava/lang/Integer; 60: astore 4 62: getstatic #4 // Field java/lang/System.out:Ljav a/io/PrintStream; 65: iload_3 66: aload 4 68: invokevirtual #9 // Method java/lang/Integer.intVal ue:()I 71: if_icmpne 78 74: iconst_1 75: goto 79 78: iconst_0 79: invokevirtual #5 // Method java/io/PrintStream.prin tln:(Z)V 82: sipush 1000 85: invokestatic #8 // Method java/lang/Integer.valueO f:(I)Ljava/lang/Integer; 88: astore 5 90: getstatic #4 // Field java/lang/System.out:Ljav a/io/PrintStream; 93: aload 4 95: aload 5 97: if_acmpne 104 100: iconst_1 101: goto 105 104: iconst_0 105: invokevirtual #5 // Method java/io/PrintStream.prin tln:(Z)V 108: aconst_null 109: astore 6 111: getstatic #4 // Field java/lang/System.out:Ljav a/io/PrintStream; 114: aload_1 115: aload 6 117: if_acmpne 124 120: iconst_1 121: goto 125 124: iconst_0 125: invokevirtual #5 // Method java/io/PrintStream.prin tln:(Z)V 128: getstatic #4 // Field java/lang/System.out:Ljav a/io/PrintStream; 131: iload_0 132: aload 6 134: invokevirtual #9 // Method java/lang/Integer.intVal ue:()I 137: if_icmpne 144 140: iconst_1 141: goto 145 144: iconst_0 145: invokevirtual #5 // Method java/io/PrintStream.prin tln:(Z)V 148: aconst_null 149: areturn
文章中很多内容都只是个人的一些理解,如果有什么问题可以在评论里留言。欢迎交流。
相关推荐
java中Integer包装类的详细讲解(java二进制操作,所有进制转换) 十进制转成二进制 十进制转八进制 十进制转十六进制 十六进制转成十进制 十六进制转成二进制 八进制转成十进制 等等所有进制转换和操作
总结,包装类在Java中扮演着重要角色,它们使得基本数据类型能够适应面向对象的环境,提供了更丰富的功能,同时也优化了性能。理解和熟练使用包装类及其转换方法,对于编写高质量的Java代码至关重要。
Java中的包装类是Java语言为每个基本数据类型提供的一个引用类型对应,它们使得基本数据类型具备了面向对象的特性,从而在需要使用面向对象编程思想处理基本数据类型时提供了便利。包装类包括Integer、Character、...
Java基本类型包装类概述与Integer类、Character类用法分析 Java基本类型包装类概述: Java基本类型包装类是将基本数据类型封装成对象的,以便在对象中定义更多的功能方法来操作该数据。常用的操作之一是用于基本...
在Java编程语言中,`java.lang.Integer`是`int`原始类型的一个包装类,它提供了许多与整数相关的操作和方法。以下是对标题和描述中提到的`Integer`类的详细分析: 1. **Integer**: `Integer`是Java中的一个核心类,...
从给定的代码片段来看,这实际上是一段C++代码,而非Java代码,旨在将一个十六进制字符串转换为双精度浮点数(double)。在深入解析这段代码之前,我们首先来了解一下Java中如何实现16位内存数据转化为double型。 #...
在Java编程语言中,Integer类是int类型的一个包装类,提供了许多方便的静态方法和实例方法来处理整型数据。本文将重点解析Integer类中的一些关键方法,包括toString、toUnsignedString以及highestOneBit。 首先,...
Java语法糖是指为了简化编程语法而引入的一些特殊写法,而Java编译器则负责将这些高级语法转换为Java字节码,字节码是Java虚拟机(JVM)能够理解的二进制指令。 自动装箱与自动拆箱是Java中的一项语法糖特性,它...
在 Java 中,基本数据类型包装类包括 Byte、Short、Integer、Long、Character、Float、Double、Boolean 等。 Integer 类是基本数据类型 int 的包装类。Integer 类具有以下特点: * 它是 final 的,因此无法被继承...
在Java编程语言中,为了能够把基本数据类型当作对象处理,提供了包装类的概念。包装类是将基本数据类型封装成类的形式,使它们可以拥有对象的特性。Java语言中一共有八个基本数据类型,它们分别是byte、short、int、...
线性整数规划(Linear Integer Programming, LIP)是一种在离散空间中寻找最优解的数学优化方法,广泛应用于各种实际问题,如生产计划、资源配置、网络设计等。MATLAB作为一款强大的数值计算软件,提供了丰富的工具...
当使用对象的方式处理int值时,可以调用包装类提供的各种方法来处理数据,例如在集合中存储int值。包装类还允许使用null值,这是基础类型无法做到的。 ### int的取值范围 int型数据长度为4个字节,即32位,其中第...
在提供的代码`BasicDemo13`中,可以看到如何使用包装类进行各种转换: - `Integer.MAX_VALUE`展示了整型的最大值。 - `Integer.parseInt("12345")`演示了如何将字符串转换为整数。 - `Integer.toBinaryString(-2)`...
Java中的包装类是针对基本数据类型(如int、char、double等)的一种特殊设计,它为每个基本类型提供了一个对应的类,例如...理解并熟练使用包装类是Java编程中不可或缺的一部分,尤其是在处理数据转换和函数参数时。
在Java中,Integer 是基本数据类型 int 的包装类,它提供了一些方便的方法来处理整数。Integer 类包含以下主要知识点: 1. **属性**: - `MAX_VALUE`:Integer 类中定义的最大整数值,即 2147483647。 - `MIN_...
在文档的示例中,我们看到的是一个关于基本类型包装器类Integer的用法,`i++`表示将Integer对象i所持有的int值加1。Integer对象是自动装箱的,所以在使用自增运算符时,会先将Integer对象转换回int,进行自增操作,...
- 示例代码演示了如何使用 `Integer.parseInt()` 和 `Integer.toHexString()` 方法进行二进制到十进制、十进制到十六进制的转换。 通过实验5的学习,学生可以深入理解Java中字符串处理、数据类型转换、输入输出...
System.out.println("\n基本类型:int 二进制位数:" + Integer.SIZE); System.out.println("包装类:java.lang.Integer"); System.out.println("最小值:Integer.MIN_VALUE=" + Integer.MIN_VALUE); System.out...