零基础学习之 Java 包装类
说起Java包装类就不得不说Java的特性 – 面向对象。Java是Sun公司的程序 James Gosling ,Bill Joe本来打算试图修改和扩展C 的功能,新开发一个语言Oak的发展。 C语言 是一个面向过程的语言,改进后的Java是面向对象,这是一个非常大的改进,这也是Java发展至今依旧非常流行的原因。
但是,Java又不是完全的面向对象,它沿用了C语言的基本数据类型(这是为了便于开发者的使用,使得在进行基本的数据计算时,开发者可以直接使用基础类),但当需要和Java其他对象结合使用,如存入集合中,就需要将基础数据类型实例封装为Java对象,这样操作起来又比较麻烦了,为了满足面向对象的这一特性,Java的 java.lang 包中设置了包装类,使得每一个基本类型都有对应的包装类,这样直接就方便了开发者的使用。
简单理解来说:包装类就是为了使得Java中的基本数据类型具有面向对象的特性。
基本介绍
基本数据类型对应的包装类有8个(,根据其继承关系可以分成三类: char acter、Number、 boolean 。继承关系图如下:
这8个包装类和基本数据类型的对应关系如下表:
基本数据类型 | 包装类(java.lang包) |
Byte | Byte |
short | Short |
int | Integer |
long | Long |
float | Float |
double | Double |
char | Character |
boolean | Boolean |
包装类的使用
把基本类型变成包装类对象的过程称为装箱。
转为包装类的对象,是为了使用专门为对象设计的API和特性(比如 泛型 )
在JDK1.5之前,这个转化过程需要手动实现,即使用包装类的 构造器 来创建对象。(称为手动装箱);
在JDK1.15之后,这个转化过程可以自动实现,即直接赋值。(称为自动装箱)
代码示例
import org. junit .Test;//导入junit包,用来进行单元测试(比main方法好用,一个类可以创建多个程序入口) | |
public class Demo7 { | |
/** | |
* Integer(Byte,Double,Float,Long,Short类似) | |
*/ @Test | |
public void test1(){ | |
int i1 = 10; //定义基本数据类型(整型) | |
//基本数据类型转化成包装类 | |
//手动装箱(使用构造器) | |
Integer i2 = new Integer(i1); | |
Integer i3 = new Integer("11"); //也可以是字符类型,但是必须是数字,否则报错 | |
//自动装箱(直接赋值) | |
Integer i4 = i1; | |
//输出结果,测试验证 | |
System.out.println(i1); | |
System.out.println(i2); | |
System.out.println(i3); | |
System.out.println(i4); | |
} | |
/** | |
* Character | |
*/ @Test | |
public void test2(){ | |
char c1 = 'a'; //定义基本数据类型(字符型) | |
//基本数据类型转化成包装类 | |
//手动装箱(构造器) | |
Character c2 = new Character(c1); | |
//Character c3 = new Character("a"); 不能是字符,如果是字符就会分不清,本身就是了 | |
//自动装箱(直接赋值) | |
Character c4 = c1; | |
//输出结果,测试验证 | |
System.out.println(c1); | |
System.out.println(c2); | |
System.out.println(c4); | |
} | |
/** | |
* Boolean | |
*/ @Test | |
public void test3(){ | |
boolean b1=true; //定义基本数据类型(布尔型) | |
//基本数据类型转化成包装类 | |
//手动装箱 | |
Boolean b2=new Boolean(b1); | |
Boolean b3=new Boolean("true");//只要参数不是true这个 字符串 ,都返回false | |
if(b3) | |
System.out.println("b3=true"); | |
else | |
System.out.println("b3=false"); | |
//自动装箱(直接赋值) | |
Boolean b4=b1; | |
//输出结果,测试验证 | |
System.out.println(b1); | |
System.out.println(b2); | |
System.out.println(b4); | |
} | |
} |
与装箱相反,拆箱就是把包装类对象转化为基本类型的过程。
转为基本数据类型,一般是因为需要运算,Java中的大多数 运算符 是为基本数据类型设计的。比较、算术等,这样的效率更高
在JDK1.5之前,这个转化过程需要手动实现,即通过对应的包装类调用xxxValue()方法。(称为手动拆箱);
在JDK1.15之后,这个转化过程可以自动实现,即直接赋值。(称为自动拆箱)
代码示例
import org.junit.Test; | |
public class Demo7 { | |
/** | |
* Integer(Byte,Double,Float,Long,Short类似) | |
*/ @Test | |
public void test1(){ | |
int i1 = 10;//定义基本数据类型(整型) | |
//自动装箱,用于后面拆箱 | |
Integer i4 = i1; | |
//包装类转化为基本数据类型 | |
//手动拆箱(调用xxxValue()) | |
int i5 = i4.intValue(); | |
//自动拆箱(直接赋值) | |
int i6 = i4; | |
//输出结果,测试验证 | |
System.out.println(i1); | |
System.out.println(i4); | |
System.out.println(i5); | |
System.out.println(i6); | |
} | |
/** | |
* Character | |
*/ @Test | |
public void test2(){ | |
char c1 = 'a';//定义基本数据类型(字符型) | |
//自动装箱,用于后面拆箱 | |
Character c4 = c1; | |
//包装类转化为基本数据类型 | |
//手动拆箱 | |
char c5 = c4.charValue(); | |
//自动拆箱 | |
char c6 =c4; | |
//输出结果,测试验证 | |
System.out.println(c1); | |
System.out.println(c4); | |
System.out.println(c5); | |
System.out.println(c6); | |
} | |
/** | |
* Boolean | |
*/ @Test | |
public void test3(){ | |
boolean b1=true; //定义基本数据类型(布尔型) | |
//自动装箱,用于后面拆箱 | |
Boolean b4=b1; | |
//包装类转化为基本数据类型 | |
//手动拆箱 | |
boolean b5=b2.booleanValue(); | |
//自动拆箱 | |
boolean b6=b2; | |
//输出结果,测试验证 | |
System.out.println(b1); | |
System.out.println(b4); | |
System.out.println(b5); | |
System.out.println(b6); | |
} | |
} |
包装类常见的API
基本数据类型和字符串之间的转换
(1)把基本数据类型转为字符串(调用valueOf()方法)
import org.junit.Test; | |
public class Demo8 { | |
/** | |
* 基本数据类型转化为字符型 | |
*/ | |
public void test(){ | |
int a = 10; //定义基本数据类型 | |
//String str = a;//不能直接转换 | |
//方式一: | |
String str = a + ""; | |
//方式二: | |
String str1 = String.valueOf(a); | |
} | |
} |
(2)把字符串转为基本数据类型
String转换成对应的基本类型 ,除了Character类之外,其他所有包装类都具有parseXxx() 静态方法 可以将字符串参数转换为对应的基本类型:
public static byte parseByte(String s) | |
public static short parseShort(String s) | |
public static int parseInt(String s) | |
public static long parseLong(String s) | |
public static float parseFloat (String s) | |
public static double parseDouble(String s) | |
public static boolean parseBoolean(String s) | |
int a = Integer.parseInt("整数的字符串"); | |
double a = Double.parseDouble("小数的字符串"); | |
boolean b = Boolean.parseBoolean("true或false"); |
注意: 如果字符串参数的内容无法正确转换为对应的基本类型,
则会抛出 java.lang.NumberFormat Exception 异常。
数据类型的最大值和最小值
求某个数据类型的最大值和最小值,直接调用MAX_VALUE和MIN_VALUE方法
import org.junit.Test; | |
public class Demo8 { | |
/** | |
* Integer类型的最大值和最小值(其他类似) | |
*/ @Test | |
public void test1(){ | |
//最大值 | |
int maxValue = Integer.MAX_VALUE; | |
//最小值 | |
int minValue = Integer.MIN_VALUE; | |
//输出结果,验证测试 | |
System.out.println(maxValue); | |
System.out.println(minValue); | |
} | |
} |
转大小写
如果转包装类型的大小写,则需要调用 toUpperCase ()方法和toLowerCase()方法
import org.junit.Test; | |
public class Demo8 { | |
/** | |
* Character转大小写 | |
*/ | |
@Test | |
public void test2(){ | |
char x1 = Character.toUpperCase('x'); | |
char x2 = Character.toLowerCase('X'); | |
System.out.println(x1); | |
System.out.println(x2); | |
} | |
} |
如果转包装类型的 进制 ,则需要调用对应方法( 二进制 toBinaryString(),十六进制toHexString(),八进制toOctalString())
package com.atguigu.demo; | |
import org.junit.Test; | |
public class Demo8 { | |
/** | |
* 转进制 | |
*/ | |
public void test3(){ | |
int i = 6; //十进制的6 | |
String s1 = Integer.toBinaryString(i); //二进制 | |
String s2 = Integer.toHexString(i); //十六进制 | |
String s3 = Integer.toOctalString(i); // 八进制 | |
System.out.println(s1); | |
System.out.println(s2); | |
System.out.println(s3); | |
} | |
} |
包装类对象的缓存问题
有一部分包装类提供了对象的缓存。对于频繁使用的包装类对象,其类在初始化时就会提前创建好对象,当需要使用该包装类的对象时,如果该对象包装的值在缓存的范围内(这个范围是在Java源码中设置的),就返回缓存的对象;当该对象的值大于缓存的范围,就会创建新的对象并返回。
下面以Integer的源码进行说明
Integer i = 10; //自动装箱,默认会调用valueOf方法 | |
/** | |
* Integer的自动装箱源码 | |
*/ | |
public static Integer valueOf(int i) { | |
//判断i的值,是否在一个范围 -128 ~ 127 从数组中取值(地址) | |
if (i >= IntegerCache.low && i <= IntegerCache.high) | |
//如果值在这个范围,返回一个数组中的值 | |
return IntegerCache.cache[i + (-IntegerCache.low)]; | |
//如果不在这个范围,new一个(和自己new的对象没区别) | |
return new Integer(i); | |
} |
各个包装类对应的 缓存 对象大小如下表:
包装类 | 缓存对象 |
Byte | -128~127 |
Short | -128~127 |
Integer | -128~127 |
Long | -128~127 |
Float | 没有 |
Double | 没有 |
Character | 0~127 |
Boolean | true和false |
面试常考
包装类中“== ”与equals的用法比较,可以算是非常重要的考点了。
包装类中的equals方法和String类一样,都是重写了Object类中的equals方法,因此比较的是内容而不是地址,而“= =”比较的依然是引用变量的地址,只是当包装类型和与之相对应的基本类型进行“==”比较时会先做自动拆箱处理。具体可以分类如下:
- ①如果在默认范围内的自动装箱,则相等(比较地址)
- ②如果比较的对象有自己new的,则不相等(比较地址)
- ③如果比较的对象值不在范围内部也是不想等的(比较地址)
- ④如果有基本数据类型参与对比,包装类型就会自动拆箱,就会变成了基本数据类型的对比,
- 这个时候比的就是值了。
常见笔试或面试问题举例
import org.junit.Test; | |
public class Demo9 { | |
public void test(){ | |
Integer i1 = 10; //1. Integer这个类会加载 2. 在创建i2这个局部变量 | |
Integer i2 = 10; | |
System.out.println(i1 == i2); //true 对比地址 | |
Integer i3 = new Integer(10); | |
System.out.println(i1 == i3); //false 对比地址 | |
Integer i4 =300; | |
Integer i5 =300; | |
System.out.println(i4 == i5);//false 对比地址 | |
Integer i6 = 300; | |
int i7 = 300; | |
System.out.println(i6 == i7); //true 对比值(因为有基本数据类型(i6会转为int在对比) ) | |
} | |
} |