本文讲解步骤:
- 需要掌握的基础(不讲,只是概述)
- 使用自动装箱的不相等问题
0. 问题引出
@Test
public void test() {
Integer i1 = 127;
Integer i2 = 127;
System.out.println(i1 == i2); // true
Integer i3 = 128;
Integer i4 = 128;
System.out.println(i3 == i4); // false
Integer i5 = new Integer(127);
System.out.println(i1 == i5); // false
}
1. 概述
- 在Java中声明
Integer
的几种方式
public class Demo {
public static void main(String[] args) {
Integer i1 = 1; // 自动装箱
Integer i2 = new Integer(1);// 手动装箱
int i3 = i2; // 自动拆箱
int i4 = i1.intValue(); // 手动拆箱
}
}
- 基本类型的自动拆箱与装箱:
public class Demo {
public static void main(String[] args) {
// 拆箱
Integer i1 = 1;
int i2 = i1;
System.out.println(i2);
// 装箱
int i3 = 1;
Integer i4 = i3;
System.out.println(i4);
}
}
2. 使用自动装箱的不相等问题
因为有Java原生语法的支持,所以包装类型可以这样声明。
public class Demo {
public static void main(String[] args) {
Integer i1 = 1; // 自动装箱
}
}
但是,包装类型的本质就是引用类型。
Integer类结构:
在Java中,每个值都有其对应的内存地址。而内存地址要么是JVM分配,要么是new
关键字开辟的。那么原生语法支持的背后是如何开辟内存的?JVM分配?new
关键字?
其实,原生语法支持的背后就是调用的Integer.valueOf()
方法,看不懂方法签名的可以点击这篇博文
那么打开Integer.valueOf()
方法浏览一番
很简单明了,if
语句中涉及到了IntegerCache
类,比较了IntegerCache
中的两个属性,按照翻译的中文意思来讲,此语句的作用是判断参数i的值是否包含在-128~127
之间,在的话就返回缓存的值。点击IntegerCache
类中看看。
的确,low的值为-128。
看注释得知,该类会在第一次使用Integer时就初始化了。
那么根据前文,使用自动装箱会调用Integer.valueOf(i)
方法或手动调用Integer.valueOf(i)
方法,那么IntegerCache
类就会初始化。
当第一次使用该类,类中的静态代码块就会执行一次。
如何算使用该类呢?分为如下几种情况:
然后根据类的加载机制:
类加载进虚拟机时会调用static代码块
(静态代码块),此时static代码块
执行。
high值可以通过属性配置,此文不教如何配置(其实我也不会)。那么high值一般我们是没有配置的,所以integerCacheHighPropValue
返回的是null
。high
就被赋值了h
。然后for语句就循环257次生成256个Integer对象,并将其储存在缓存数组中。
最后,初始化完了IntegerCache
类,根据参数从IntegerCache
类的cache缓存数组
中获取缓存的Integer
对象,或new
一个新的Integer
对象。
@Test
public void test() {
Integer i1 = 127; // Integer.valueOf(127); 在缓存范围内,取缓存数组中的Integer对象
Integer i2 = 127; // Integer.valueOf(127); 在缓存范围内,取缓存数组中的Integer对象
System.out.println(i1 == i2); // true
Integer i3 = 128; // Integer.valueOf(128); 不在存范围中,new一个新的Integer对象
Integer i4 = 128; // Integer.valueOf(128); 不在存范围中,new一个新的Integer对象
System.out.println(i3 == i4); // false
Integer i5 = new Integer(127); // 手动装箱,自己开辟一个新地址,不用缓存数组中的Integer对象
System.out.println(i1 == i5); // false
}
手动装箱128
和Integer.valueOf(128)
是一模一样的。
public class Demo {
public static void main(String[] args) {
Integer i1 = new Integer(128); // 手动装箱
Integer i2 = Integer.valueOf(128); // 自动装箱
System.out.println(i1 == i2); // false
}
}