先看一段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二进制操作,所有进制转换) 十进制转成二进制 十进制转八进制 十进制转十六进制 十六进制转成十进制 十六进制转成二进制 八进制转成十进制 等等所有进制转换和操作
- `SIZE`:int类型在二进制补码表示下的位数。 - `TYPE`:表示int基本类型的Class对象。 例如,以下代码展示了如何使用这些常量: ```java int maxint = Integer.MAX_VALUE; int minint = Integer.MIN_VALUE; int ...
Java中的包装类是Java语言为每个基本数据类型提供的一个引用类型对应,它们使得基本数据类型具备了面向对象的特性,从而在需要使用面向对象编程思想处理基本数据类型时提供了便利。包装类包括Integer、Character、...
Java基本类型包装类概述与Integer类、Character类用法分析 Java基本类型包装类概述: Java基本类型包装类是将基本数据类型封装成对象的,以便在对象中定义更多的功能方法来操作该数据。常用的操作之一是用于基本...
在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 的,因此无法被继承...
线性整数规划(Linear Integer Programming, LIP)是一种在离散空间中寻找最优解的数学优化方法,广泛应用于各种实际问题,如生产计划、资源配置、网络设计等。MATLAB作为一款强大的数值计算软件,提供了丰富的工具...
编程语言经历了从机器语言到高级语言的演变,从最初的二进制指令集(如汇编语言)到过程化语言(如C语言),再到面向对象编程(OOP)的阶段。面向对象编程强调通过封装、继承和多态来组织和管理代码,Java就是一种...
在文档的示例中,我们看到的是一个关于基本类型包装器类Integer的用法,`i++`表示将Integer对象i所持有的int值加1。Integer对象是自动装箱的,所以在使用自增运算符时,会先将Integer对象转换回int,进行自增操作,...
1. **数据类型**:Java有多种数据类型用于存储十进制数值,包括基本类型(如`int`, `long`, `float`, `double`)和包装类(如`Integer`, `Long`, `Float`, `Double`)。其中,`int`用于整数,`float`和`double`用于...
在JSP系统中,常常会用到一些核心的Java类,如Integer、Float、Math以及Random类,这些类在处理数据和生成随机数时发挥着重要作用。 **Integer类**是Java中的一个包装类,它主要用于处理整数类型的数据。Integer类...
- `TestDigitCount.java`可能涉及到数字处理,例如计算数字的位数或者进行位运算,这些在处理二进制数据或优化算法时很有用。 8. **字符串操作**: - 尽管没有明确的`String`相关的文件,但在Java中,字符串处理...
Java提供了基本数据类型的包装类,例如`Integer`、`Double`和`Float`,它们包含了将字符串转换为对应数值类型的方法。例如: - `Integer.parseInt(String s)`将字符串转换为`int`类型。 - `Double.parseDouble...
14. Integer与int的主要区别在于Integer是int的包装类,可以用于对象操作,如封装、比较、null值等。Integer对象在一定范围内有缓存,而int是原始类型,性能更高,但无法作为对象使用。 以上内容只是Java面试宝典...
其次,`java.lang.Integer`类是对基本类型`int`的包装类,提供了许多实用方法: 1. `byteValue()`, `doubleValue()`, `floatValue()`, `longValue()`, `shortValue()`:将`Integer`对象转换为相应的原始类型值。 2....
在 Java 中,每种基本数据类型都有对应的包装类,如 `Byte`、`Short`、`Integer`、`Long`、`Float`、`Double`、`Boolean` 和 `Character`。这些包装类提供了很多方便的方法,例如将基本类型转换成字符串,以及进行...
对于基本数据类型,Java提供了对应的包装类,如Integer、Double等,这些包装类支持自动装箱(对象到基本类型)和拆箱(基本类型到对象)操作。 String在Java中是不可变的,这意味着一旦创建了String对象,其内容就...
基础类型如`int`、`char`直接存储值,而它们的包装类如`Integer`、`Character`是对象,可以支持更多的高级功能,如比较、序列化等。在实体类中,如果你的属性不需要这些额外功能,通常使用基础类型以节省内存和提高...
4. **方法返回值**:在编程中,`boolean` 类型通常用于表示逻辑判断,`int` 表示整型数值,`String` 表示字符串,`Integer` 是 `int` 的包装类,通常用于对象引用。`()` 方法没有返回值,因此返回值类型是 `void`,...