• Java源码解读(一) 8种基本类型对应的封装类型


    说起源码其实第一个要看的应该是我们的父类Object,这里就不对它进行描述了大家各自对其进行阅读即可(其中留意wait()方法可能会存在虚假唤醒的情况)。

    一、八种基本类型

    接下来介绍我们的八种基本类型(这个大家都知道吧):char、byte、short、int、long、float、double、boolean。这里也不太描述其过多的东西,只说些要特别注意的事项(如果我这存在遗落的,欢迎大家补充):

    1、byte、short、char 不能进行含有变量的运算符运算(正常的运算符),都要求进行强转,因为都有范围限制。
     但是可以进行+= 和自增增减的操作。
    2、自动转型等级:byte,short,char(同级)-> int -> long -> float -> double (由低精度到高精度),同级不能自动转型,需要强制转换
     

    二、八种封装类型

    先说共同点:

    • equals方法:
      只有同一类型的才能作比较,然后再比较其值。源码以short为例,其它几个都一样。
        public boolean equals(Object obj) {
            if (obj instanceof Short) {
                return value == ((Short)obj).shortValue();
            }
            return false;
        }
      所以不同类型的不管值是否相等都是false;
        @Test
        public void testEquals(){
            Short num1 = 1;
            Integer num2 = 1;
            Long num3 = 1L;
            System.out.println(num1.equals(num2));//false
            System.out.println(num2.equals(num3));//false
        }
    •  直接赋值时,都会调用valueOf方法。所以要注意其的源代码。
    不同点:
    1、Character
    • 注意valueOf中代码,它缓存了ASCII码0~127的字符。其他均会创建实例。

     
    2、Byte
    • 范围是-128~127,所以超过这个范围会要求强制转换。如果使用Byte(String s)创建实例的话,超过范围会抛出异常:NumberFormatException
    • 注意valueOf中的代码,它缓存了-128~127,所以直接赋值是不创建新实例的。
        @Test
        public void testByte(){
            //byte的范围是-128~127,针对byte如果赋值不在范围eclipse会要求强制转型成byte.
            //封装类型Byte  new Byte("128")当使用字符串创建实例时,其中值超过范围会报错NumberFormatException。
            byte b1 = 12;
            Byte b2 = 12;//(byte)129;//超过范围要求强转
            Byte b3 = 12;//(byte)129;
            //Byte b4 = new Byte("128");//抛出异常
            Byte b4 = new Byte("12");//抛出异常
            System.out.println(b1 == b2);//true
            System.out.println(b2 == b3);//true
            System.out.println(b2 == b4);//false
        }
     
    3、Short
    • 跟byte的第一点一样,只是范围(-32768 ~ 32767)不一样
    • 注意valueOf方法,它缓存了-128~127的值,超过这个范围(-128~127)就会创建新的实例。
    • 基于第二种情况,不便于进行循环遍历复制操作,否则超过范围就会多个实例,影响内存。
        @Test
        public void testShort(){
            //1、short范围:-32768 ~ 32767
            Short s = new Short("32767");//超过范围会报错 NumberFormatException
            s = new Short((short)327671);//超过这个范围自动转换
            
            //2、装箱与拆箱 自动转型
            short s1 = 12;
            Short s2 = new Short(s1);//手动装箱
            System.out.println("s1 == s2:" + (s1 == s2));//自动拆箱  true
            
            //3、valueOf方法缓存了-128~127的范围,超过这个范围就要另外创建这个实例。
            Short s3 = 12;
            Short s4 = 12;
            Short s5 = 128;
            Short s6 = 128;
            System.out.println("s3 == s4:" + (s3 == s4)); //true
            System.out.println("s5 == s6:" + (s5 == s6)); //false
            
            //4、由于上面这个特性,所以这种包装类型不能在循环遍历中赋值。不然其值超过这个范围的话,就会创建新的对象,如果很多的话,就会创建很多对象。浪费空间。
        }
     
    4、Integer
    • 承受的值要注意范围(-2147483648 ~ 2147483647 ),不要求强转。
    • 注意valueOf方法,跟Short的方法一样,缓存了-128~127的值,超过这个范围(-128~127)就会创建新的实例。
    • 基于第二种情况,不便于进行循环遍历复制操作,否则超过范围就会多个实例,影响内存。
         @Test
          public void testInteger(){
              //1、Integer范围:-2147483648  ~ 2147483647 
              //后面与Short一样
              //2、装箱与拆箱 自动转型
              int s1 = 12;
              Integer s2 = new Integer(s1);//手动装箱
              System.out.println("s1 == s2:" + (s1 == s2));//自动拆箱 true
              
              //3、valueOf方法缓存了-128~127的范围,超过这个范围就要另外创建这个实例。
              Integer s3 = 12;
              Integer s4 = 12;
              Integer s5 = 128;
              Integer s6 = 128;
              System.out.println("s3 == s4:" + (s3 == s4));//true
              System.out.println("s5 == s6:" + (s5 == s6));//false
              //4、由于上面这个特性,所以这种包装类型不能在循环遍历中赋值。不然其值超过这个范围的话,就会创建新的对象,如果很多的话,就会创建很多对象。浪费空间。
          }
     
    5、Long
    • 承受的值要注意范围(-9223372036854775808 ~ 9223372036854775807 ),不要求强转。
    • 注意valueOf方法,跟Short的方法一样,缓存了-128~127的值,超过这个范围(-128~127)就会创建新的实例。
    • 基于第二种情况,不便于进行循环遍历复制操作,否则超过范围就会多个实例,影响内存。
          @Test
          public void testLong(){
              //范围就不考虑了。
              //同样、valueOf方法缓存了-128~127的范围,超过这个范围就要另外创建这个实例。
              Long s3 = 12L;
              Long s4 = 12L;
              Long s5 = 128L;
              Long s6 = 128L;
              System.out.println("s3 == s4:" + (s3 == s4));//true
              System.out.println("s5 == s6:" + (s5 == s6));//false
              //由于上面这个特性,所以这种包装类型不能在循环遍历中赋值。不然其值超过这个范围的话,就会创建新的对象,如果很多的话,就会创建很多对象。浪费空间。
          } 
    6、Float
    • 承受的值要注意范围(-1.4E-45~ 3.4028235E38),不要求强转。
    • 注意valueOf方法,跟前面的Short、Integer、Long不一样了,直接创建实例。  
    • 所以相等值的两个变量 ==运算是false.
    • 不要做加减法运算。精度(9位)问题。
        @Test
        public void testFloat(){
            //没有特殊要注意的,其他跟上面一样
            int f = 1;
            Float f1 = 1F;
            Float f2 = new Float(f);
            System.out.println(f == f1);//true
            System.out.println(f1 == f2);//false
            //注意不要用这类型做加减运算,精度问题会影响。
            System.out.println(f1 - 0.1f*9);//0.099999964
        }
     
    7、Double
    • 承受的值要注意范围,不要求强转。
    • 注意valueOf方法,与float一样,直接创建实例。
      所以相等值的两个变量 ==运算是false.
    • 不要做加减法运算。精度(17位)问题。
        @Test
        public void testDouble(){
            //注意不要用这类型做加减运算,精度问题会影响。
            System.out. println(1.0 - 0.1*9);//0.09999999999999998
            //valueof 
            Double i1 = 100.0;
            Double i2 = 100.0;
            Double i3 = 200.0;
            Double i4 = 200.0;
            System.out.println(i1==i2);//false
            System.out.println(i3==i4);//false
        }
    8、Boolean
    • valueof方法

     

      缓存了两个方法,所以如果是同样的赋值,== 运算是为true的。
        @Test
        public void testEquals(){
            Short num1 = 1;
            Integer num2 = 1;
            Long num3 = 1L;
            System.out.println(num1.equals(num2));//false
            System.out.println(num2.equals(num3));//false
        }

     三、案例分析

      猜猜下面各个输出的结果是什么:

    @Test
        public void test1(){
            Integer a = 1;
            Integer b = 2;
            Integer c = 3;
            Integer d = 3;
            Integer e = 321;
            Integer f = 321;
            Long g = 3L;
            Long h = 2L;
             
            System.out.println(c==d);
            System.out.println(e==f);
            System.out.println(c==(a+b));
            System.out.println(c.equals(a+b));
            System.out.println(g==(a+b));
            System.out.println(g.equals(a+b));
            System.out.println(g.equals(a+h));
        }

      其中会涉及到拆箱与装箱(自行弄懂)的问题。针对个别解析如下:

      c==(a+b) :a+b都会拆箱成int然后相加,所以c也会自动拆箱比较。

      g==(a+b):同理,a+b都会拆箱成int然后相加,g会拆箱成long类型。所以基本类型比较只要比较其值即可。

      g.equals(a+b):先拆箱a+b再装箱还是Integer,这里不会自动转型。Long类型的equals判断不是同一类型直接返回false

      g.equals(a+h):同上,先拆箱a+h再装箱(这里会自动向上转型)为Long,所以同类型的比较值又相等,这里返回true.

      最终结果如下:

    true
    false
    true
    true
    true
    false
    true

  • 相关阅读:
    转载viewstate(一) 太经典的东西 不得不转载保存下来
    Asp.Net中HttpModule的研究(转)
    linux学习笔记(9)
    老手经验谈:Linux驱动程序开发学习步骤(转)
    浅谈C中的malloc和free(1)
    ASP.NET的HttpModule和HttpHandler(转)
    C语言学习笔记(1)
    xcode 4 code sense
    不是bug 是教训
    win7 管理员 开关命令
  • 原文地址:https://www.cnblogs.com/yuanfy008/p/8321217.html
Copyright © 2020-2023  润新知