不是吧!java中的包装类你还不知道?

1. 包装类概述

Java提供了两个类型系统,基本类型与引用类型 (包装类是一种引用类型,而基本数据类型是一种值类型),使用基本类型在于效率,然而很多情况,会创建对象使用,因为对象可以做更多的功能,如果想要我们的基本类型像对象一样操作,就可以使用基本类型对应的包装类。

Java中每一种基本类型都会对应一个唯一的包装类,基本类型与其包装类都可以通过包装类中的静态或者成员方法进行转换。每种基本类型及其包装类的对应关系如下,值得注意的是,所有的包装类都是final修饰的,也就是它们都是无法被继承和重写的。

小贴士:
包装类的继承关系:除了Boolean、Character类型直接继承object类,其他:Byte、Short、Integer、Long、Float、Double都是继承Object的子类Number。

在这里插入图片描述

2. 装箱与拆箱

基本类型与对应的包装类对象之间,来回转换的过程称为”装箱“与”拆箱“:

  • 装箱:从基本类型转换为对应的包装类对象。
  • 可以使用构造方法:
    • Integer(int value) : 构造一个新分配的Integer对象,它表示指定的int值
    • Integer(String s) :构造一个新分配的Integer对象,它表示String参数所指示的int值。

注意:传递的字符串,必须是基本类型的字符串,否则会抛出异常 “100” 正确, “a"抛出异常

  • 可以使用静态方法:

    • static Integer valueOf(int i):返回一个表示指定的int值的Integer实例
  • static Integer valueOf(Strings):返回保存指定的String的值的Integer对象。

  • 拆箱:从包装类对象转换为对应的基本类型。

    • 可以使用成员方法:

      • int intValue() 以int类型返回该 Integer的值

用Integer与 int为例:

基本数值---->包装对象

Integer i = new Integer(4);//使用构造函数函数
Integer iObj = Integer.valueOf(4);//使用包装类中的valueOf静态方法

包装对象---->基本数值

int num = i.intValue();

3. 自动装箱与自动拆箱

由于我们经常要做基本类型与包装类之间的转换,从Java 5(JDK 1.5)开始,基本类型与包装类的装箱、拆箱动作可以自动完成。例如:

Integer i = 4;//自动装箱。相当于Integer i = Integer.valueOf(4) / Integer i = new Integer(4);
i = i + 5;//等号右边:将i对象转成基本数值(自动拆箱) i.intValue() + 5;
//加法运算完成后,再次装箱,把基本数值转成对象。

分析:
从源代码的角度来看,基础类型和包装类型都可以通过赋值语法赋值给对应的变量类型,如下面的代码所示。

Integer i = 4;
int i = new Integer(4);

这种语法是可以通过编译的。但是,Java作为一种强类型的语言,对象直接赋值给引用类型变量,而基础数据只能赋值给基本类型变量,这个是毫无异议的。那么基本类型和包装类型为什么可以直接相互赋值呢?这其实是Java中的一种“语法糖”。“语法糖”是指计算机语言中添加的某种语法,这种语法对语言的功能并没有影响,但是更方便程序员使用。通常来说使用语法糖能够增加程序的可读性,从而减少程序代码出错的机会。换句话说,这其实是一种障眼法,那么实际上是怎么样的呢?下面是Integer i = 4;语句编译的字节码。

0: iconst_4
1: invokestatic #2 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
2: astore_4

首先,生成一个常量4,然后调用Integer.valueOf(int)方法返回Integer对象,最后将对象的地址(引用)赋值给变量i。Integer i = 4;其实相当于Integer i = Integer.valueOf(4);。

其他的包装类都是类似的,下表是所有包装类中的类型转换方法。
在这里插入图片描述

小贴士:

ArrayList集合无法直接存储整数,但是可以存储Integer包装类 比如: ArrayList list = new
ArrayList<>(); list.add(1); // --> 包含了自动装箱的过程,list.add(new
Integer(1)); int a = list.get(0); // --> 包含自动拆箱的过程,
list.get(0).intValue();

4. 基本类型与字符串之间的转换

基本类型转换为String

基本类型 --> String总共有三种方式:

1.基本类型的值 + “ ” 最简单的方法(常用)
2.包装类的静态方法toString(参数),不是Object类的toString()重载
static String toString(int i) 返回一个表示指定整数的 String对象
3.String类的静态方法valueOf(参数)
static String valueOf(int i) : 返回 int 参数的字符串表示形式

public class DemoInteger {
  public static void main(String[] args) {
    // 基本类型 -> 字符串(String)
    // 第一种方式
    int i1 = 201;
    String s1 = i1 + "";
    System.out.printIn(s1 + 314);   // 201314
    
    // 第二种方式 
    String s2 = Integer.toString(201);
    System.out.println(s2 + 314);     // 201314
    
    // 第三种方式
    String s3 = String.valueOf(201);
    System.out.println(s3 + 314);   // 201314
  }
}

String转换成对应的基本类型

除了Character类之外,其他所有包装类都具有parseXxx静态方法可以将字符串参数转换为对应的基本类型:

  • public static byte parseByte(String s):将字符串参数转换为对应的byte基本类型。
  • public static short parseShort(String s):将字符串参数转换为对应的short基本类型。
  • public static int parseInt(String s):将字符串参数转换为对应的int基本类型。
  • public static long parseLong(String s):将字符串参数转换为对应的long基本类型。
  • public static float parseFloat(String s):将字符串参数转换为对应的float基本类型。
  • public static double parseDouble(String s):将字符串参数转换为对应的double基本类型。
  • public static boolean parseBoolean(String s):将字符串参数转换为对应的boolean基本类型。

代码使用(以Integer类的静态方法parseXxx为例)如:

public class Demo18WrapperParse {
    public static void main(String[] args) {
        int num = Integer.parseInt("100");
    }
}

注意:如果字符串参数的内容无法正确转换为对应的基本类型,则会抛出java.lang.NumberFormatException异常。

5. 扩展

5.1. 空指针异常(NullPointException)

Integer a = null;
...
int b = a; // 抛出NullPointException

上面的代码可以编译通过,但是会抛出空指针异常(NullPointException)。前面已经说过了,int b = a实际上是int b = a.intValue(),由于a的引用值为null,在空对象上调用方法就会抛出NullPointException。

5.2. 两个包装类引用相等性

在Java中,“==”符号判断的内存地址所对应的值得相等性,具体来说,基本类型判断值是否相等,引用类型判断其指向的地址是否相等。看看下面的代码,两种类似的代码逻辑,但是得到截然不用的结果。

	Integer a1 = 1;
	Integer a2 = 1;
	System.out.println(a1 == a2); // true
	
	Integer b1 = 222;
	Integer b2 = 222;
	System.out.println(b1 == b2); // false

这个必须从源代码中才能找到答案。Integer类中的valueOf()方法的源代码如下:

	public static Integer valueOf(int i) {
	    if (i >= IntegerCache.low && i <= IntegerCache.high) // 判断实参是否在可缓存范围内,默认为[-128, 127]
	        return IntegerCache.cache[i + (-IntegerCache.low)]; // 如果在,则取出初始化的Integer对象
	    return new Integer(i); // 如果不在,则创建一个新的Integer对象
}

由于1属于[-128, 127]集合范围内,所有valueOf()每次都会取出同一个Integer对象, 故第一个“==” 判断结果为true;
但是222不属于这个集合范围,所以valueOf() 每次都会创建一个新的Integer对象,由于两个新创建的对象的地址不一样,所以第二个判断结果为false。

感谢你看到这里,我是程序员麦冬,一个java开发从业者,深耕行业六年了,每天都会分享java相关技术文章或行业资讯

欢迎大家关注和转发文章,后期还有福利赠送!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值