美文网首页
Java中的基本数据类型

Java中的基本数据类型

作者: 胜舟 | 来源:发表于2021-01-17 18:00 被阅读0次

    本篇我们对java的基本数据类型进行学习,同样也是面试喜欢考的基础内容,所以我们给它好好的过一遍。

     

    首先我们得知道,java有两大数据类型:

    基本数据类型(又叫内置数据类型)

    引用数据类型

    基本数据类型比较简单,就是int、long这样的,引用数据类型类似c++的指针,它指向一个对象,我们用的所有的对象或数组都属于引用数据类型,它的默认值都是null。

    本篇文章关注的是基本数据类型,但是同时也会说明这些基本类型对应的包装类,这个包装类就是引用类型。

     

    1. 八大基本数据类型

    java有8种基本数据类型,这个需要记住

    4个整数类型:byte、short、int、long

    2个浮点数类型:float、double

    1个字符类型:char

    1个布尔类型:boolean

    看到这几个熟悉的名字,大家应该完全明白什么是基本数据类型了,简单来说,其实就是我们常用的小写的数据类型

    下图是它们所占的位数和字节数,其中boolean没有明确的定义,但是一般是只占一位。

    基本类型 位数 字节 最小值 最大值 默认值
    byte 8 1 -128 127 0
    short 16 2 -32768 32767 0
    int 32 4 -2147483648 2147483647 0
    long 64 8 -9223372036854775808 9223372036854775807 0L(L不分大小写,但是小写容易和1混淆,所以一般大写)
    char 16 2 'u0000' '\uFFFF' 'u0000'(即为空格)
    float 32 4 1.4 E-45 3.4028235 E38 0f
    double 64 8 4.9 E-324 1.7976931348623157 E308 0d
    boolean 1 无最大最小值之分 无最大最小值之分 false

    E是科学计数法,E后面的数字代表E前面的数字要乘以10的多少次方,例如3.14E-3就是乘以10的负三次方:

    3.14 x 0.001 =0.00314

    然后这些最大值最小值,可以通过它们的包装类里的MAX_VALUEMIN_VALUE两个常量查看,例如:

            System.out.println("Integer最小值:" + Integer.MIN_VALUE);  
            System.out.println("Integer最大值:" + Integer.MAX_VALUE)
    

    关于什么是包装类,第三小节会详细说明,这里先剧透一下,就是Integer、Double之类的和基本数据类型对应的大写的类。

     

    2. char数据的赋值

    char类型较为特殊,它在java中是Unicode编码,且占2个字节16位,无符号,所以它的范围0-65535。可以理解成可以存65536个不同的符号,但是计算机是不能直接存符号的。所以它本质上其实是用整数存储,但是使用了Unicode码代表字符,每个字符都有一个专属固定的Unicode码,所以每个数字都对应一个符号。

    而另一种赋值方式是通过十六位的Unicode编码,这种比较特殊,用起来可能比较少,格式就是'\u1234'这样。'\u'代表这是个Unicode字符,里面四位数字其实是16进制的Unicode码。char的包装类中的MAX_VALUEMIN_VALUE两个常量也是以这种方式存储的字符。

    例如:对char赋值'\u7801'或整数30721,结果都等于字符:码。如果你将16进制的7801计算为10进制,就会发现结果就是30721。

    所以总共可以用三种形式给它赋值

    ①单引号包住的单个字符

    ②0-65535中的整数(Unicode值的十进制)

    ③单引号包住的字符编码(Unicode值的十六进制)

    当然结果和范围是一样的,它最终只能代表一个字符,所以我们一般使用的时候用第一种方式赋值就行了。只是以后看到有人赋值整数结果却是字符时,不要大惊小怪就好。

    例如:

        public static void main(String[] args) {
            char a = 'A';
            char b = 65;
            char c = '\u0041';
            System.out.println(a);
            System.out.println(b);
            System.out.println(c);
        }
    

    输出的结果是一样的,都是:A

    所以以后不要下意识的觉得char字符'6'转换为整数也是6哦,最终其实是看Unicode值的,结果应该是整数:54

     

    3. 包装类

    这8种基本类型都有一个对应的包装类,也就是java中的另一种数据类型:引用数据类型,有自己的属性和方法,默认值为null。

    我们通常使用基本数据时,也是使用它们的包装类更多。因为这些基本数据类型仅仅只能声明和存放一个值,甚至都不能为null,也没有我们常用的一些类型转换equals()方法。基本数据类型只能做做运算,而包装类就比较完善了,适合在业务中使用。

    基本数据类型对应的包装类分别是:Byte、Short、Integer、Long、Float、Double、Character、Boolean。也就是除了char对应的是Character,int对应Integer,其他的都只是首字母变成大写而已。

    注:这里注意一下String,它既不是基本类型也不是谁的包装类,不要误以为它是字符类型的基本类型之类的了,虽然它的重要性并不比基本类型低。

    字符类的基本类型仅有char而已。

     

    4. 自动装箱和自动拆箱

    自动拆装箱大家应该有听过,它是针对基本类型和它们的包装类的,让它们可以自动进行转换。

    装箱:将基本类型用它们对应的应用类型包装起来

    拆箱:将包装类型转换为基本数据类型

    可能这样说还不是很理解,实际上我们一直在使用这个功能,例如在java se5之前,如果要初始化一个Integer对象,是需要这样的:

    Integer i = new Integer(10);
    

    看起来又正常又别扭,因为每个新对象都是通过new初始化出来的,但好像我们使用的时候从来没有这么麻烦过,一般我们是:

    Integer i=10;
    

    这就是自动装箱,理论上来说,10是基本类型的数据,只能直接赋给int类型。现在我们将它赋给了int的包装类Integer,其实就是java自动对基本数据10进行了装箱,装到了包装类中。简单的说就是替你创建了一个Integer对象,值存为10。

    自动拆箱则是相反,java自动将Integer变量拆箱为具体的整数值,这样就可以做到将包装类变量直接赋给int基本数据类型。

    自动拆箱:

    Integer i=10;   //自动装箱
    int j=i;        //自动拆箱
    

    在大部分包装类和基本类型混用的地方,都会自动进行拆装箱,下面第6小节会详细说明自动进行拆装箱的场景。

     

    5.自动拆装箱的实现原理

    通过编译再对class字节码文件的反编译,我们可以知晓答案

    首先写一段这样的测试代码:

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

    打开cmd输入javac Test.java进行编译,得到Test.class

    然后通过jd-gui工具反编译Test.class,得到如下代码:

    public class Test
    {
      public static void main(String[] paramArrayOfString)
      {
        Integer localInteger = Integer.valueOf(10);
        int i = localInteger.intValue();
      }
    }
    

    可以看到,自动拆装箱的核心是在包装类变量上使用了两个方法,装箱时是Integer.valueOf(),通过看源码可以得知本质上是调用了new Integer初始化。拆箱时是intValue(),也是直接返回了int的值。

    看来所谓高大上的自动拆装箱,其实也只是偷偷的调用了包装类的两个方法,只是我们没发现而已。另外,其他基本类型的拆装箱也是一样的,例如char的两个方法也分别是valueOf()和charValue(),大家可以自己测试一下。

    总结:装箱过程是通过调用包装器的valueOf方法实现的,而拆箱过程是通过调用包装器的 xxxValue方法实现的。

     

    6.自动拆装箱的场景

    除了我们最常见的赋值,还有一些其他场景会进行自动拆装箱,以下都可以通过反编译查看原理

    ①将基本数据类型放入集合类

    例如

    List<Integer> li = new ArrayList<>();
    for (int i = 1; i < 50; i ++){
        li.add(i);
    }
    

    这里使用了自动装箱:li.add(Integer.valueOf(i));

    ②比较大小

    Integer a=1;
    System.out.println(a==1);
    

    结果是true,其实这里用了自动拆箱:System.out.println(a.intValue()==1);

    ③运算

    Integer i = 1;
    System.out.println(i+2);
    

    这里使用了自动拆箱,拆成基本类型才可以进行运算:System.out.println(i.intValue()+2);

    ④三目运算符

    这种情况比较少接触,我也是通过网上搜集资料才知道有这种情况的

    boolean flag = true;
    Integer i = 0;
    int j = 1;
    int k = flag ? i : j;
    

    这里使用了自动拆箱:int k = flag ? i.intValue() : j,当第二、第三位操作数分别是基本类型和对象时,其中的对象会自动拆箱。所以一不小心可能就会触发空指针异常,要注意一下这点。

    这几个场景最需要注意的是运算这一块,以后碰到包装类的运算时,要记住它们是先拆箱为基本数据类型,再运算。

     

    7.不同基本类型之间的运算

    ①不同的基本类型之间

    在java中,除了boolean,其他基本类型是可以自动转换的。转换的形式从低到高,也就是两个不同的基本类型在一起运算时,会按照如下的顺序,将低的转换成高的类型。

    byte,short,char——》int——》long——》float——》double

    byte,short和char有些特殊,就算不涉及更高的类型,它们在运算比较时也是直接自动转换为int进行处理的。举个例子也就是,如果short、int、和float类型相加,那么统一都会转换成3个float类型,然后再进行运算。

    ②基本类型与String

    基本类型与String进行运算的话,会自动转换成String类型 ,但是这里要注意如下特殊情况:

    System.out.println(1+2+"3"+4);
    

    这里从左到右,由于1+2是两个整数,所以会先计算得到3,然后3+"3",则是转换成String,同理"33"+4,也就变成了字符串334。

     

    8.包装类和常量池

    Java的基本类型的包装类,大部分都实现了常量池技术: Byte,Short,Integer,Long,Character,Boolean,也就是通过了一定范围的缓存,避免重复新建对象。

    Byte,Short,Integer,Long默认创建了[-128,127]范围的数据

    Character默认创建了数值在[0,127]范围的数据

    Boolean默认则是直接返回True 或false

    这些都可以通过源码的valueOf()方法查看到,也就是当你在任何地方通过valueOf()创建基本数据时(自动装箱),它们都是从同一个常量池里先判断是否有这个值,如果有,就直接返回常量池中的对象,如果没有,才new一个新对象给你。

    因此,如果你是通过自动装箱或valueOf获取的包装类对象,当数据的值在缓存范围内时,无论你获取多少次相同的数据,本质上都是指向同一个对象,所以内存地址之类的自然也都是相等的。

    至于浮点数是没有缓存的,因为在某个范围里的整数是有限的,但浮点数却是无限的。即便范围是0到1,其中也有无数个浮点数,也很难定位到哪些浮点数比较常用,所以浮点数是没有常量池缓存的。

     

     

     

    参考资料:

    1.什么是Java中的自动拆装箱

    https://blog.csdn.net/wufaliang003/article/details/82347077

    2.深入剖析Java中的装箱和拆箱

    https://www.cnblogs.com/dolphin0520/p/3780005.html

    3.java不同基本类型之间的运算

    https://blog.csdn.net/shenzixincaiji/article/details/82735390

    相关文章

      网友评论

          本文标题:Java中的基本数据类型

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