1. 为什么要有包装类型?
个人理解
- 这是为了弥补基本数据类型的不足 如果你在集合中使用 是无法放入
int
long
之类的类型的 所以需要一个桥梁 为了泛型而考虑 - 这也是为了保证面向对象的完整性 当你需要将字符串
"1123"
转化为int
类型 发现无从下手了 所以包装类可以提供一系列的属性方法 增强基本数据类型 - 数据缓存 当
Integer
类型在 -128~127之间时 会从缓存区去取 作者可能是考虑到这个范围的数比较常用而考虑的吧 - 某些时候我们并不希望一些数值有默认值 即便是0也不想要 我们只希望它为空 而基本数据类型大多默认值为0 而包装类默认就是为null 的
…
2. 自动装箱与拆箱
自动装箱:能够将基本数据类型包装起来变成特定的包装类,无需其他操作
自动拆箱:能够将包装类型转化为基本数据类型,同样无需其他操作
这两点都体现在自动
上
如下所示 轻易就能够转换过去
Integer a=10;
int b = new Integer(20);
让我们探究下内部做了什么操作
通过打断点的方式 我们找到了对应的代码
以下是自动装箱的源码 其实真正调用的是valueOf
方法实现的
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
简单的说下 装箱会从缓存区去取值 如果找的到 直接返回 找不到就new
一个Integer
返回
自动拆箱的代码就更简单了 自动调用initValue
方法 返回 int
类型的 value
值
public int intValue() {
return value;
}
3. 基本数据类型与包装类的==与equals
这样一个面试题想必大家都不陌生
Q1: 请说一下==与equals的区别?
对于基本数据类型 只能用==
来比较两个数值是否相等了 它也想调用equals
方法啊
奈何
其实说白了 ==比较的是内存中的地址 我们常用的 1 2 3 4 5 这些数字
一旦被使用 就会被放入常量池中 下一次使用 指向的还是那个位置 所以一定会相等
但如果是包装类型 就不一定了 用== 可能会相等 可能是不相等的 引出之前提到的常量池技术
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
之前这里没有细讲
IntegerCache.low=-128
IntegerCache.high=127
其实 high的值并不是固定的 可以在jvm参数中设置 但一般我们不做设置 所以就是在这个范围以内
其他类型也实现了常量池技术 Byte,Short,Integer,Long
这 4 种包装类默认创建了数值 [-128,127]
的相应类型的缓存数据,
Character
创建了数值在[0,127]
范围的缓存数据,Boolean 直接返回 True
或 False
。
而 Float,Double
没有实现常量池技术
所以下面的题目应该会做了吧?
Integer a=120;
Integer b=120;
System.out.println(a==b);
Integer c = 130;
Integer d = 130;
System.out.println(c==d);
很简单 分别打印 true
和 false
需要注意一点 一旦使用了 new
就会在堆里面再开辟出一片空间 所以内存地址肯定是不一样的了
再说说 equlals
方法
我们进入 Object
类 查看源码
public boolean equals(Object obj) {
return (this == obj);
}
发现了什么? 竟然也是用的 ==
不对啊 怎么跟我们想象的不一样
因为我们看的是最高级的父类 Object
一般我们都会覆盖equals
方法
我们再看一下 Integer
类的源码
public boolean equals(Object obj) {
//①
if (obj instanceof Integer) {
//②
return value == ((Integer)obj).intValue();
}
return false;
}
在 ① 处 首先会判断下 比较的对象是否是 Integer
类或者是其子类(当然Integer
不可被继承 所以就限定是这个类)
否则就不比较直接返回false
了
在 ② 处 会将对应的对象转化为Integer
类 再拆箱 比较两者是否相等
其实Integer
类的 equals
方法很简单 没什么复杂的操作 以后我们再分析字符串的equals
方法
接下来该回答一下前面的问题了
A1:
- 对于基本数据类型 只能使用
==
比较两个值是否相等 其实比较的就是两个变量的内存地址是否相同 - 对于其他引用类型
==
和equlals
都可以使用 默认Object
的equals
方法比较的就是两个对象的内存地址
一般的常用类都会重写equals
方法,从而可以实现比较两个对象的某个特定内容是否相等
对于我们自定义的类 都需要我们自己重写一下equals
方法,否则默认使用的还是==
4. 阿里巴巴开发手册规约
我再将阿里巴巴开发手册关于包装类型有关的规约发一下
因为有缓存区 所以一律使用equals
这个后面会讲到关于浮点类型的比较
定义一些pojo
类的时候 建议使用包装类型 因为可能值可能为null
返回类型要一致
5. 其他
有了包装类型 我们可以调用一些方法来简化我们的操作
比如定义 int
类型的最大最小值
int a = Integer.MAX_VALUE;
int b = Integer.MIN_VALUE;
将字符串转化为对应的整型
int s=Integer.parseInt("11223");
同样的将 int
类型或者字符串转化为包装类
一种是 new
一种是使用valueOf
int a1 = new Integer("213");
int a2 = Integer.valueOf("213");
int b1 = new Integer(213);
int b2 = Integer.valueOf(213);
推荐使用第二种方法 因为第一种必定会创建新的对象 而第二种可能直接用缓存区里的值 且可能还会有后续优化
要是你老是认为自己配不上一个更好的人,
那么,你也永远无法成为一个更好甚至最好的自己。