一.概述:
-
包装类就是把基本数据类型转换为对象(引用数据类型)
二.理解包装类:
-
对于基本数据类型,在变量中记录的是真实的数据值,例如上述图片中定义了一个基本数据类型的整型变量i为10,那么变量i真实的数据值就是10,内存中变量记录的也是10
-
以int为例,int对应的包装类为Integer类,可以认为在Java中是用Integer类来描述整数,在Integer类里有一个属性值value,value用来记录整数的数据值
-
创建包装类的对象也是用new关键字去创建,比如此时创建了一个Integer类对象即Integer n=new Integer(10);->该对象名为n,类型为Integer类,传入的属性值为10,这是时会在栈里创建一个变量n,类型是Integer类,由于此时是new的对象,所以就会在堆里再开辟一个小空间记录成员变量value,成员变量value就记录n的属性值10,而栈里的n记录的是成员变量value在堆内的地址值
-
包装类的本质就是创建了一个对象,对象中记录对应的数据值->包装类:用一个对象,把基本数据类型给包起来
三.为什么要学习包装类:
在Java中,万物皆对象,由于多态的存在,所有的对象都是Object类的子类,意味着所有对象都可以被Object类接收,
对于基本数据类型,如果没有包装类,假设此时传递了一个整数,就会导致Object类无法接收,程序就会有局限性,
而且在集合中,是不能存储基本数据类型的,只能存储对象即引用数据类型,所以要想往集合中存储基本数据类型,就必须用基本数据类型的包装类。
四.基本数据类型对应的包装类:
五.以int型的包装类Integer为例:其他类似
1.获取Integer对象的方式(了解):
在JDK5以前,如果要获取包装类的对象,需要通过new一个构造方法,或者通过静态方法valueOf来获取:
对于valueOf方法:
1.形参包括字符串的:
2.形参为整数的:
上述图片中第1069行代码里的[]是数组的含义,所以cache表示一个数组,而且是Integer型。
形参为整型的valueOf方法:首先会对参数i进行判断,
如果参数i在if里的范围,就会执行if语句从cache数组中获取已经创建好的Integer对象并返回,
如果参数i不在if里的范围时才会new一个对象。
由此可以得出,如果传入的参数i符合if语句里的范围中,就不会自己new一个对象,而是从cache数组中获取一个Integer对象并返回。
对于if语句里的范围i >= IntegerCache.low && i <= IntegerCache.high,i是参数,IntegerCache是方法,low和high是IntegerCache里的变量,
if语句中的IntegerCache方法,包含变量low(值为-128)、变量high以及数组cache
->对于变量high,第1014行代码中有一块静态代码块,首先定义了一个变量h,值为127,然后在第1028行中把h的值即127赋值给了high,所以if语句里的范围是[-128,127]即byte类型的取值范围,
->因此传入的参数i如果在[-128,127]这个范围内,就会执行第1035行代码,其中首先会创建一个Integer类型的数组c,该数组的长度是size,size的值为 (high - low) + 1(在第1032行代码),加1是因为在[-128,127]之间还有一个0,加1是为了把0也计入,(high - low) + 1=(127-(-128))+1=(127+128)+1=255+1=256,所以有256个数据,数组c的长度也是256
->在第1038行还有一个遍历c数组for循环,循环体即第1039行代码中继续操作数组c,给数组c里的每一个值进行赋值,通过创建Integer对象赋值,传入j++,j的初始值是low即-128(第1037行代码)
->所以就是会把low创建一个Integer对象,放到数组c中(一开始j为-128,放到c数组的0索引,j++是先赋值再++,因此就是先把j的值赋给数组,再++进行下一轮的操作,所以一开始j以-128的值赋值给c数组的0索引,再++进行第二轮操作。所以-127给c数组的1索引,以此类推)
->综上所述,Integer类在底层首先会把[-128,127]之间的所有数据都创建好Integer对象 ,然后全部放到cache数组中,当使用参数为整型的valueOf方法获取到对象时,首先会判断参数是否在[-128,127]范围内,如果在,不会创建新的Integer对象,而是从cache数组中获取已经创建好的Integer对象并返回,只有不在[-128,127]范围内,才会new一个Integer对象。
代码演示:
package com.itheima.a03integerdemo;
public class A01_IntegerDemo1 {
public static void main(String[] args) {
//1.利用构造方法获取Integer的对象(JDK5以前的方式)
Integer i1=new Integer(1);
Integer i2=new Integer("1");
System.out.println(i1); //运行结果为1,i1就是整数对应的包装类
System.out.println(i2); //运行结果为1,i2就是整数对应的包装类
/*虽然利用构造方法获取Integer的对象在JDK5以及JDK5之后的版本中已废弃,
但是依旧能够在JDK5以及JDK5之后的版本中利用构造方法获取Integer的对象,
尽管此时idea会报编译时异常,但代码可以运行*/
/* -------------------------------------------------------------------------------------------------------------------------------------------------*/
//2.利用静态方法获取Integer的对象(JDK5以前的方式)
Integer i3 = Integer.valueOf(123); //表示此时获取的是一个包装类,包装类里记录的数据是整数123
Integer i4 = Integer.valueOf("123"); //表示此时获取的是一个包装类,包装类里记录的数据是字符串123
Integer i5 = Integer.valueOf("123",8); //表示此时获取的是一个包装类,包装类里记录的数据是字符串123,8代表前面的字符串123是8进制下的
System.out.println(i3); //运行结果为123
System.out.println(i4); //运行结果为123
System.out.println(i5); //运行结果为83,这里不是123,是因为i5已经指定了字符串123是在8进制下的数据,那么在打印时就会把123转化为8进制,再把结果以10进制输出打印,所以结果为83
/* -------------------------------------------------------------------------------------------------------------------------------------------------*/
//3.上述获取Integer对象的两种方式的区别(需要掌握)->以下的==号比的是地址值,如果结果为true,表示前后是同一个对象,如果结果为false,表示前后不是同一个对象
/*底层原理:
在实际开发中,-128到127之间的整数数据用的比较多,
如果每次使用-128到127之间的整数数据都是new一个对象,那么会浪费很多内存,
所以,Java会提前把-128到127之间的每一个整数数据都创建好对象,
如果要用到-128到127之间的整数数据就不会创建新的对象了,而是返回已经创建好的对象 */
Integer i6=Integer.valueOf(127);
Integer i7=Integer.valueOf(127);
System.out.println(i6==i7); //运行结果为true
/* 对于参数为整型的valueOf方法,
如果传入的参数范围在[-128,127]内,那么最终创建的对象就是同一个对象,地址值也就一样,
所以本例中传入127,最终表示同一个对象,地址值也就一样,因此运行结果为true */
Integer i8=Integer.valueOf(128);
Integer i9=Integer.valueOf(128);
System.out.println(i8==i9); //运行结果为false
/* 对于参数为整型的valueOf方法,
如果传入的参数范围在[-128,127]内,那么最终创建的对象就是同一个对象,地址值也就一样,
但本例中传入的是128,超出了[-128,127],因此最终表示不同的对象,地址值也就不一样,因此运行结果为false */
//new关键字:
Integer i10=new Integer(127);
Integer i11=new Integer(127);
System.out.println(i10==i11);
/* 运行结果为false,
原因:对于i10和i11,都使用了关键字new,
在Java中,每一次new都是创建了一个新的对象,所以i10和i11的地址值不一样,
又因为此时i10和i11都表示地址值,因此结果为false */
Integer i12=new Integer(128);
Integer i13=new Integer(128);
System.out.println(i12==i13);
/* 运行结果为false,
原因:对于i12和i13,都使用了关键字new,
在Java中,每一次new都是创建了一个新的对象,所以i12和i13的地址值不一样,
又因为此时i12和i13都表示地址值,因此结果为false */
}
}
2.Integer对象的计算:
代码演示:
package com.itheima.a03integerdemo;
public class A02_IntegerDemo2 {
public static void main(String[] args) {
//在以前包装类如何进行计算
Integer i1=new Integer(1);
Integer i2=new Integer(2);
//需求:需要把i1和i2两个数据进行相加得到结果3
/* 注:i1和i2此时都是包装类对象即引用数据类型,包装类对象之间是不能直接进行计算的,
如果想要进行计算,步骤如下:
1.把包装类对象进行拆箱,也就是把包装类对象变为基本数据类型
2.变为基本数据类型后就可以相加了
3.把得到的结果再次进行装箱(装箱的目的就是变回包装类对象) */
//intValue方法可以把Integer包装类对象进行拆箱为int型
int result = i1.intValue() + i2.intValue();
//把result进行装箱:new一个Integer对象,参数传入result,就可以把int型的result装箱为Integer包装类
Integer i3=new Integer(result);
System.out.println(i3); //运行结果为3
}
}
3.自动装箱和自动拆箱:
代码演示:
package com.itheima.a03integerdemo;
public class A03_IntegerDemo3 {
public static void main(String[] args) {
//在JDK5的时候提出了一个机制:自动装箱和自动拆箱
/* 自动装箱:把基本数据类型自动地变成其对应的包装类对象
自动拆箱:把包装类对象自动地变成其对象的基本数据类型 */
//在底层,int型还是会去自动调用静态方法valueOf进行自动装箱得到一个Integer对象,只不过这个操作不需要我们自己去实现了
//10是基本数据类型,但最终是Integer类,说明进行了自动装箱
Integer i1 = 10;
Integer i2 = new Integer(10);
//把i2进行自动拆箱,最终为int型
int i=i2;
//在JDK5以后,int和Integer可以看作是同一个东西,因为在底层可以自动转化。
/*---------------------------------------计算---------------------------------------*/
/* 有了自动装箱和自动拆箱的机制,
Integer类可以直接赋值整数(把int型整数自动装箱为Integer类),
然后可以直接计算(计算时会把Integer类自动拆箱为int型整数),
最终得出结果(得出的结果是把int型整数自动装箱得来的Integer类)*/
Integer a=1;
Integer b=2;
Integer c=a+b;
System.out.println(c); //运行结果为3
}
}
4.总结:
5.Integer类的成员方法:
-
上述图片中前三个得到进制的方法的返回值都是String型,而不是整型,原因:1.比如二进制可能有01010101,但如果是整型,整数中0是不能做开头的,这就出现了局限性;2.整型中long型和int型是有长度限制的,以int型为例,int型最多只能取到21个亿,也就是int类型最多只能有10位,而二进制可能有30多位、40多位和50多位,所以int型可能装不下,long型同理,只有String型可以,这也就是为什么返回String型
-
上述图片的四个方法都是静态的,因此都可以用类名.方法名进行调用
-
上述图片中前三个得到进制的方法常出现在源码中,如Object类里的toString方法,就用到了toHexString方法:意思是把对象的地址值转成十六进制的形式后进行返回
代码演示:
package com.itheima.a03integerdemo;
public class A04_IntegerDemo4 {
public static void main(String[] args) {
//1.把整数转成二进制
String str1 = Integer.toBinaryString(100);
System.out.println(str1); //运行结果为1100100
//2.把整数转成八进制
String str2 = Integer.toOctalString(100);
System.out.println(str2); //运行结果为144
//3.把整数转成十六进制
String str3 = Integer.toHexString(100);
System.out.println(str3); //运行结果为64
//4.将字符串类型的整数转成int类型的整数
/* Java是一种强类型语言:强类型语言指的是每种数据在Java中都有各自的数据类型,
在计算的时候,如果不是同一种数据类型,是无法直接计算的。
只有数据的类型相同时,才可以进行计算。
比如想让字符串"123"和整数123相加,此时想要得到的结果是246,
但字符串和数字进行计算时,是把数字拼接到字符串上,此时的结果为123123,
要想达到目的,就需要把字符串"123"变为整数才能和后面的数字123相加,
因此就需要把字符串"123"变为整数 */
int i = Integer.parseInt("123");
System.out.println(i); //运行结果为123
System.out.println(i+123); //运行结果为246
}
}
parseInt方法的细节演示:
public class Main2 {
public static void main(String[] args) {
//细节1:在类型转换的时候,括号中的参数只能是数字,不能是其他,否则代码会报错
//细节2:在8种包装类中,除了Character类外都有对应的parseXxx的方法,进行类型转换,转换为对应的基本数据类型
String str="true";
/*需求:把str的值的类型变为布尔类型*/
boolean b = Boolean.parseBoolean(str); //如果str是"true",结果为true,除此之外都是false
System.out.println(b); //运行结果为true
}
}
6.键盘录入改进:
package com.itheima.a03integerdemo;
import java.util.Scanner;
public class A05_IntegerDemo5 {
public static void main(String[] args) {
//键盘录入
Scanner sc=new Scanner(System.in);
/*弊端:
当我们在使用next、nextInt、nextDouble等接收数据的时候,如果遇到空格、回车、制表符的时候就会停止接收,
如果此时想要录入的是123 123,由于有一个空格,那么此时只能接收到空格前面的数据即123,显然少接收一部分。
平时写代码时,想要接收的是一整行的数据
->约定:以后想要键盘录入,无论什么类型,统一使用nextLine,nextLine方法会接收一整行的数据,把空格、制表符全部会接收,
nextLine方法遇到回车才停止,nextLine方法返回的是String型,
但如果要多次使用键盘录入,就不要使用nextLine方法了 */
System.out.println("请输入一个字符串");
String s = sc.nextLine(); //录入123 123
System.out.println(s); //运行结果为123 123
}
}
package com.itheima.a03integerdemo;
import java.util.Scanner;
public class A05_IntegerDemo5 {
public static void main(String[] args) {
//键盘录入
Scanner sc=new Scanner(System.in);
System.out.println("请输入一个字符串");
String line = sc.next();//录入123 123
System.out.println(line); //运行结果为123,因为next在接收时遇到空格、回车、制表符会停止接收,所以只接收到空格前的123
/*
//如果此时要求录入的结果是整型,只需要类型转换即可
int i = Integer.parseInt(line);
*/
//如果此时要求录入的结果是小数即浮点型,只需要类型转换即可
double v = Double.parseDouble(line);
System.out.println(v); //运行结果为123.0
System.out.println(v+1); //运行结果为124.0
}
}