基础知识:位、字节
- 位(bit):计算机中最小的数据单位。每一位的状态只能是0或1
- 字节(byte):8个二进制位构成1个"字节(Byte)",存储空间的基本计量单位。如:英文字母占一个字节,汉字占两个字节
如 byte占一个字节,即占用存储空间为 2^8 换算到正负范围 -2^7 ~ 2^7-1
1. 基本数据类型分类
Java中基本数据类型的分类:四类8种
- 整型:byte、short、int、long
- 浮点型:float、double
- 字符型:char
- 布尔型:boolean
2. boolean占几个字节
《Java虚拟机规范》中描述:虽然定义了boolean这种数据类型,但是只对它提供了非常有限的支持。在Java虚拟机中没有任何供boolean值专用的字节码指令,Java语言表达式所操作的boolean值,在编译之后都使用Java虚拟机中的int数据类型来代替,而boolean数组将会被编码成Java虚拟机的byte数组,每个元素boolean元素占8位”。这样我们可以得出boolean类型占了单独使用是4个字节,在数组中又是1个字节。
3. 类型转换
- 实心箭头,表示无信息丢失的转换;
- 虚箭头, 表示可能有精度损失的转换;
- 如果要反过来需要使用强制类型转换关键字 cast ;
不同类型间运算导致的自动装换:
- 如果两个操作数中有一个是 double 类型, 另一个操作数就会转换为 double 类型。
- 否则,如果其中一个操作数是 float 类型,另一个操作数将会转换为 float 类型。
- 否则, 如果其中一个操作数是 long 类型, 另一个操作数将会转换为 long 类型。
- 否则, 两个操作数都将被转换为 int 类型。
- 在JAVA中,对char类型字符运行时,直接当做ASCII表对应的整数来对待。
4. 包装类
Java会为每一个基础数据类型都提供一个相应包装类的目的,在于将Java的所有东西都抽象成对象,可以更方便的控制和使用。
区别:
-
包装类型可以为 null,而基本类型不可以
《阿里巴巴 Java 开发手册》上规定POJO属性必须使用包装类
数据库的查询结果可能是 null,如果使用基本类型的话,因为要自动拆箱(将包装类型转为基本类型,比如说把 Integer 对象转换成 int 值),就会抛出 `NullPointerException` 的异常。 -
包装类型可用于泛型,而基本类型不可以
泛型在编译时会进行类型擦除,最后只保留原始类型,而原始类型只能是 Object 类及其子类——基本类型是个特例
-
基本类型比包装类型更高效
基本数据类型存放在栈空间,而包装类存放在堆空间
-
两个包装类型的值可以相同,但却不相等
Integer a = new Integer(10);
Integer b = new Integer(10);
System.out.println(a == b); // false == 判断的是地址,因为对象不同所以不相等
System.out.println(a.equals(b)); // true
自动装箱和自动拆箱:
装箱就是自动将基本数据类型转换为包装器类型;如:使用Integer.valueOf方法;
拆箱就是自动将包装器类型转换为基本数据类型;如:使用Integer.intValue方法。
当基础类型与它们的包装类有如下几种情况时,编译器会自动帮我们进行装箱或拆箱.
- 进行 = 赋值操作(装箱或拆箱)
- 进行+,-,*,/混合运算 (拆箱)
- 进行>,<,==比较运算(拆箱)
- 调用equals进行比较(装箱)
- ArrayList,HashMap等集合类 添加基础类型数据时(装箱)
相关面试题:
-
拆装箱导致的对象比较问题
public void testAutoBox2() { //1 int a = 100; Integer b = 100; System.out.println(a == b); // true 比较时进行拆箱,直接比较值 //2 Integer c = 100; Integer d = 100; System.out.println(c == d); // true 比较时是比较的对象地址,但是却为true //3 c = 200; d = 200; System.out.println(c == d); // false 比较时是比较的对象地址,false }针对2中的现象,我们可以查看JDK中Integer的源码
// 此方法将始终缓存 -128 到 127(含)范围内的值,并且可能缓存此范围之外的其他值。 // 当需要进行自动装箱时,如果数字在 -128 至 127 之间时,会直接使用缓存中的对象,而不是重新创建一个对象。 public static Integer valueOf(int i) { if (i >= IntegerCache.low && i <= IntegerCache.high) return IntegerCache.cache[i + (-IntegerCache.low)]; return new Integer(i); } private static class IntegerCache { static final int low = -128; static final int high; static final Integer cache[]; static { // high value may be configured by property int h = 127; String integerCacheHighPropValue = sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high"); if (integerCacheHighPropValue != null) { try { int i = parseInt(integerCacheHighPropValue); i = Math.max(i, 127); // Maximum array size is Integer.MAX_VALUE h = Math.min(i, Integer.MAX_VALUE - (-low) -1); } catch( NumberFormatException nfe) { // If the property cannot be parsed into an int, ignore it. } } high = h; cache = new Integer[(high - low) + 1]; int j = low; for(int k = 0; k < cache.length; k++) cache[k] = new Integer(j++); // range [-128, 127] must be interned (JLS7 5.1.7) assert IntegerCache.high >= 127; } } -
拆装箱导致的性能问题
long t1 = System.currentTimeMillis(); Long sum = 0L; for (int i = 0; i < Integer.MAX_VALUE;i++) { sum += i; } long t2 = System.currentTimeMillis(); System.out.println(t2-t1);由于sum被声明成了包装类Long,所以在sum += i 计算的时候进行了大量的拆装箱操作,导致这段代码运行比sum声明成long时时间花费更大