java包装类
java包装类
- 基本类型不是类,不能产生对象,所以,它既没有属性也没有方法。那么如果我们要对其进行一些特殊操作,如
将基本数据类型存储到Object[]数组或集合中的操作等
,要怎么做?- 概述:可以将基本数据类型转换成对象的类就是包装类
- 我们都知道,基本数据类型是不能存储到对象数组中的,为了解决这个不足,Java在设计类时为每个基本数据类型设计了一个对应的类进行代表,这样八个和基本数据类型对应的类统称为包装类(Wrapper Class)。
- 好处:将基本数据类型封装成对象的好处在于可以在对象中定义更多的功能方法操作该数据。
- 常用的操作之一:用于基本数据类型与字符串之间的转换
一、基本数据类型对应的包装类
基本类型 | 包装类 |
---|---|
byte | Byte |
short | Short |
int | Integer |
long | Long |
float | Float |
double | Double |
char | Character |
boolean | Boolean |
可以看到,基本数据类型除了
int(Integer)
和char(Character)
这两种以外,其他的都是将首字母改成大写即可
二、装箱与拆箱
基本类型与对应的包装类对象之间,来回转换的过程称为”装箱“与”拆箱“:
- 装箱:从基本类型转换为对应的包装类对象。
- 拆箱:从包装类对象转换为对应的基本类型。
八种包装类提供不同类型间的转换方式。
Number父类中提供的6个共性方法。
- parseXXX()静态方法(除了Character)。
- valueOf()静态方法。
注意:需保证类型兼容,否则抛出NumberFormatException异常。
演示:
基本数值---->包装对象
Integer i = new Integer(4);//使用构造函数进行封装
Integer iii = Integer.valueOf(4);//使用包装类中的valueOf方法
包装对象---->基本数值
int num = i.intValue();
一)自动装箱与自动拆箱
JDK 5.0之后,自动装箱、拆箱。基本数据类型和包装类自动转换。
自动装箱:编译器自动调用valueOf方法,把基本数据类型包装成包装类
自动拆箱:编译器自动调用XXvalue方法转换成基本数据类型
字符串与包装类之间的转换需要手动调用valueOf方法
Boolean b = Boolean.valueOf("zads"); String s = String.valueOf(b);
注意:在使用自动拆装箱时,如果Integer i = null,代码就会出现NullPointerException。建议先判断是否为null,然后再使用
还记得前面讲过,基本数据类型不能存储到对象数组中,但是看下面的代码你会疑惑明明放入的是基本数据类型,为什么编译器不报错?
public static void main(String[] args) {
Object[] o = {1};
}
通过打断点的方式可以看到,执行到Object[] o = {1};
这一语时,会调用Integet类的valueOf方法完成自动装箱
public static Integer valueOf(int i) { // 传入一个基本数据类型 int
/*
IntegerCache.low:-128
IntegerCache.high:127
1、首先判断传入的i是否位于 -128 ~ 127之间,如果在这范围内,则返回预先定义好的
IntegerCache.cache[]中对应的Integer对象
2、如果不在这个范围内,则调用Integer构造方法创建一个新的Integer对象
*/
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
由此可以知道,即使我们传入的是基本数据类型,在JDK1.5版本之后,也会有每个基本数据类型所对应的包装类进行自动的装箱操作,自动拆箱也是同样的道理:
/*
1、调用构造方法进行赋值
public Integer(int value) {
this.value = value;
}
*/
Integer integer = new Integer(200);
/*
2、自动调用Integer的inValue(),返回一个int类型数据,完成自动拆箱目的
public int intValue() {
return value;
}
*/
int i = integer;
或者:
Integer i = 4;//自动装箱。相当于Integer i = Integer.valueOf(4);
//等号右边:将i对象转成基本数值(自动拆箱) i.intValue() + 5;
//加法运算完成后,再次装箱,把基本数值转成对象。
i = i + 5;
二)整数缓冲区
- 为了提高效率和节省内存,针对-128到127之间的数据,Java做了一个数据缓冲池。
- 如果数据是该范围内的,会直接从缓冲池里获取数据,也就是说,每次赋值并不创建新的空间。
- 在实际应用当中,对已创建的对象进行复用。
Integer类型
在Integer类中有一个内部类
IntegerCache
,JVM在调用Integer的时候内部类IntegerCache
就创建了一个缓存数组static final Integer[] cache;
,cache数组的长度为256,其中IntegerCache.low = -128
和IntegerCache.high:127
代表cache存储的元素从-128到127的,即cache[-128,127]
,如果在这范围内,则返回预先定义好的 IntegerCache.cache[]中对应的Integer对象,如果不在这个范围内,则调用Integer构造方法创建一个新的Integer对象。又由于数组是引用类型,所以返回的是数组首地址,只是所在数组下标不同而已,这代表了只要不是使用new
创建的对象且在-128~127
这个范围内的整数,只要字面值相等
,都是同一个对象
演示:
public static void main(String[] args) {
/**
* 使用new关键字创建了两个对象,一旦使用new关键字,则代表这是一个新的对象
*/
Integer integer = new Integer(100);
Integer integer2 = new Integer(100);
System.out.println(integer == integer2);//false
/**
* Integer integer3 = 100;与Integer integer5 = Integer.valueOf(100);其
* 实是一样的,前者是后者的缩写
*/
Integer integer3 = 100;
Integer integer4 = 100;
System.out.println(integer3 == integer4);//true
Integer integer5 = Integer.valueOf(100);
Integer integer6 = Integer.valueOf(100);
System.out.println(integer5 == integer6);//true
System.out.println(integer3 == integer6);//true
/**
* 虽然都是在缓冲数组的范围内,但是数字不相同,所以肯定不相等
*/
Integer integer7 = 100;
Integer integer8 = 101;
System.out.println(integer7 == integer8);//false
/**
* 超出了-128~127之间的范围,所以新创建一个对象
*/
Integer integer9 = 200;
Integer integer10 = 200;
System.out.println(integer9 == integer10);//false
/**
* 只要两者之间有基本数据类型,那比较的一定是两者的值
*/
Integer integer11 = 200;
int int12 = 200;
System.out.println(integer11 == int12);//ture
}
Byte类型
由于byte类型的取值范围就是
-128~127
,所以byte类型所有数据都是从cache数组中获取的,即除了new出来的对象之外,只要字面值相等,则判断为是同一个对象
public Byte(byte value) {
this.value = value;
}
public static Byte valueOf(byte b) {
final int offset = 128;
return ByteCache.cache[(int)b + offset];
}
示例:
Byte b = 127;
Byte b1 = 127;
System.out.println(b == b1);//true
Byte b4 = 105;
byte b5 = 105;
System.out.println(b4 == b5);//ture
// 注意:由于整数默认类型为int类型,所以不能直接在Byte构造方法中放入数字,需放入提前定义好的byte
Byte b6 = new Byte(b5);
Byte b7 = new Byte(b5);
System.out.println(b6 ==b7);//false
注意:由于整数默认类型为int类型,所以不能直接在Byte构造方法中放入数字,需放入提前定义好的byte
Short类型
public Short(short value) {
this.value = value;
}
public static Short valueOf(short s) {
final int offset = 128;
int sAsInt = s;
/*
1、首先判断传入的s是否位于 -128 ~ 127之间,如果在这范围内,则返回预先定义好的
ShortCache.cache[]中对应的Short对象
2、如果不在这个范围内,则调用Short构造方法创建一个新的Short对象
*/
if (sAsInt >= -128 && sAsInt <= 127) { // must cache
return ShortCache.cache[sAsInt + offset];
}
return new Short(s);
}
示例:
Short s = 128;
Short s1 = 128;
System.out.println(s == s1);//false
Short s2 = 127;
Short s3 = 127;
System.out.println(s2 == s3);//ture
Short s4 = 25105;
short s5 = 25105;
System.out.println(s4 == s5);//ture
// 注意:由于整数默认类型为int类型,所以不能直接在Short构造方法中放入数字,需放入提前定义好的short
Short s6 = new Short(s5);
Short s7 = new Short(s5);
System.out.println(s6 ==s7);//false
Long类型
public Long(long value) {
this.value = value;
}
public static Long valueOf(long l) {
final int offset = 128;
/*
1、首先判断传入的s是否位于 -128 ~ 127之间,如果在这范围内,则返回预先定义好的
LongCache.cache[]中对应的Long对象
2、如果不在这个范围内,则调用Long构造方法创建一个新的Long对象
*/
if (l >= -128 && l <= 127) { // will cache
return LongCache.cache[(int)l + offset];
}
return new Long(l);
}
示例:
Long l = 128L;
Long l1 = 128L;
System.out.println(l == l1);//false
Long l2 = 127L;
Long l3 = 127L;
System.out.println(l2 == l3);//ture
Long l4 = 25105L;
long l5 = 25105;
System.out.println(l4 == l5);//ture
Long l6 = new Long(l5);
Long l7 = new Long(l5);
System.out.println(l6 ==l7);//false
三)字符缓冲区
public Character(char value) {
this.value = value; // 根据构造方法给属性赋值
}
public static Character valueOf(char c) {
/*
用char类型对应的ASCII值作比较,如果数值在0~127之间,则从缓存数组中获取,
若超出范围则创建一个新从Character对象
*/
if (c <= 127) { // must cache
return CharacterCache.cache[(int)c];
}
return new Character(c);
}
示例:
Character c = 128;
Character c1 = 128;
System.out.println(c == c1);//false
Character c2 = 127;
Character c3 = 127;
System.out.println(c2 == c3);//ture
Character c4 = 1227;
char c5 = 1227;
System.out.println(c4 == c5);//ture
Character c6 = new Character('a');
Character c7 = new Character('a');
System.out.println(c6 == c7);//false
三、Java中 基本数据类型与包装类的比较
一)int 与 Integer.valueOf() 与 new Integer() 使用==比较
-
使用new生成的Integer变量永远不相等
因为new生成的是两个对象,其内存地址不同。
-
只要比较的双方有一个基本数据类型,且两者值相等,则为true
因为包装类Integer和基本数据类型int比较时,java会自动将Integer拆箱为int,然后进行比较,实际上就变为两个int变量的比较。
-
Integer.valueOf()变量和new Integer()生成的变量比较时,结果为false
因为Integer.valueOf()变量指向的是java常量池中的对象,而new Integer()生成的变量指向堆中新建的对象,两者在内存中的地址不同。
-
两个Integer.valueOf()生成的变量比较
两个Integer.valueOf()生成的Integer对象,进行比较时,如果两个变量的值在区间
-128到127
之间,则比较结果为true,如果两个变量的值不在此区间,则比较结果为false
因为java已经用cache[]数组对[-128~127]
之间的对象进行了缓存。
public static void main(String[] args) {
/**
* 使用new关键字创建了两个对象,一旦使用new关键字,则代表这是一个新的对象
*/
Integer integer = new Integer(100);
Integer integer2 = new Integer(100);
System.out.println(integer == integer2);//false
/**
* Integer integer3 = 100;与Integer integer5 = Integer.valueOf(100);其
* 实是一样的,前者是后者的缩写
*/
Integer integer3 = 100;
Integer integer4 = 100;
System.out.println(integer3 == integer4);//true
Integer integer5 = Integer.valueOf(100);
Integer integer6 = Integer.valueOf(100);
System.out.println(integer5 == integer6);//true
System.out.println(integer3 == integer6);//true
/**
* 超出了-128~127之间的范围,所以新创建一个对象
*/
Integer integer7 = 200;
Integer integer8 = 200;
System.out.println(integer7 == integer8);//false
/**
* 只要两者之间有基本数据类型,那比较的一定是两者的值
*/
Integer integer9 = 200;
int int10 = 200;
System.out.println(integer9 == int10);//ture
}
二)浮点型 使用 == 比较
由于浮点类型数据的包装类使用
valueOf()
方法时,是直接创建一个新的对象,并没有缓存区,所以怎么比都是false
,除非两者之间有基本类型,才会比较两者的值
三)整数型与浮点型混合使用==比较
1、包装类混合使用 == 比较
Character integer3 = 100;
Integer integer4 = 100;
System.out.println(integer3 == integer4); // 报错,不同类型对象不能使用 == 比较
2、基本类型与包装类混合使用 == 比较
int i = 1270;
Integer integer = 1270;
double d = 1270;
Double dou = 1270.0;
System.out.println(i == integer); // 有基本类型,比较数值,true
System.out.println(i == d); // 自动类型提升为double,true
System.out.println(i == dou); // 自动类型提升double,有基本类型,比较数值,true
System.out.println(d == dou); // 有基本类型,比较数值,true
System.out.println(d == integer); // 有基本类型,比较数值,integer自动拆箱为int类型,再类型提升为double,true
// System.out.println(integer == dou); // 报错
-
总结:
在涉及到对象的时候,尽量使用已根据需要进行重写的equals方法来比较值的大小,否则得到的结果可能有偏差
(注意:未重写的equals方法也是采用 == 比较的,所以用之前要按需重写,不过包装类的equals方法已经重写过了,无需我们再重写。需要重写equals方法的一种场景:自定义了一个类,然后要比较对象的属性值,这是就要对equals方法进行重写)
四、常用方法
一)Integer
方法 | 描述 |
---|---|
public Integer(String s); | 把String类型的数据转换为Integer类型 注意:这个字符串必须由数字字符组成 |
public static int parseInt(String s); | 将字符串参数作为有符号的十进制整数进行解析,返回得到对应的整数值 |
public static String toString(int i); | 将int类型的数据转换为字符串 |
public static Integer valueOf(String s); | 把String类型的数据转换为Integer类型 |
public static String toBinaryString(int i); | 以二进制无符号整数形式返回一个整数参数的字符串 |
public static String toOctalString(int i); | 以八进制无符号整数形式返回一个整数参数的字符串 |
public static String toHexString(int i); | 以十六进制无符号整数形式返回一个整数参数的字符串 |
public static String toString(int i, int radix); | 十进制转换为其它进制的字符串形式;radix参数指进制数; 注意:其他进制的范围为2-36,因为0-9和A-Z总共36个字符 |
public static int parseInt(String s, int radix); | 其它进制转换为十进制 参数s表示进制数的字符串形式,参数radix表示该字符串是什么进制数; 注意:这个字符串必须由相应进制的系数组成 |
二)Character
方法 | 描述 |
---|---|
public static boolean isUpperCase(char ch); | 判断字符是否为大写字符 |
public static boolean isLowerCase(char ch); | 判断字符是否为小写字符 |
public static boolean isDigit(char ch); | 判断字符是否为数字字符 |
public static char toUpperCase(char ch); | 把字符转换为大写字符 |
public static char toLowerCase(char ch); | 把字符转换为小写字符 |
其他类的方法大同小异,可以自行查看java API