美文网首页Android开发Android开发经验谈
Android进阶–int和Integer的理解

Android进阶–int和Integer的理解

作者: 遛狗的程序员 | 来源:发表于2018-07-26 22:39 被阅读11次

    今天早高峰在地铁上突然有一个疑惑:String 是immutable是为了保证线程安全,Integer也是Immutable,为什么并发的时候建议使用AtomicInteger呢?

    晚上回来查阅相关资料得出总结:

    String a="test";
    String b="test";
    System.out.println(a==b);
    System.out.println(System.idntityHashCode(a));
    System.out.println(System.identityHashCode(b));
    
    输出:true
    851664923
    851664923
        
    //为什么有觉得可变呢?    
    String a="test";
    a="test1"
    

    a就变成了test1,其实在这里是新建了一个"test1"字符串对象(如果常量池没有这个值的话就是新建)。然后将变量引用指向它。注意:这里并没有修改"test"这个变量的内部状态,"test"这个字符串对象是线程安全的
    除非你用final修饰,否则所有的变量指向都是可变的。
    这种情况下要保证线程安全性:

    • 可以考虑使用volatile确保可见性。
    • 可以使用final修饰
    • 你可以使用AtomicReference之类的原子对象,对于Integer等也有AtomicInteger之类的
    • 对相应代码区域加锁

    有兴趣可以查看这两篇文章:
    String是线程安全的吗?那String岂不是不能进行同步?
    Java多线程系列--“JUC原子类”04之 AtomicReference原子类

    综上:String Immutable为了线程安全知识相对的(字符串常量值不可变),但是引用可变,所以为了并发的时候线程安全,可以使用上面所说的几种方案。(如果有更好的认识深度,欢迎讨论)有兴趣可以查看我之前写的一篇文章关于介绍:String为什么是final修饰的

    问题:

    • int和Integer有什么区别?谈谈Integer的值缓存范围?

    知识点

    1. Integer缓存或者String 常量池缓存用到的设计模式-享元模式。
    image

    相关代码(好记性不如烂笔头,代码是最好的理解):

    package yonghui.cn.firstthread.flyweight;
    
    /**
     * 作者:huangchen on 2018/7/26 20:57
     * 邮箱:huangchen@yonghui.cn
     */
    public interface IBike {
        void biliing(int  time);
    }
    
    package yonghui.cn.firstthread.flyweight;
    
    /**
     * 作者:huangchen on 2018/7/26 20:58
     * 邮箱:huangchen@yonghui.cn
     */
    public class ShareBike implements IBike {
        private int price;//单价
        private int total;//总价
    
        @Override
        public void biliing(int time) {
            System.out.println("total price is" + price * time);
        }
    }
    
    
    package yonghui.cn.firstthread.flyweight;
    
    import java.util.HashMap;
    
    /**
     * 作者:huangchen on 2018/7/26 20:11
     * 邮箱:huangchen@yonghui.cn
     */
    public class FlyWeightFactory {
        private HashMap<String, IBike> map = new HashMap<>();
    
        public IBike getIBike(String name) {
            IBike iBike;
            if (map.containsKey(name)) {
                System.out.println("押金已经交过了" + name);
                iBike = map.get(name);
                return iBike;
            } else {
                System.out.println("押金没有交,开始交押金299元");
                iBike = new ShareBike();
                map.put(name, iBike);
                return iBike;
            }
        }
    }
    
    
    package yonghui.cn.firstthread.flyweight;
    
    /**
     * 作者:huangchen on 2018/7/26 20:16
     * 邮箱:huangchen@yonghui.cn
     */
    public class Client {
        public void test(){
            FlyWeightFactory flyWeightFactory = new FlyWeightFactory();
            IBike ofo = flyWeightFactory.getIBike("ofo");
            ofo.biliing(2);
            IBike mobike = flyWeightFactory.getIBike("mobike");
            mobike.biliing(1);
            IBike ofo1 = flyWeightFactory.getIBike("ofo");
            ofo1.biliing(3);
        }
    }
    
    

    关于享元模式有兴趣可以参考:Android的设计模式-享元模式

    1. 自动装箱、自动拆箱发生在编译阶段。静态工厂方法valueof()使用了缓存机制,自动装箱的时候,缓存机制起作用。实际开发中,避免无意的装箱、拆箱行为(不管是内存使用还是运行速度、10w个Java对象比10w整数的开销要大得多,光是对象头空间占用已经是数量级的差距了)。
    2. 对象的内存结构:对象由对象头、对象实例、对齐填充三部分组成。具体有兴趣可以参考:Java对象内存布局

    回答问题:

    int是我们常说的整形,是八大基本数据类型之一,占4个字节,取值范围2的31次方减去1,Java需要号称一切都是对象,但是基本数据类型是个例外。

    Integer是int对应的包装类,他有一个int类型存字段(private final修饰,Immutable),并且提供了基本操作,比如数字运算、int和字符串之间的转换。在Java5中,引入了自动装箱、拆箱功能。Java根据上下文,自动进行转换,极大简化了相关编程。

    关于Integer的值缓存,这涉及Java5的内一个改进。大部分数据操作都集中在有限的、较小的数值范围,因而,在Java 5 中新增了静态工厂方法valueof,在调用它的时候会利用一个缓存机制,带来了明显的性能改进。按照Javadoc,这个值默认缓存-128-127之间。

    //Integer部分源码
    //Immutable private final
    /**
         * The value of the {@code Integer}.
         *
         * @serial
         */
        private final int value;
     /**
         * 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
         */
        public static Integer valueOf(int i) {
            assert IntegerCache.high >= 127;
            if (i >= IntegerCache.low && i <= IntegerCache.high)
                return IntegerCache.cache[i + (-IntegerCache.low)];
            return new Integer(i);
        }
    

    参考:

    声明:此为原创,转载请联系作者


    作者:微信公众号添加公众号-遛狗的程序员 ,或者可以扫描以下二维码关注相关技术文章。

    qrcode_for_gh_1ba0785324d6_430.jpg

    当然喜爱技术,乐于分享的你也可以可以添加作者微信号:

    WXCD.jpeg

    相关文章

      网友评论

        本文标题:Android进阶–int和Integer的理解

        本文链接:https://www.haomeiwen.com/subject/nbmimftx.html