Java基础——包装类

时间:2023-02-17 15:35:42

Java是面向对象的编程语言,但它也包含了8种基本数据类型。这8种数据类型不支持面向对象的编程机制,基本数据类型的数据也不具备“对象”的特性:没有成员变量、方法可以被调用。

这8种数据类型带来了一定的方便性,例如可以进行简单、有效的常规数据处理。但在某些时候,基本数据类型会有一些制约,例如所有引用类型变量都继承了Object类,都可以当成Object类型变量使用。但基本数据类型的变量就不可以。

为了解决8种基本数据类型的变量不能当成Object类型变量使用的问题,Java提供了包装类的概念,为8种基本数据类型分别定义了相应的引用类型,并称之为基本数据的包装类

基本数据 包装类
byte Byte
short Short
int Integer
long Long
char Character
float Float
double Double
boolean Boolean

除了int和char有点例外之外,其他基本数据类型对应的包装类都是将其首字母大写即可。

在JDK1.5以前,把基本数据类型变量变成包装类需要通过对应包装类的构造器来实现。

但是从JDK1.5之后这种繁琐就消除了,JDK1.5提供自动装箱(Autoboxing)和自动拆箱(AutoUnboxing)功能

所谓自动装箱,就是可以把一个基本类型变量直接赋给对应包装类变量,或者赋给Object变量(Object是所有类的父类,子类可以直接赋给父类变量);自动拆箱则相反,允许把包装类对象直接赋给一个对应的仅类型变变量

下面程序示范了自动装箱和自动拆箱的用法。

public class AutoBoxingUnboxing
{

public static void main(String[] args)
{
//直接把一个基本类型变量赋给Integer对象
Integer inObj = 5;
//直接把一个boolean类型变量赋给一个Object类型的变量
Object boolean = true;
//直接把一个Integer对象赋给int类型变量
int it = inObj;
if(boolObj instanceof Boolean)
{
//先把Object对象强制类型转换为Boolean类型
//再赋给boolean变量
boolean b = (Boolean)boolObj;
System.out.println(b);
}
}
}

除此之外,包装类还可实现基本类型变量和字符串之间的转换。

把字符串类型的值转换为基本类型的值有两种方式。

①利用包装类提供的parseXxx(String s)静态方法(除了Character之外所有包装类都提供了该方法)。

②利用包装类提供的Xxx(String s)构造器。

String类提供了多个重载valueOf()方法,用于将基本类型转换成字符串

public class Primitive2String
{
public static void main(String[] args)
{
String intStr = "123";
//把一个特定字符串转换成int变量
int it1 = Integer.parseInt(intStr);
int it2 = new Integer(intStr);
System.out.println(it2);
String floatStr = "4.56";
//把一个特定字符串转换成float变量
float ft1 = Float.parseFloat(floatStr);
float ft2 = Float.parseFloat(floatStr);
System.out.println(ft2);
//把一个float变量转换成String变量
String ftStr = String.valueOf(2.345f);
System.out.println(ftStr);
//把一个double变量转换成String变量
String dbStr = String.valueOf(3.344);
System.out.println(dbStr);
//把一个boolean变量转换成String变量
String boolStr = String.valueOf(true);
System.out.println(boolStr);
}
}

如果希望吧基本类型变量转换成字符串,还有一种更简单的方法:将基本类型变量和“”进行了连接运算,系统会自动把基本类型变量转换成字符串。例如如下代码:

//intStr的值为 "5"
String intStr = 5 + "";

注意:虽然包装类型的变量时引用数据类型,但包装类的实例可以与数值类型的值进行比较,这种比较时可以直接取出包装类实例所包装的数值来进行比较的。

例如:

Integer a = new Integer(6);
//输出true
System.out.println("6的包装类实例是否大于5.0" + (a > 5.0));

两个包装类实例比较就比较复杂,因为包装类的实例实际上是引用类型,只有两个包装类指向同一个对象时才会返回true。下面代码示范了这种效果。

System.out.println("比较两个包装类的实例是否相等:" 
+ (new Integer(2) == new Integer(2)));//输出false

但JDK1.5以后支持的自动装箱,自动装箱就是可以直接把一个基本类型值赋给一个包装类实例,在这种情况下可能会出现一些特别的情形。看如下代码:

//通过自动装箱,允许把基本类型值赋给包装类实例
Integer ina = 2;
Integer inb = 2;
System.out.println("两个2自动装箱后是否相等:" + (ina == ina));//输出true
Integer biga = 128;
Integer bigb = 128;
System.out.println("两个128自动装箱后是否相等:" + (biga == bigb));//输出false

为什么同样两个int类型,两个2自动装箱后就相等;但如果是两个128自动装箱后就不相等,这是为什么呢?
这与Java的Integer类的设计有关,查看Java系统中java.lang.Integer类的源代码,如下所示。

//定义一个长度为256的Integer数组
static final Integer[] cache = new Integer[-(-128)+127+1];
static{
//执行初始化,创建-128~127的实例,并放入cache数组中
for(int i = 0;i < cache.length;i++)
cache[i] = new Integer(i - 128);
}

从上面代码可以看出,系统把一个-128~127之间的整数自动装箱成Integer实例,并放入了一个名为cache的数组中缓存起来。如果以后把一个-128~127之间的整数自动装箱成一个Integer实例时,实例实际直接指向对应的数组元素,因此-128~127之间的同一个整数自动装箱成Integer实例时,永远是引用cache数组的同一个数组元素,所以它们全部都相等;但每次把一个不再-128~127范围内的整数自动装箱成Integer实例时,系统总是创建一个Integer实例,所以出现程序中的运行结果。