• 关于int和Integer缓存(一):以及设计构想(享元模式)


    关于Integer的值缓存:
    在介绍Integer的值缓存之前,我们需要了解的是,java中的包装类型,
    我们都知道java中有包装类型
    int                     Integer   
    double             Double      
    char                 Character
    boolean           Boolean     

    ... 

    为什么要使用包装?

    包装类型源于java万物皆对象的思想
    1.因为基本类型不具备对象的特性,所以就出现了包装类型(想象如果没有包装类型,Collection等集合中,就不能存放基本类型,泛型的使用就出现了尴尬点咯)
    2.包装类提供的丰富的方法也简化和帮助我们完成了一些繁琐的操作(类型转化一系列parse操作)
    3.假设一个业务需求,其中涉及到对多个值进行判断,最常见检测初始化,如果是int 类型等等基础类型,例如:
    byte         0            
    short0            
    int         0            
    long         0L          
    float         0.0f        
    double0.0d       
    char         'u0000'
    booleanfalse      

    这个时候,包装类型就难得可贵了,包装类型的默认值都是null!



    但是为什么java不直接使用包装类型,同样保留了基础类型?

    因为一些小的变量,通过对象的形式存储在堆中,就很浪费空间,而且操作也
    没有那么高效了!

    所以java中有了包装和基本类型


    那么自动装箱和拆箱是怎么发生的呢?

    因为包装类本质是引用类型,对象本身不能像基础类型一样进行操作,

    例如:int、double、float的加减乘除(这里顺便一提,double有设计缺陷,进行减价乘除操作的时候,会出现精度错误和值错误的问题,需要使用:BigDecimal,请自行了解!)

     

    所以在进行加减操作,把Integer的值赋给int类型的变量的时候,就会出现自动拆箱;

    Integer n1 = new Integer(18);
    n1 += 10;  
    n1++; 
    n1--;
    int n2 = n1;
    Integer i = new Integer(100);
    int j = 100;
    System.out.print(i == j); // 这里也会自动拆箱



    在直接给Integer类型赋值时候(不通过new的方式进行赋值),就会出现自动装箱:

    Integer n1 = 999;

    首先我们做一个看似无关的测试,来巩固我们的思考:
    如下运行:

    Integer i = new Integer(100);
    Integer j = new Integer(100);
    System.out.print(i == j); //false
    
    
    Integer i = new Integer(100);
    int j = 100;
    System.out.print(i == j); //true
    
    
    Integer i = new Integer(100);
    Integer j = 100;
    System.out.print(i == j); //false





    通过上面的例子,我们一一分析:
    1.都是引用类型,对象比较堆空间中地址不同,肯定不相等!
    2.第二个 一个是int类型,一个是Integer类型,因为Integer对应的是int的包装类,所以在进行比较之前要进行一次拆箱。
    3.两个不同的Integer的声明方式一个是通过new对象的方式进行的,一个是通过直接赋值进行的,因为前一个肯定是引用类型,只要一边出现了引用类型,那肯定是不相等的!堆中地址不同。



    Integer i = 100;
    Integer j = 100;
    System.out.print(i == j); //true
    
    
    Integer i = 128;
    Integer j = 128;
    System.out.print(i == j); //false

    注意上面,为什么我这里写的是128就不行,100就可以呢


    解释,分析以下源码片段(Integer):

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

           其中在第一个方法中有一个high和low,并且明确讲了,只有在low和hgih之间的数字才会进入内部类IntegerCache,
    在IntergerCache中就做了一件事情:就是如果传入的数字是[-128, 127]之间数字,就直接存储进常量池中;如果不在这个范围内,就new Integer(xx)进行返回。
    所以其实我们的一句 Integer n1 = 128 其实是通过了Integer内部进行new操作自动装箱的!

    那为什么Integer要进行对-127到128之间的数据进行存入常量池中进行操作呢?
            这里就涉及到java的23中设计模式中的享元模式了:这里简单介绍一下享元模式[享元模式就是把一些常用的常量等
    共享出来,重复高效的去使用,以达到节约内存和提高效率的目的,JDK5.0之后的enum也是享元模式的一种体现
    ]






    学习参考,感谢:
    https://www.zhihu.com/question/22775729
    http://simon-c.iteye.com/blog/1016031
    https://baike.baidu.com/item/%E4%BA%AB%E5%85%83%E6%A8%A1%E5%BC%8F/10541959
    http://baijiahao.baidu.com/s?id=1584080745080984291&wfr=spider&for=pc
    https://www.jianshu.com/p/9bd18eae9a1a

    https://blog.csdn.net/chenliguan/article/details/53888018

  • 相关阅读:
    leetcode 86. Partition List
    leetcode 303. Range Sum Query
    leetcode 1310. XOR Queries of a Subarray
    leetcode 1309. Decrypt String from Alphabet to Integer Mapping
    leetcode 215. Kth Largest Element in an Array
    将numpy.ndarray写入excel
    leetcode 1021 Remove Outermost Parentheses
    leetcode 1306. Jump Game III
    leetcode 1305. All Elements in Two Binary Search Trees
    ICCV2019 oral:Wavelet Domain Style Transfer for an Effective Perception-distortion Tradeoff in Single Image Super-Resolution
  • 原文地址:https://www.cnblogs.com/mzywucai/p/11053408.html
Copyright © 2020-2023  润新知