看了不少关于数据类型的文章(面向百度编程的时候),发现都没有跟装箱/拆箱联系起来,更没有讲解在实战中这些概念的运用以及为什么要这么运用,所以我把脑海里关于这些概念结合一些资料的补充把它们串联起来,通过下面的讲解后你会对java的数据类型以及实际运用有更深刻的了解,为的就是在平时码代码或者学习其他知识时能更通透。
开胃小菜
在讲解这一篇之前,先上一张java的数据分类图:
还有一张基本数据类型占用的空间和取值范围的表格,心里大概有个数,不用死记硬背:
数据类型 | 占用空间 | 取值范围 | 备注 |
---|---|---|---|
byte | 1字节 | -2的31次方到2的31次方-1 | |
boolean | 1字节 | false/true | |
char | 2字节 | 0到2的16次方-1 | java规定字符采用unicode编码,规定2个字节表示一个字符:char c = ‘s’ |
short | 2字节 | -32768~32767 | |
int | 4字节 | -2的63次方到2的63次方-1 | |
float | 4字节 | -2的149次方到2的128次方-1 | 带后缀F的浮点数值 |
long | 8字节 | -2的63次方到2的63次方-1 | |
double | 8字节 | -2的1074次方到2的1024次方-1 | 不带后缀F的浮点数值 |
包装类和基本数据类型的区别
这一块有很多人都有点懵的知识点:
- int和Integer的区别
- double和Double的区别
- float和Float的区别
… …
前者在上图可以看到都属于基本数值类型,后者在java中则被称为包装类Wrapper Class
我们拿Integer来解释下,先进入Integer的源码中看一眼:
继承了Number并实现了 Comarable
接口(接口里只有一个 compareTo
方法),定义了最大值和最小值的范围(80000000~7fffffff),0x代表十六进制,略过…挑一个跟我们问题相关的代码:
Integer内部定义了一个int值 value
(注意,有一个 final
修饰词,代表一旦创建了Integer对象,那么该对象就不会变了),有参构造器支持传入int值为 value
赋值,相当于是在为包装类Integer赋值,好,再往下看
是不是又发现了一个有参构造器,不同之处是传入了String类型(不要把String类型和上面的数据类型混为一谈,它比较特殊,后面会详细讲到),最终结果也是通过Integer的 parseInt()
方法给 value
赋值
上面这两种赋值行为我们称之为自动装箱,反之就是自动拆箱
Integer i = new Integer(666);//自动装箱
int ii = i.intValue();//自动拆箱
问题来了,这种装箱拆箱有什么意义吗,基本数据类型不能直接用吗?
先讲下这两者之间的主要区别:
- 包装类是class,生成的对象是引用类型,对象是放在内存堆中的,通过引用来调用值,基本数据类型是把值放在栈内,也不需要引用,直接赋值(高效)
- 包装类的初始值都是null,而基本类型都各不相同,比如int的初始值为0,boolean为false,且必须要先声明,否则编译期就会报错
总而言之,包装类是一种类,JDK提供的,不属于上述基本数据类型里的任何一种,是属于引用类型的类class
一个是引用类型的类,一个是基本数值类型,你觉得在java程序里用哪个操作数值转换会更方便点?
答案肯定是引用类型啦?
包装类的第一个好处:jdk提供了大量的方法供包装类来进行花式数值转换
比如把一个int=100的值按照8进制输出,可以这么做
int i = Integer.parseInt("100",8);//返回64
也有这样直接转成其他数值类型的,不必担心强转出错的问题
包装类的第二个好处:实体类创建用包装类的话程序对于非空判断比较好控制
比如创建一个实体类:
public class Student {
//学员姓名
private String name;
//考试成绩
private int score;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getScore() {
return score;
}
public void setScore(int score) {
this.score = score;
}
}
如果数据返回age是空,定义的age因为int类型默认值为0所以会返回0,但是你能说这个学生考试成绩是0分吗?严谨点来说应该是查不到这个学生的考试成绩,而上面说到包装类的初始值是null,所以这里如果用 private Integer score;
作为成绩字段会更合适点(如果考试成绩是0那么Integer的值也是0,无就是返回null)
而且,在泛型和反射调用函数的时候也需要用到包装类
包装类的第三个好处:可以在一些collection/map中使用
用基本数值类型放在集合中时编译期间就会报错,包装类因为是class所以完全没问题,在实际应用肯定存在对数值进行集合操作的情况
好处这么多,那缺点肯定也有咯:
- 装箱和拆箱会影响代码的执行效率
- 在装/拆箱时可能会出现的各种异常
实际码代码的时候,基本数值类型和包装类型都会用到,但我觉得后者在实际开发的过程使用的情况多得多。
文章比较长,因为希望你们能理解(其实也有助于我能彻底搞懂),本篇文章的内容到这里就结束了,分割线下的是额外联想到的内容
特殊的String
你会发现,java代码里用的最多的String居然没有出现在上述的数据类型里,是不是很奇怪,那String到底算是什么类型?
String在java中被称为字符串,很明显,字符就是上面的字符类型char,那为什么平时编码一般都是使用String而很少使用char呢?
字符char只能占用两个字节,所以不能用char去定义多个字符(字符串),但可以用字符数组转成String字符串(早期的jdk确实会用char[]来作为字符串):
char[] cs = {
'第','一','次','操','作'};
System.out.println("输出结果:"+String.valueOf(cs));
System.out.println("字符串长度:"+String.valueOf(cs).length());
看到第一个应该是你们期待的结果,但是第二个字符串长度为什么是5而不是10?不是说一个字符占用两个字节吗?
答案:.length()方法输出的是字符个数,不是字节个数
转成字符串好麻烦,有么有更加简单的办法
当然有了! 如String cs = "第一次操作"
,因为太常用,所以为了简化操作jdk提供了这种语法,这种语法跟我们平常理解的字符串对象生成方式有区别,我们想的是生成一个String对象可以这样子嘛: String s = new String("啦啦啦")
,也可以,但是这样子做的坏处有两个:
- 写法稍微麻烦了一点,相比前者
- 直接在堆内存中创建新对象,不管是否已经存在相同值的对象
第一种创建对象的过程在下面会结合代码一起讲解,先看下String类里的源码。
和上面的包装类一样,会在String源码里发现这么一句话:
这个意味着什么?
字符串不可变,一旦生成字符串对象那么指向该字符串的对象不可再变,我们用下面的代码来验证这种说法:
String getfood = "我点了一只鸡翅";
String getfood2 = "我点了一只鸡翅";
System.out.println("两个字符串==结果:"+(getfood == getfood2));
System.out.println("两个字符串equals结果:"+(getfood.equals(getfood2)));
输出结果:
为什么==的结果也是true,不是说是两个对象吗?其实是这样的,jdk在编译的时候会把字符串对象放到一个常量池里面(不管有多少个相同的字符串都会被当做一个对象),**这个常量池独立于栈和堆而存在,存储不可变量,**所以上面两个变量引用的都是同一个对象,那我们做一下改变,事先让两个字符串不同,在编译期后即放入常量池后再让两个字符串的值变一样:
String getfood = "我点了一只鸡翅";
String g1 = "我点了";
String g2 = "一只鸡翅";
String getfood2 = g1 + g2;
System.out.println("两个字符串==结果:"+(getfood == getfood2));
System.out.println("两个字符串equals结果:"+(getfood.equals(getfood2)));
输出结果:
上面说到还有一种创建String对象的方式,我们来验证下这种方式的对象是否相等:
String s1 = new String("我点了一只鸡翅");
String s2 = new String("我点了一只鸡翅");
System.out.println("两个字符串==结果:"+(s1 == s2));
System.out.println("两个字符串equals结果:"+(s1.equals(s2)));
输出结果:
所以说为什么我们平时都用string s1 = ““而不是用new string(””),不仅仅是因为方便,后者会每次在堆内存中创建一个新对象,而前者首先会在常量池里找有没有相同值的对象进行引用,有的话就直接引用不重新创建了。
总结下:String是jdk为了方便操作字符数组而创建的特殊类,可以与上述的包装类混为一谈,但不能与char像int与Integer之间的关系一样对应,需要懂得为什么平常都用String s1 = “”这种语法
这块内容可能还会有补充,先写到这吧…
今天的文章什么是自动装箱拆箱_样品箱图片「建议收藏」分享到此就结束了,感谢您的阅读。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/69100.html