zoukankan      html  css  js  c++  java
  • Java基础之数据比较Integer、Short、int、short

    基础很重要,基础很重要,基础很重要。重要的事情说三遍,。

    今天聊一聊Java的数据比较,这个范围比较大,基础类型的比较、引用类型的比较。

    前提:

    1、Java和c#都提供自动装箱和自动拆箱操作,何为自动装箱,简单点说就是将值类型转换成为引用类型,自动拆箱就是将引用类型转换成为值类型。并且我们还经常被教导,要避免自动的装箱和拆箱操作,因为这个会影响性能。

    2、比较常用的运算符是==,equals。

    下面分几类来说明数据的比较,

    引用类型之间的比较:Integer与Integer之间的比较、Boolean与Boolean之间的比较、Integer与Boolean之间的比较

    值类型之间的比较:int与int之间的比较、int与bool之间的比较

    值类型与引用类型之间的比较:Integer与int之间的比较、Boolean与bool之间的比较

    开工

    引用类型之间的比较--Integer与Integer之间的比较

    简单说明一下,Integer是引用类型,代表的是整形数字

    上代码

     1 public static void main(String[] args) throws Exception {
     2          Integer integer = new Integer(0);
     3          Integer mInteger = Integer.valueOf(0);
     4          Integer sInteger = 0;
     5 
     6         System.out.println(integer == mInteger);//false
     7          System.out.println(integer == sInteger);//false
     8          System.out.println(mInteger == sInteger);//true
     9 
    10         System.out.println(memoryAddress(integer));
    11          System.out.println(memoryAddress(mInteger));
    12          System.out.println(memoryAddress(sInteger));
    13 
    14     }
    15 
    16     private static int memoryAddress(Object object) {
    17          // 内存地址会有所不同
    18          return System.identityHashCode(object);
    19      }

    执行结果:

    image

    分析:

    1、执行结果和我们预想的不太一样,引用类型是在堆上存放的,每个引用的地址应该都不相同。但是mInteger == sInteger  执行结果为true,并且mInteger ,sInteger的内存地址是相同的。

    2、要分析这个原因,我们需要了解Java设计者为了性能而进行的一些努力,查看Java源代码,可以看到Integer的valueof方法里面包含了一个缓存:其中IntegerCache.low =-127,IntegerCache.high=128

    1 @HotSpotIntrinsicCandidate
    2    public static Integer valueOf(int i) {
    3        if (i >= IntegerCache.low && i <= IntegerCache.high)
    4            return IntegerCache.cache[i + (-IntegerCache.low)];
    5        return new Integer(i);
    6    }

    对于使用Integer.valueof()方法,如果数值是-127至128,那么会使用缓存对象,否则会new一个对象。

    3、Integer sInteger = 0;   发生了什么呢?自动装箱,等价于Integer sInteger=Integer.valueOf(0)。通过这个,我们就可以得出比较等于true的原因了,都是从缓存中读取的对象,难怪内存地址会一致。

    引用类型比较--Integer与Integer引用类型比较   使用equals

    上代码:

     1 public static void main(String[] args) throws Exception {
     2          Integer integer = new Integer(0);
     3          Integer mInteger = Integer.valueOf(0);
     4          Integer sInteger = 0;
     5 
     6         System.out.println(integer == mInteger);// false
     7          System.out.println(integer == sInteger);// false
     8          System.out.println(mInteger == sInteger);// true
     9 
    10         System.out.println(memoryAddress(integer));
    11          System.out.println(memoryAddress(mInteger));
    12          System.out.println(memoryAddress(sInteger));
    13 
    14         System.out.println(integer.equals(mInteger));//true
    15          System.out.println(integer.equals(sInteger));//true
    16          System.out.println(mInteger.equals(sInteger));//true
    17 
    18     }
    19 
    20     private static int memoryAddress(Object object) {
    21          // 内存地址会有所不同
    22          return System.identityHashCode(object);
    23      }

    分析:使用equals比较,只要数值相同,那么比较结果就是相同。查看Java源代码:

    1 public boolean equals(Object obj) {
    2        if (obj instanceof Integer) {
    3            return value == ((Integer)obj).intValue();
    4        }
    5        return false;
    6    }

    可以看到Integer的equals比较,其实比较的就是数值。

    值类型之间的比较:int与int

    上代码

    1           int  m=0;
    2           int i=0;
    3           int s=0;
    4           System.out.println(m==i);//true
    5           //值类型是没有equals方法
    6           //System.out.println(m.equals(i));

    分析:对于int 的比较,无需多言,本来就是数值比较。

    Integer与int的比较:

     1          Integer integer = new Integer(0);
     2          Integer mInteger = Integer.valueOf(0);
     3          Integer sInteger = 0;// 等价于Integer。valueof
     4          int i = 0;
     5          System.out.println(integer == i);//true
     6          System.out.println(mInteger == i);//true
     7          System.out.println(sInteger == i);//true
     8          System.out.println(integer.equals(i));//true
     9          System.out.println(mInteger.equals(i));//true
    10          System.out.println(sInteger.equals(i));//true

    分析:

    1、Integer类型与int类型通过==比较,Integer会自动拆箱,转换成int数值进行比较

    2、equals方法更是读取对应的int数值进行比较。

    因此引用类型与值类型之间的比较,使用equals与==都可以。

    简单总结:

    1、引用类型之间的比较,由于存在-127至128之间的缓存对象,因此使用== 进行比较存在风险。优先使用equals进行比较

    2、引用类型与值类型进行比较,由于会自动拆箱,因此使用==和equals都可以正确得到结果

    3、建议在实际编码过程中,对数值的比较使用equals

    深入总结:

    不仅仅Integer,其他的基本类型也都存在缓存,下面给出一个简单图表进行说明

    基本类型 装箱类型 取值范围 是否缓存 缓存范围
    byte Byte -128~127 -128~127
    short Short -2^15 ~ (2^15 - 1) -128~127
    int Integer -2^31 ~ (2^31 - 1) -128~127

    long

    Long -2^63 ~ (2^63 - 1) -128~127
    float Float --  
    double Double

    --

     
    boolean Boolean true、false true、false
    char Character u0000 ~ uffff u0000 ~ uffff

    Java博大精深,要想深入,基础必须要好,才能避免bug。

    我们程序员的职责就是少写bug,这才是我们一直学习的动力。

  • 相关阅读:
    痞子衡嵌入式:在IAR开发环境下RTThread工程自定义函数段重定向失效分析
    痞子衡嵌入式:深扒IAR启动函数流程之段初始化实现中可用的压缩选项
    痞子衡嵌入式:深扒IAR启动函数流程及其__low_level_init设计对函数重定向的影响
    《痞子衡嵌入式半月刊》 第 44 期
    痞子衡嵌入式:再测i.MXRT1060,1170上的普通GPIO与高速GPIO极限翻转频率
    痞子衡嵌入式:把玩i.MXRT1062 TencentOS Tiny EVB_AIoT开发板(1) 开发环境搭建与点灯
    痞子衡嵌入式:嵌入式CortexM系统中断延迟及其测量方法简介
    痞子衡嵌入式:把玩i.MXRT1062 TencentOS Tiny EVB_AIoT开发板(2) 在Flash调试及离线启动
    痞子衡嵌入式:利用GPIO模块来测量i.MXRT1xxx的系统中断延迟时间
    痞子衡嵌入式:在i.MXRT1170上启动含DQS的Octal Flash可不严格设Dummy Cycle (以MT35XU512为例)
  • 原文地址:https://www.cnblogs.com/jiagoushi/p/9943637.html
Copyright © 2011-2022 走看看