1、JVM JRE JDK
JVM
是Java虚拟机,它可以屏蔽Java程序和底层操作系统的差异;
JVM
只有结合了Java的一些基础类库才能构成真正意义上的Java运行时环境,即JRE
而JDK
在这JRE
的基础上加上一些编译开发工具(如javac,javap,内存检测工具)就是JDK
基础类库:平时我们开发时需要用到的类,比如说java.lang.*,集合类,线程类,日期类,IO类
2、Java数据类型
1、数据类型
:
Java语言有8大基本数据类型:
-
4个整形。byte(8)、short(16)、int(32)、long(64)
-
2个浮点。float(32)、double(64)
-
char(16) 和 boolean(~)
boolean 只有 True 和 False 两个值,可以使用 1 bit 来存储,但是具体大小没有明确规定。
JVM 会在编译时期将 boolean 类型的数据转换为 int,使用 1 来表示 true,0 表示 false。
JVM 支持 boolean 数组,但是是通过读写 byte 数组来实现的。
每种类型占有的内存长度不同,可存储的数值范围也就不同,如果存储值超出类型范围,称为溢值(overflow)
2、包装类型
:
基本类型都有自己的包装器,如果想要让基本类型像对象一样操作,就可以使用这些包装类型。例如:Integer、Long、Double、Float、Boolean、Byte等包装类型。
3、自动拆装箱
:
编译器会自动判断是否能够进行自动装箱:
Integer wrapper = 10; // 自动装箱,调用了Integer.valueOf(2)
int foo = wrapper; // 自动拆箱,调用了wrapper.intValue()
Boolean foo = true;
System.out.println(foo && false); // false
同样的,在进行&&
运算时,会先将foo拆箱,再与false进行运算
4、自动拆装箱原理
:
自动装箱与拆箱的原理其实是Compiler Sugar
,即编译程序语法糖
也就是说,编译程序会让我们在写代码时“吃点糖”(更方便),然后在编译时期根据所撰写的语法,再去决定是否要进行装箱和拆箱的动作,例如:
Integer num = 520;
编译程序会将这行代码展开成:
Integer localInteger = Integer.valueOf(520);
了解编译程序会如何装箱和拆箱是有必要的,例如:
Integer a = null;
int b = a;
可以通过编译,但当编译程序对其展开时会出现错误:
Object obj = null;
int a = obj.intValue();
在Java中,null
代表一个特殊对象
,它不属于任何对象实体。也是因为这个原因,所以就不可能执行intValue(),会出现NullPoniterException的错误信息
5、默认类型
:
在Java语言中。若是出现整形,则默认是int类型;若是出现浮点型,则默认是float类型
也可以使用更一般化的Number类来自动装箱
Number num = 3.14f;
在上面的代码中,3.14f会被自动装箱为Float,然后再指定给number
6、缓存池
:
- byte【对应Byte】:-128~127
- int【对应Integer】:-128~127
- short【对应Short】:-128~127
- boolean【对应Boolean】:true和false
- char【对应Character】:\u0000 to \u007F
在使用这些基本类型的包装类型时,如果该数值范围在缓冲池范围内,就可以直接使用缓冲池中的对象
编译器会在自动装箱过程调用 valueOf() 方法,因此多个值相同且值在缓存池范围内的 Integer 实例使用自动装箱来创建,那么就会引用相同的对象
在 jdk1.8 所有的数值类缓冲池中,Integer 的缓冲池 IntegerCache 很特殊,这个缓冲池的下界是 -128,上界默认 127,但是这个上界是可调的,在启动 JVM 的时候,通过
-XX:AutoBoxCacheMax=<size>
来指定这个缓冲池的大小,该选项在 JVM 初始化的时候会设定一个名为 java.lang.IntegerCache.high 系统属性,然后 IntegerCache 初始化的时候就会读取该系统属性来决定上界。