基本数据类型的包装类

基本数据类型的包装类

八种基本数据类型并不是对象,为了将基本类型数据和对象之间实现互相转化,Java为每一个基本数据类型提供了相应的包装类。


包装类基本知识

Java是面向对象的语言,但并不是“纯面向对象”的,因为我们经常用到的基本数据类型就不是对象。但是我们在实际应用中经常需要将基本数据转化成对象,以便于操作。比如:将基本数据类型存储到Object[ ]数组或集合中的操作等等。

为了解决这个不足,Java在设计类时为每个基本数据类型设计了一个对应的类进行代表,这样八个和基本数据类型对应的类统称为包装类(Wrapper Class)。

包装类位于java.lang包,八种包装类和基本数据类型的对应关系:


在这八个类名中,除了IntegerCharacter类以外,其它六个类的类名和基本数据类型一致,只是类名的第一个字母大写而已。


Number类是抽象类,因此它的抽象方法,所有子类都需要提供实现。Number类提供了抽象方法:intValue()longValue()floatValue()doubleValue(),意味着所有的“数字型”包装类都可以互相转型。
ps:根据源码可知,其实所有的“数字型”包装之间的互相转型不过是将数据做一个强制类型转换

包装类源码解读




自动装箱:

基本类型的数据处于需要对象的环境中时,会自动转为“对象”。

我们以Integer为例:

Integer i = 5

编译器会自动转成:Integer i = Integer.valueOf(5),这就是Java的自动装箱。
Integer i = 100;//自动装箱
//相当于编译器自动为您作以下的语法编译:
Integer i = Integer.valueOf(100);//调用的是valueOf(100),而不是new Integer(100)

自动拆箱:

每当需要一个值时,对象会自动转成基本数据类型,没必要再去显式调用intValue()、doubleValue()等转型方法。

Integer i = Integer.valueOf(5);

int j = i;

编译器会自动转成:int j = i.intValue();

这样的过程就是自动拆箱。

自动装箱/拆箱的本质是:

自动装箱与拆箱的功能是编译器来帮忙,编译器在编译时依据您所编写的语法,决定是否进行装箱或拆箱动作。
Integer i = 100;
int j = i;//自动拆箱
//相当于编译器自动为您作以下的语法编译:
int j = i.intValue();

自动装箱与拆箱的功能是所谓的“编译器蜜糖(Compiler Sugar)”,虽然使用这个功能很方便,但在程序运行阶段您得了解Java的语义。如下所示的程序是可以通过编译的:

【示例】包装类空指针异常问题

public class Test1 {
    public static void main(String[ ] args) {
        Integer i = null;
        int j = i;
    }
}

执行结果如图所示:

image-20220211104724482

运行结果之所以会出现空指针异常,是因为如上代码相当于:

public class Test1 {
    public static void main(String[ ] args) {
        /*示例8-5的代码在编译时期是合法的,但是在运行时期会有错误
因为其相当于下面两行代码*/
        Integer i = null; 
        int j = i.intValue();        
    }
}

包装类的缓存问题

整型、char类型所对应的包装类,在自动装箱时,对于-128~127之间的值会进行缓存处理,其目的是提高效率。

缓存原理为:如果数据在-128~127这个区间,那么在类加载时就已经为该区间的每个数值创建了对象,并将这256个对象存放到一个名为cache的数组中。每当自动装箱过程发生时(或者手动调用valueOf()时),就会先判断数据是否在该区间,如果在则直接获取数组中对应的包装类对象的引用,如果不在该区间,则会通过new调用包装类的构造方法来创建对象。
   private static class IntegerCache {
        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 =
                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;
        }

        private IntegerCache() {}
    }

    /**
     * Returns an {@code Integer} instance representing the specified
     * {@code int} value.  If a new {@code Integer} instance is not
     * required, this method should generally be used in preference to
     * the constructor {@link #Integer(int)}, as this method is likely
     * to yield significantly better space and time performance by
     * caching frequently requested values.
     *
     * This method will always cache values in the range -128 to 127,
     * inclusive, and may cache other values outside of this range.
     *
     * @param  i an {@code int} value.
     * @return an {@code Integer} instance representing {@code i}.
     * @since  1.5
     */
    @HotSpotIntrinsicCandidate
    public static Integer valueOf(int i) {
        if (i >= IntegerCache.low && i <= IntegerCache.high)
            return IntegerCache.cache[i + (-IntegerCache.low)];
        return new Integer(i);
    }


	

总结

  • 自动装箱调用的是valueOf()方法,而不是new Integer()方法。
  • 自动拆箱调用的xxxValue()方法。
  • 包装类在自动装箱时为了提高效率,对于-128~127之间的值会进行缓存处理。超过范围后,对象之间不能再使用==进行数值的比较,而是使用equals方法。
















#java基础知识#
全部评论
学习包装类基本知识
点赞 回复 分享
发布于 2022-10-22 15:53 河南

相关推荐

scsu12345:不局限语言感觉可以看 dify langchain
点赞 评论 收藏
分享
一面(1h):一面忘记录了,随便记了一点。感觉沟通不畅,不过还是过了。早上面试,晚上通知二面1.&nbsp;自我介绍2.&nbsp;项目的应用场景介绍3.&nbsp;Spring&nbsp;Boot&nbsp;和&nbsp;Spring&nbsp;Cloud用在哪些地方4.&nbsp;为什么要用&nbsp;Lua&nbsp;+&nbsp;Redis&nbsp;判断是否需要图形验证码5.&nbsp;对哪些库表进行分库分表6.&nbsp;为什么要用基因法改造7.&nbsp;为什么要用Es8.&nbsp;分片策略是什么9.&nbsp;Redisson封装多种分布式锁,怎么做的,用在哪里&nbsp;&nbsp;&nbsp;&nbsp;1.&nbsp;我这边创建了ServiceLocker的接口,然后用具体的实现类去实现这个接口。然后把对应的key和锁类型放到map的结构里,通过ManageLocker提供对外的服务,然后具体的锁里面是有redisson客户端的,通过这个客户端对传入的key进行获取。10.&nbsp;分布锁用在哪里&nbsp;&nbsp;&nbsp;&nbsp;1.&nbsp;可重入锁:在防止缓存穿透的时候会用到,使用了双重检测的方式防止请求达到数据库。&nbsp;&nbsp;&nbsp;&nbsp;2.&nbsp;读锁:对应票档的数据、座位数据存在redis如果不加锁,又有其他线程进行写入会有脏读。11.&nbsp;限流算法有哪些12.&nbsp;为什么要用令牌桶13.&nbsp;说说JUC14.&nbsp;说说JVM15.&nbsp;算法:翻转链表16.&nbsp;算法:股票(最基础的那题)17.&nbsp;反问:美团直播18.&nbsp;base:北京,上海二面:我的评价就是神,这leader我简直爱死,很真诚地在和我聊业务、技术栈的选择,还有以后的职业规划。1.&nbsp;算法:二叉树的最大路径和2.&nbsp;进程、线程、协程3.&nbsp;总结一下并发相关的和锁4.&nbsp;B+树和跳表5.&nbsp;SpringBoot和SpringCloud作用6.&nbsp;IOC和AOP7.&nbsp;SpringAOP和传统AOP有什么区别8.&nbsp;开始安利美团,聊人生9.&nbsp;反问业务二面是晚上面的,第二天下午oc。然后下周一腾讯发offer了,周二我让leader帮我跟进一下,半小时后offer,太爱了!
查看23道真题和解析
点赞 评论 收藏
分享
评论
1
1
分享

创作者周榜

更多
牛客网
牛客企业服务