1、包装类与基本数据类型
- 在前面我们已经学过Java的数据类型,可分为基本数据类型和引用数据类型两大类,而基本数据类型是不具有对象的特征的:不能像对象一样拥有属性和方法;无法对象化地进行交互。
- 而通过包装类可以让基本数据类型获取和对象一样的特征,即拥有属性和方法,并可以对象化地进行交互。
- 关于基本数据类型与包装类的对应关系详见博客Java零基础入门笔记2-Java常量与变量
- 数值型基本数据类型对应的包装类都继承自
Number
并实现了Comparable
接口(这里暂时不会讲,后续博客会有),像Byte
、Short
、Integer
、Long
、Float
、Double
都继承自Number
。 - 而布尔型和字符型包装类继承自
Object
并实现了Serializable
或者Comparable
接口。
更多关于包装类的介绍请去官方API自行查阅学习,这里不再赘述。【所有的包装类位于java.lang包下】
2、基本数据类型和包装类之间的转换
- 说到基本数据类型和包装类之间的转换,就不得不提到装箱和拆箱这两个名词。
- 装箱:所谓装箱,即将基本数据类型的值转换为对应包装类的对象。
- 拆箱:所谓拆箱则是装箱的逆操作,即将包装类的对象转换为对应的基本数据类型的值。
- 1.新建一个名为
WrapperProj
的Java项目,新建一个名为com.cxs.wrapper
的包,然后在保重新建一个名为WrapperDemoOne
的测试类,并勾选main
方法。
public class WrapperDemoOne {
public static void main(String[] args) {
// 自动装箱
int t1 = 2;
Integer t2 = t1;
System.out.println("int类型的变量t1=" + t1 + ",Integer类型对象t2=" + t2);
System.out.println("--------------------------");
// 手动装箱
Integer t3 = new Integer(t1);
System.out.println("Integer类型对象t3=" + t3);
System.out.println("--------------------------");
// 自动拆箱
int t4 = t2;
System.out.println("int类型的变量t4=" + t4);
System.out.println("--------------------------");
// 手动拆箱:调用了intValue()方法
int t5 = t2.intValue();
System.out.println("int类型的变量t5=" + t5);
System.out.println("--------------------------");
// 测试一下其他方法
double t6 = t2.doubleValue();
System.out.println("double类型的变量t6=" + t6);
}
}
- 2.运行代码,结果如下。
3、基本数据类型和字符串之间的转换
- 1.在
wrapper
包下新建一个类名为WrapperDemoTwo
。
public class WrapperDemoTwo {
public static void main(String[] args) {
// 基本数据类型--→字符串
int t1 = 2;
String t2 = Integer.toString(t1);
System.out.println("t2被转换为String类型对象:" + (t2 instanceof String));
System.out.println("-------------------------");
// 字符串--→基本数据类型
// 方式1:通过parseInt方法
int t3 = Integer.parseInt(t2);
// 方式2:通过valueOf方法将t2转换为Integer对象,然后在赋值时通过自动拆箱,将其再次转换为int类型的值
int t4 = Integer.valueOf(t2);
System.out.println("t3=" + t3);
System.out.println("t4=" + t4);
}
}
- 2.运行代码结果如下。
4、知识点补充
- 包装类对象的初始值都为null。
- 1.在包下新建一个名为
WrapperDemoThree
的类,并勾选主方法。
public class WrapperDemoThree {
public static void main(String[] args) {
Integer one = new Integer(100);// 手动装箱
Integer two = new Integer(100);// 手动装箱
System.out.println("one==two的结果:" + (one == two));// 比较1
Integer three = 100;// 自动装箱,下同
System.out.println("three==100的结果:" + (three == 100));// 比较2
Integer four = 100;
System.out.println("three==four的结果:" + (three == four));// 比较3
Integer five = 200;
System.out.println("five==200的结果:" + (five == 200));// 比较4
Integer six = 200;
System.out.println("five==six的结果:" + (five == six));// 比较5
}
}
- 2.运行代码结果如下。
- 3.结果分析如下。
- 比较1:
==
两边若比较的是对象的话,则比较的是对象在内存当中的引用是否相同,而不仅仅是里面的值, 通过new关键字开辟的是两块空间,即one和two指向的是不同的内存空间。 - 比较2:代码中采用了自动装箱的操作创建了Integer对象three,然后在与数值100比较时,又采用了自动拆箱的操作,此时比较的是两个整数的值是否相等,结果可想而知。
- 比较3:在创建对象four时,实际上执行的代码是:
Integer four = Integer.valueOf(100);
,如下图,在执行该方法时,为了提高运行效率,Java提供了一个类似于常量数组的缓存区(多数资料叫对象池),若valueOf方法传进来的参数满足-128<参数<127
,会先从这个缓存区中查找是否存在这样一个对象(即值为100的Integer对象),若存在这样一个对象,直接拿来使用;若没有找到,则会隐式调用new关键字去实例化一个Integer对象。而先前在创建Integer对象three时(那时缓存区并不存在满足条件的Integer对象),则会在缓存区构建并保存着这个值为100的Integer对象,而当创建four对象时,发现缓存区存在满足自己要求的对象,此时便可以直接拿来用(即Integer four=three,大家可以更改代码进行尝试)则three和four指向的是缓存区的同一块空间。 - 比较4:解释同比较2。
- 比较5:可以借用比较3的解释,创建five对象时由于传入参数不满足
-128<参数<127
的条件,则不会将该对象放入缓存区,再创建six对象时,会再次创建一个新的对象,这样,five和six指向了不同内存空间。
- 比较1:
补充:在包装类中,除了Double和Float,其他类型的包装类都可以应用对象常量池的概念。(大家可以自行代码尝试)