广告
返回顶部
首页 > 资讯 > 后端开发 > Python >Java包装类的概述与应用
  • 566
分享到

Java包装类的概述与应用

2024-04-02 19:04:59 566人浏览 薄情痞子

Python 官方文档:入门教程 => 点击学习

摘要

目录一、包装类概述二、包装类的自动装箱、自动拆箱机制 三、包装类中的缓存机制四、包装类的四则运算、位运算、比较运算、逻辑运算1、四则运算和位运算2、比较运算和逻辑运算五、包

一、包装类概述

Java有8种基本数据类型:整型(byte、short、int、long)、浮点型(float、double)、布尔型boolean、字符型char,相对应地,Java提供了8种包装类Byte、Short、Integer、Long、Float、Double、Boolean、Character。包装类创建对象的方式就跟其他类一样。

Integer num = new Integer(0);    //创建一个数值为0的Integer对象

二、包装类的自动装箱、自动拆箱机制 

上面的构造对象语句实际上是基本数据类型向包装类的转换。在应用中我们经常需要进行基本类型数据和包装类对象之间的互转。

Integer num1 = new Integer(1);	//基本数据类型转为包装类
int num2 = num1.intValue();		//包装类型转为基本数据类型
System.out.println(num1 +"	"+ num2);

而Java为了方便我们使用,以及出于其他目的如性能调优,给我们提供了自动装箱、拆箱机制。这种机制简化了基本类型和包装类型的转换。

//1、包装类中的自动装箱拆箱机制
Integer  num1 = 1;		//自动装箱
int num2 = num1;		//自动拆箱
System.out.println(num1 +"	"+ num2);

当使用jad工具对上面的代码进行反编译时,结果如下。

Integer integer = Integer.valueOf(1);
int i = integer.intValue();
System.out.println((new StringBuilder()).append(integer).append("\t").append(i).toString());

可见,Java编译器帮我们完成了转换操作。另外,我们可以看到,除了使用new关键字,还可以使用Integer类的valueOf()方法创建一个Integer对象。这两个方式是有所区别的,我们下面会说到。

三、包装类中的缓存机制

前面说到创建包装类对象有两种方式:new关键字、valueOf()方法。我们来看一段代码感受一下它们的区别。

//2、包装类中的缓存机制
Integer num3 = 10;
Integer num4 = 10;
Integer num5 = new Integer(20);
Integer num6 = new Integer(20);
Integer num7 = 128;
Integer num8 = 128;
System.out.println((num3==num4) +"	"+ num3.equals(num4));
System.out.println((num5==num6) +"	"+ num5.equals(num6));
System.out.println((num7==num8) +"	"+ num7.equals(num8));

运行结果为

我们看下它的反编译代码

Integer integer = Integer.valueOf(10);
Integer integer1 = Integer.valueOf(10);
Integer integer2 = new Integer(20);
Integer integer3 = new Integer(20);
Integer integer4 = Integer.valueOf(128);
Integer integer5 = Integer.valueOf(128);
System.out.println((new StringBuilder()).append(integer == integer1).append("\t").append(integer.equals(integer1)).toString());
System.out.println((new StringBuilder()).append(integer2 == integer3).append("\t").append(integer2.equals(integer3)).toString());
System.out.println((new StringBuilder()).append(integer4 == integer5).append("\t").append(integer4.equals(integer5)).toString());

首先,我们查看Integer的valueOf()方法的源码

    public static Integer valueOf(int i) {
        if (i >= IntegerCache.low && i <= IntegerCache.high)
            return IntegerCache.cache[i + (-IntegerCache.low)];
        return new Integer(i);
    }

再查看下Integer的内部类IntegerCache的cache数组成员、low、high成员

        static final int low = -128;
        static final int high;
        static final Integer cache[];
 
        static {
            // high value may be configured by property
            int h = 127;
            String integerCacheHighPropValue =
                sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
            if (integerCacheHighPropValue != null) {
                try {
                    int i = parseInt(integerCacheHighPropValue);
                    i = Math.max(i, 127);
                    // Maximum array size is Integer.MAX_VALUE
                    h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
                } catch( NumberFORMatException nfe) {
                    // If the property cannot be parsed into an int, ignore it.
                }
            }
            high = h;
 
            cache = new Integer[(high - low) + 1];
            int j = low;
            for(int k = 0; k < cache.length; k++)
                cache[k] = new Integer(j++);
 
            // range [-128, 127] must be interned (JLS7 5.1.7)
            assert IntegerCache.high >= 127;
        }

可以发现,只要Integer类第一次被使用到,Integer的静态内部类就被加载,加载的时候会创建-128到127的Integer对象,同时创建一个数组cache来缓存这些对象。当使用valueOf()方法创建对象时,就直接返回已经缓存的对象,也就是说不会再新建对象;当使用new关键字or使用valueOf()方法创建小于-128大于127的值对象时,就会创建新对象。

//2、包装类中的缓存机制
Integer num3 = 10;
Integer num4 = 10;
Integer num5 = new Integer(20);
Integer num6 = new Integer(20);
Integer num7 = 128;
Integer num8 = 128;

由于num3、num4都小于等于127,它们指向的是同一个缓存的Integer对象,所以用==进行比较的结果是true;num5、num6由于使用new关键字指向的是两个不同的新对象,结果为false;num7、num8虽然是采用自动装箱的方式,但执行valueOf()方法的时候,由于不满足条件i >= IntegerCache.low && i <= IntegerCache.high,而同样新建了两个不同的新对象,结果同样是false。

接着,我们再来看看源码中Integer的equals()方法的实现

    public boolean equals(Object obj) {
        if (obj instanceof Integer) {
            return value == ((Integer)obj).intValue();
        }
        return false;
    }

可见equals()方法比较的是Integer对象的值,而不是像==一样比较的是对象是否是同一个对象。所以,当需要比较两个Integer对象的值是否相等时,记住要用equals()方法。用==比较的话由于缓存机制的存在,可能产生一些让人困扰的结果。

此外,在8种包装类型中,有缓存区的有Character、Byte、Short、Integer、Long,而且它们的实现方式基本一样,都是-128到127的缓存范围。Boolean虽然没有缓存区,但是因为只有两个值true、false,所以Boolean在成员变量中就创建了两个相应的对象。没有缓存区的只有Float、Double,之所以没有原因很简单,即便是0到1这么小的范围,浮点数也有无数个,使用缓存区缓存它们不具备可能性和实用性。

缓存区的存在使得常用的包装类对象可以得到复用,这有利于提升性能。当我们需要创建新对象的时候再new一个,增加了灵活性。

四、包装类的四则运算、位运算、比较运算、逻辑运算

1、四则运算和位运算

//四则运算、位运算
Integer num9 = 1;
Integer num10 = 2;
Integer num11 = num9 + num10; 
Short num12 = 5;
Integer num13 = num9 + num12;
Long num14 = num9 + 10L;
System.out.println(num9 << 1);	//位运算
System.out.println(num9 +"	"+ num10 +"	"+ num11 +"	"+ num12 +"	"+ num13 +"	"+ num14);

反编译结果如下

        Integer integer = Integer.valueOf(1);
        Integer integer1 = Integer.valueOf(2);
        Integer integer2 = Integer.valueOf(integer.intValue() + integer1.intValue());
        Short short1 = Short.valueOf((short)5);
        Integer integer3 = Integer.valueOf(integer.intValue() + short1.shortValue());
        Long long1 = Long.valueOf((long)integer.intValue() + 10L);
        System.out.println(integer.intValue() << 1);
        System.out.println((new StringBuilder()).append(integer).append("\t").append(integer1).append("\t").append(integer2).append("\t").append(short1).append("\t").append(integer3).append("\t").append(long1).toString());

可以看到Integer num11 = num9 + num10; 这一句被划分为3个步骤:将两个Integer对象分别进行拆箱;将拆箱得到的两个int数值相加求其和;将和值进行装箱,从而将num11指向缓存数组中值为3的Integer对象。

而Short num12 = 5; 这一句则先将5强制转换成short类型,再将其装箱把值为5的Short对象的引用赋给num12。

而Integer num13 = num9 + num12; 这一句除了Integer num11 = num9 + num10;的3个步骤,中间还有short+int=int的类型自动提升的过程。

而Long num14 = num9 + 10L; 这一句Integer num11 = num9 + num10;的3个步骤,中间还有强制类型转换的过程。需要注意的是,如果是Long num14 = num9 + num10; 的话就会出现类型不匹配的错误,因为num9、num10拆箱之后相加的和是int类型,而Long.valueOf(long)需要的形参是long类型,自然会出错。我们也可以看到,当包装类型对象和基本类型数据进行四则运算的时候,对象是会被拆箱的,然后再按基本类型数据的运算规则进行运算。

另外,如果仅仅是打印两个包装类型对象求和的结果,是不会有将和值重新转换成该包装类型的步骤的,如下面所示

System.out.println(num9 + num10);
System.out.println(integer.intValue() + integer1.intValue());

这里还需要注意一点,尽管基本类型与自动类型提升/强制类型转换,包装类是没有类似的用法的。下面的做法是错的。

Short num3 = 10;
Integer num4 = num3;	//错误: 不兼容的类型: Short无法转换为Integer
Long num5 = (Long)num4;	//错误: 不兼容的类型: Integer无法转换为Long
Double num6 = num5;	//错误: 不兼容的类型: Long无法转换为Double

小结:不同包装类型对象是不能直接转换的,不过有两种途径可以代替:一种是上面讨论的不同包装类对象进行四则运算后赋给某一种类型;另一种就是利用包装类的方法

Integer a = 20;
Long b = a.longValue();
Short c = b.shortValue();
System.out.println(a +"	"+ b +"	"+ c);

2、比较运算和逻辑运算

Integer num9 = 100;
Integer num10 = 200;
Short num11 = 50;
Long num12 = 50L;
System.out.println((num9<num10) +"	"+ (num9<200) +"	"+ (num9<num11) +"	"+ (num9<num12) +"	"+ (num9<10L));

反编译结果为

Integer integer = Integer.valueOf(100);
Integer integer1 = Integer.valueOf(200);
Short short1 = Short.valueOf((short)50);
Long long1 = Long.valueOf(50L);
System.out.println((new StringBuilder()).append(integer.intValue() < integer1.intValue()).append("\t").append(integer.intValue() < 200).append("\t").append(integer.intValue() < short1.shortValue()).append("\t").append((long)integer.intValue() < long1.longValue()).append("\t").append((long)integer.intValue() < 10L).toString());

可以看到,两个同类型的包装类对象进行比较时比较的其实是各自的基本类型数值,如num9 < num10;两个不同类型的包装类对象进行比较时则在比较基本类型数值之前,会有类型提升or强制类型转换,如num9 < num11,num9 < num12。

当想比较两个对象是否相等时,注意要使用equals()方法,从前面的讨论也知道,使用==的话比较的其实是引用的对象是否同一个,一般不满足我们的需求。

Integer num13 = new Integer(100);
System.out.println(num9.equals(num13) +"	"+ num9.equals(50));

反编译结果为

Integer integer2 = new Integer(100);
System.out.println((new StringBuilder()).append(integer.equals(integer2)).append("\t").append(integer.equals(Integer.valueOf(50))).toString());

逻辑运算举例:

System.out.println((num9&1));

反编译结果为

System.out.println(integer.intValue() & 1);

五、包装类作为方法的形参、返回值

//包装类作为方法的形参、返回值
	public static Integer intToInteger(int i) {
		return i;
	}  
	public static int integerToInt(Integer i) {
		return i;
	}

反编译结果为

    public static Integer intToInteger(int i)
    {
        return Integer.valueOf(i);
    }
 
    public static int integerToInt(Integer integer)
    {
        return integer.intValue();
    }

六、包装类作为集合的元素

//包装类作为集合元素
List list = new ArrayList();
list.add(1);
list.add(new Object());
Iterator it = list.iterator();
while (it.hasNext()) {
	System.out.println(it.next());
}

反编译结果为

ArrayList arraylist = new ArrayList();
arraylist.add(Integer.valueOf(1));
arraylist.add(new Object());
for(Iterator iterator = arraylist.iterator(); iterator.hasNext(); System.out.println(iterator.next()));

可以发现,虽然集合元素要求是对象,add()方法的形参也是对象(public boolean add(E e)),但由于自动装箱,基本数据类型也可以直接加入集合中。

                List<Integer> list = new ArrayList<>();
		for (int i=0; i<5; i++) {
			list.add(i);
		}
		Iterator it = list.iterator();
		while (it.hasNext()) {
			System.out.println(it.next());
		}

反编译结果为

        ArrayList arraylist = new ArrayList();
        for(int i = 0; i < 5; i++)
            arraylist.add(Integer.valueOf(i));
 
        for(Iterator iterator = arraylist.iterator(); iterator.hasNext(); System.out.println(iterator.next()));

七、包装类使用过程中有可能引起的空指针异常

//注意包装类可能产生的空引用异常
		Boolean flag1 = false;
		System.out.println(flag1?"命题为真":"命题为假");
		Boolean flag2 = null;
		System.out.println(flag2?"命题为真":"命题为假");
		Boolean flag3 = true;

运行结果为

这里只是简单演示空指针异常。平时使用时需要注意这一点,比如当Boolean的对象作为形参时,在方法执行体的头部需要做下null检测。

上述代码的反编译结果为

        Boolean boolean1 = Boolean.valueOf(false);
        System.out.println(boolean1.booleanValue() ? "\u547D\u9898\u4E3A\u771F" : "\u547D\u9898\u4E3A\u5047");
        Boolean boolean2 = null;
        System.out.println(boolean2.booleanValue() ? "\u547D\u9898\u4E3A\u771F" : "\u547D\u9898\u4E3A\u5047");
        Boolean boolean3 = Boolean.valueOf(true);

可见三目运算符的条件表达式的位置一定是boolean值,如果你传入的是Boolean对象,则会自动拆箱转换为boolean值。

另外,三目运算符的其他两个表达式位置也是如此,会把包装类对象转换为相应的基本类型对象。

八、为什么需要包装类?有了包装类又为什么要保留基本数据类型?(包装类的优缺点)

为什么需要包装类?

首先,Java语言是一个面向对象的语言,但是Java中的基本数据类型却是不面向对象的,将每个基本数据类型设计一个对应的类进行代表,这种方式增强了Java面向对象的性质。

其次,如果仅仅有基本数据类型,那么在实际使用时将存在很多的不便,很多地方都需要使用对象而不是基本数据类型。比如,在集合类中,我们是无法将int 、double等类型放进去的,因为集合的容器要求元素是Object类型。而包装类型的存在使得向集合中传入数值成为可能,包装类的存在弥补了基本数据类型的不足。

此外,包装类还为基本类型添加了属性和方法,丰富了基本类型的操作。如当我们想知道int取值范围的最小值,我们需要通过运算,如下面所示,但是有了包装类,我们可以直接使用Integer.MAX_VALUE即可。

//求int的最大值
int max = 0;
int flag = 1;
for (int i=0; i<31; i++) {
	max += flag;
	flag = flag << 1;
}
System.out.println(max +"	"+ Integer.MAX_VALUE); //2147483647      2147483647

为什么要保留基本数据类型?

我们都知道在Java语言中,用new关键字创建的对象是存储在堆里的,我们通过栈中的引用来使用这些对象,所以,对象本身来说是比较消耗资源的。对于经常用到的类型,如int等,如果我们每次使用这种变量的时候都需要new一个对象的话,就会比较笨重了。所以,Java提供了基本数据类型,这种数据的变量不需要使用new在堆上创建,而是直接在栈内存中存储,因此会更加高效。

到此这篇关于Java包装类的文章就介绍到这了,更多相关Java包装类内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: Java包装类的概述与应用

本文链接: https://www.lsjlt.com/news/145141.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • Java包装类的概述与应用
    目录一、包装类概述二、包装类的自动装箱、自动拆箱机制 三、包装类中的缓存机制四、包装类的四则运算、位运算、比较运算、逻辑运算1、四则运算和位运算2、比较运算和逻辑运算五、包...
    99+
    2022-11-13
  • Java基础学习之ArrayList类概述与常用方法
    目录一、ArrayList类概述二、ArrayList类常用方法三、ArrayList存储字符串并遍历四、ArrayList存储学生对象并遍历五、ArrayList存储学生对象并遍历...
    99+
    2022-11-13
  • 分析概述IPv6与IPv4的应用与区别
    网购、网游、网聊、网络直播、网上… 这个年代要是没有了这张“网” 我们的生活几乎无法运行 你有想过网络互通如何实现的吗? 虚拟世界如何确定网上的...
    99+
    2022-11-12
  • Java包装类怎么应用
    这篇文章主要介绍“Java包装类怎么应用”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“Java包装类怎么应用”文章能帮助大家解决问题。一、包装类概述Java有8种基本数据类型:整型(byte、sho...
    99+
    2023-06-29
  • Java File类的概述及常用方法使用详解
    目录一、File类的概述和构造方法二、File类创建功能三、File类创建和获取功能四、File类的删除功能一、File类的概述和构造方法 public class File ext...
    99+
    2022-11-13
  • Java如何使用与操作包装类
    这篇文章主要介绍了Java如何使用与操作包装类,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。包装类何为包装类?基本类型包装类的概述: 将基本数据类型封装成对象的好处在于可以在...
    99+
    2023-06-29
  • C++深入讲解类与封装的概念与使用
    目录一、类的组合二、类的封装三、类成员的作用域四、小结一、类的组合 电脑一般而言是由 CPU,内存,主板,键盘和硬盘等部件组合而成。 二、类的封装 类通常分为以下两个部分 类的实现...
    99+
    2022-11-13
  • Python闭包的概念、形式与应用方式
    本篇内容主要讲解“Python闭包的概念、形式与应用方式”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Python闭包的概念、形式与应用方式”吧!闭包(Closure)是词法闭包(Lexical...
    99+
    2023-06-17
  • Java面向对象之包装类的用途与实际使用
    目录一、什么是包装类二、包装类的用途三、包装类的实际使用(以int和integer为例)1.int和integer类之间的转换2、Integer类内部的常用方法四、常见的面试题1.J...
    99+
    2022-11-13
  • JAVA基本类型包装类 BigDecimal BigInteger 的使用
    目录1、了解包装类2、Integer3、Double4、BigDecimal5、BigInteger1、了解包装类 Java 中预定义了八种基本数据类型,包括:byte,int,lo...
    99+
    2022-11-12
  • Java中包装类Integer的使用方法
    这篇文章主要介绍Java中包装类Integer的使用方法,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!一、Java中为什么引入包装类?在Java中,很多类的方法都需要接受引用类型的对象,此时就无法将一个基本数据类型的...
    99+
    2023-06-15
  • 详解Java中包装类Integer的使用
    目录一、Java中为什么引入包装类?二、基本数据类型对应的包装类三、Integer类和int的区别四、Integer类的常用方法五、代码如下六、输出一、Java中为什么引入包装类? ...
    99+
    2022-11-12
  • Java虚拟机类装载:原理、实现与应用
    Java虚拟机类装载:原理、实现与应用[@more@]  一、引言   Java虚拟机(JVM)的类装载就是指将包含在类文件中的字节码装载到JVM中, 并使其成为JVM一部分的过程。JVM的类动态装载技术能够在运行时刻动态地加载或者替换系统...
    99+
    2023-06-03
  • Java 数据结构之堆的概念与应用
    目录什么是堆堆的类型小根堆大根堆堆的基本操作:创建堆堆的时间复杂度和空间复杂度堆的应用-优先级队列概念优先级队列基本操作入优先级队列出优先级队列首元素java的优先级队列堆的常见面试...
    99+
    2022-11-12
  • Bottle框架中的装饰器类和描述符应用详解
    最近在阅读Python微型Web框架Bottle的源码,发现了Bottle中有一个既是装饰器类又是描述符的有趣实现。刚好这两个点是Python比较的难理解,又混合在一起,让代码有些晦涩难懂。但理解代码之后不...
    99+
    2022-06-05
    详解 框架 Bottle
  • C++类与封装的概念是什么及怎么使用
    这篇文章主要介绍“C++类与封装的概念是什么及怎么使用”,在日常操作中,相信很多人在C++类与封装的概念是什么及怎么使用问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”C++类与封装的概念是什么及怎么使用”的疑...
    99+
    2023-06-30
  • 【Java基础教程】(三十二)常用类库篇 · 第二讲:包装类 Wrapper Class——概念及用途, 自动装箱与拆箱,常用操作方法~
    Java基础教程之常用类库 · 包装类 1️⃣ 概念2️⃣ 设计目的(作用)和用途3️⃣ 使用3.1 自动装箱与拆箱3.2 常用方法3.3 常用属性3.4 null和默认值 4️⃣ 注意事项🌾 总结Ὅ...
    99+
    2023-08-17
    java jvm 开发语言 经验分享 java-ee 面试 后端
  • java基础之包装类的介绍及使用
    1. 包装类的介绍 针对八种基本数据类型定义相应的引用类型--包装类(封装类),有了类的热点后,就可以调用类中的方法 2. 基本数据类型 --> 包装类:调用包装类的构造器,...
    99+
    2022-11-12
  • Java并发包工具类CountDownLatch的应用详解
    目录1.CountDownLatch的源码解读2.CountDownLatch的原理解析3.CountDownLatch的应用场景4.总结CountDownLatch是Java并发包...
    99+
    2023-05-18
    Java工具类CountDownLatch应用 Java工具类CountDownLatch Java CountDownLatch
  • Java开发中容器概念、分类与用法的示例分析
    这篇文章将为大家详细讲解有关Java开发中容器概念、分类与用法的示例分析,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。1、容器的概念在Java当中,如果有一个类专门用来存放其它类的对象,这个类就叫做容器,...
    99+
    2023-05-30
    java
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作