0

0

Java包装类怎么应用

王林

王林

发布时间:2023-05-26 16:26:21

|

1099人浏览过

|

来源于亿速云

转载

    一、包装类概述

    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对象。这两个方式是有所区别的,我们下面会说到。

    立即学习Java免费学习笔记(深入)”;

    三、包装类中的缓存机制

    在前面提到的创建包装类对象的方法中,包括使用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));

    运行结果为

    Java包装类怎么应用

    我们看下它的反编译代码

    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

    接着,我们再来看看源码中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);

    Java包装类怎么应用

    反编译结果如下

            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()

    可以看到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

    反编译结果为

    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()

    中国工商网电子商务购物中心系统EMall
    中国工商网电子商务购物中心系统EMall

    完全公开源代码,并无任何许可限制 特别基于大型电子商务网站的系统开发 Microsoft SQL Server 2000后台数据库,充分应用了存储过程的巨大功效 基于类模块的扩展数据访问能力支持任何类型的大型数据库 加密用户登录信息(cookie) 易于安装的系统和应用功能 100%的asp.net的代码,没有COM,java或者其他的格式 完全基于MS建议的系统安全设计 最佳的应用程序,数据库

    下载

    可以看到,两个同类型的包装类对象进行比较时比较的其实是各自的基本类型数值,如num9

    当想比较两个对象是否相等时,注意要使用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 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;

    运行结果为

    Java包装类怎么应用

    这里只是简单演示空指针异常。平时使用时需要注意这一点,比如当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

    Java是一个通用术语,用于表示Java软件及其组件,包括“Java运行时环境 (JRE)”、“Java虚拟机 (JVM)”以及“插件”。php中文网还为大家带了Java相关下载资源、相关课程以及相关文章等内容,供大家免费下载使用。

    832

    2023.06.15

    java正则表达式语法
    java正则表达式语法

    java正则表达式语法是一种模式匹配工具,它非常有用,可以在处理文本和字符串时快速地查找、替换、验证和提取特定的模式和数据。本专题提供java正则表达式语法的相关文章、下载和专题,供大家免费下载体验。

    737

    2023.07.05

    java自学难吗
    java自学难吗

    Java自学并不难。Java语言相对于其他一些编程语言而言,有着较为简洁和易读的语法,本专题为大家提供java自学难吗相关的文章,大家可以免费体验。

    734

    2023.07.31

    java配置jdk环境变量
    java配置jdk环境变量

    Java是一种广泛使用的高级编程语言,用于开发各种类型的应用程序。为了能够在计算机上正确运行和编译Java代码,需要正确配置Java Development Kit(JDK)环境变量。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

    397

    2023.08.01

    java保留两位小数
    java保留两位小数

    Java是一种广泛应用于编程领域的高级编程语言。在Java中,保留两位小数是指在进行数值计算或输出时,限制小数部分只有两位有效数字,并将多余的位数进行四舍五入或截取。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

    398

    2023.08.02

    java基本数据类型
    java基本数据类型

    java基本数据类型有:1、byte;2、short;3、int;4、long;5、float;6、double;7、char;8、boolean。本专题为大家提供java基本数据类型的相关的文章、下载、课程内容,供大家免费下载体验。

    446

    2023.08.02

    java有什么用
    java有什么用

    java可以开发应用程序、移动应用、Web应用、企业级应用、嵌入式系统等方面。本专题为大家提供java有什么用的相关的文章、下载、课程内容,供大家免费下载体验。

    430

    2023.08.02

    java在线网站
    java在线网站

    Java在线网站是指提供Java编程学习、实践和交流平台的网络服务。近年来,随着Java语言在软件开发领域的广泛应用,越来越多的人对Java编程感兴趣,并希望能够通过在线网站来学习和提高自己的Java编程技能。php中文网给大家带来了相关的视频、教程以及文章,欢迎大家前来学习阅读和下载。

    16925

    2023.08.03

    Java 桌面应用开发(JavaFX 实战)
    Java 桌面应用开发(JavaFX 实战)

    本专题系统讲解 Java 在桌面应用开发领域的实战应用,重点围绕 JavaFX 框架,涵盖界面布局、控件使用、事件处理、FXML、样式美化(CSS)、多线程与UI响应优化,以及桌面应用的打包与发布。通过完整示例项目,帮助学习者掌握 使用 Java 构建现代化、跨平台桌面应用程序的核心能力。

    36

    2026.01.14

    热门下载

    更多
    网站特效
    /
    网站源码
    /
    网站素材
    /
    前端模板

    精品课程

    更多
    相关推荐
    /
    热门推荐
    /
    最新课程
    Kotlin 教程
    Kotlin 教程

    共23课时 | 2.5万人学习

    C# 教程
    C# 教程

    共94课时 | 6.7万人学习

    Java 教程
    Java 教程

    共578课时 | 45.8万人学习

    关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
    php中文网:公益在线php培训,帮助PHP学习者快速成长!
    关注服务号 技术交流群
    PHP中文网订阅号
    每天精选资源文章推送

    Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号