1、Java基本数据类型及其对应的包装器类类型
Java中共用8种基本数据类型,并为这8种基本数据类型中的每一种都提供了一个包装器类,例如int类型对应的包装器类是Integer。具体类型如下表:
2、自动装箱和自动拆箱
- 自动装箱:就是指自动将基本数据类型转换为包装器类型。
- 自动拆箱:就是指自动将包装器类型转换为基本数据类型。
Integer i = 19; // 自动装箱
int j = i; // 自动拆箱
如上第一行代码,数组19是基本数据类型(int),当赋值给包装器类型(Integer)变量时,触发自动装箱操作,创建一个Integer类型对象,并且赋值给了 i 。其底层实际执行了以下代码:
Integer i = Integer.valueOf(19);
同理,第二行代码,将 i 赋值给 j,触发了自动拆箱操作,将 i 中的数据取出赋值给 j 。其底层实际执行了以下代码:
int j = i.intValue();
3、双等于“=="
通过” == “ 来比较对比的是栈中的值,基本数据类型比较的值,引用数据类型比较的是堆中内存对象的地址。即判断两个对象是否相等,实际上是在判断两个局部变量存储的地址是否相同,即是否指向相同的对象。
但如下代码中比较的a1和a2却是相等的。b1和b2又是不相等的。
Integer a1 = 58;
Integer a2 = 58;
Integer b1 = 129;
Integer b2 = 129;
Integer a3 = new Integer(58);
System.out.println(a1 == a2); // true
System.out.println(b1 == b2); // false
System.out.println(a1 == a3); // false
实际是,Integer运用了 享元设计模式 来复用对象,当通过自动装箱,即调用 valueOf() 来创建Integer对象的时候,如果要创建的Integer对象的值在 -128~127之间,就会从IntegerCache类中直接返回,否则才会调用new方法创建新的对象。即a1和a2都是指向同一个对象(享元对象),b1和b2不是同一个对象。 而Integer a3 = new Integer(58);并不会调用valueOf(),即不会使用到IntegerCache。
为什么IntegerCache只缓存 -128~127之间的整型值?
当IntegerCache类被加载的时候,缓存的享元对象会被集中一次性创建好,而整型数值太多,不能一次性被创建,否则会占用太多的内存,类加载的时间会过长,即只能缓存大部分应用来说最常用的整型值,即一个字节的大小,byte数据类型的范围。
实际,jdk提供了自定义缓存的最大值,设置方法有
方法一: -Djava.lang.Integer.IntegerCache.high = 255
方法二: -XX:AutoBoxChaheMax = 255
4、字符串类型String
String s1 = "小姐姐";
String s2 = "小姐姐";
String s3 = new String("小姐姐");
System.out.println(s1 == s2); // true
System.out.println(s1 == s3); // false
String类型利用了享元设计模式来复用相同的字符串常量,JVM会专门开辟一块存储区来存储字符串常量,这块存储区叫做”字符串常量池“
Integer类中要共享的对象是在类加载的时候就会集中一次性创建好,而字符串是在第一次被使用时被存储到常量池中,当之后再使用的时候,就直接引用常量池中已经存在的即可。