4、Java基本数据类型

一、基本数据类型

1、基本数据类型

JAVA中一共有八种基本数据类型,他们分别是 byte、short、int、long、float、double、char、boolean

类型型别字节取值范围
byte 整型 1byte -27 ~ 27-1
short 整型 2byte -215 ~ 215-1
int 整型 4byte -231 ~ 231-1
long 整型 8byte -263 ~ 263-1
float 浮点型 4byte 3.402823e+38 ~ 1.401298e-45
double 浮点型 8byte 1.797693e+308~ 4.9000000e-324
char 文本型 2byte 0~216-1
boolean 布尔型 1byte true/false

在通常情况下,如果JAVA中出现了一个整数数字比如35,那么这个数字就是int型的。如果我们希望它是byte型的,可以在数据后加上大写的 B:35B,表示它是byte型的。同样的35S表示short型,35L表示long型的,表示int我们可以什么都不用加,但是如果要表示long型的,就一定要在数据后面加“L”。

double型比float型存储范围更大,精度更高,所以通常的浮点型的数据在不声明的情况下都是double型的,如果要表示一个数据是float型的,可以在数据后面加上“F”。 浮点型的数据是不能完全精确的,所以有的时候在计算的时候可能会在小数点最后几位出现浮动,这是正常的。

2、自动类型转换

1)两种类型是彼此兼容的

2)转换后的目标类型占的空间范围一定要大于被转化的源类型

由低字节向高字节自动转换(黑线表示无数据丢失的自动数据转换,红线表示转换中可能发生精度丢失)

<关于int转float发生精度丢失,而int转double可以无数据丢失,可自行研究。

3、强制数据转换

将容纳更多信息的数据类型转换成一个容量更小的数据类型,可能存在精度损失的风险,编译器要求程序员进行强制类型转换。

强制转换过程中可能发生数据溢出,必须警惕。

int a=(int)3.14;

4、数据类型自动提升

  如果两个操作数其中有一个是double类型,另一个操作就会转换为double类型。

  否则,如果其中一个操作数是float类型,另一个将会转换为float类型。

  否则,如果其中一个操作数是long类型,另一个会转换为long类型。

  否则,两个操作数都转换为int类型。

5、大数据类型

如果基本的整数和浮点数精度不够满足需求,那么可以使用java.math包中的两个很有用的类:BigInteger和BigDecimal。这两个类可以处理包含任意长度数字序列的数值,BigInteger类实现了任意精度的整数运算,BigDecimal实现了任意精度的浮点数运算。 使用静态的valueOf方法可以将普通的数值转换为大数值:

BigInteger  a = BigInteger.valueOf(100);

 

二、基本类型对应的包装类

1、概述

虽然 Java 语言是典型的面向对象编程语言,但其中的八种基本数据类型并不支持面向对象编程,基本类型的数据不具备“对象”的特性——不携带属性、没有方法可调用。 沿用它们只是为了迎合人类根深蒂固的习惯,并的确能简单、有效地进行常规数据处理。 这种借助于非面向对象技术的做法有时也会带来不便,比如引用类型数据均继承了 Object 类的特性,要转换为 String 类型(经常有这种需要)时只要简单调用 Object 类中定义的toString()即可,而基本数据类型转换为 String 类型则要麻烦得多。为解决此类问题 ,Java为每种基本数据类型分别设计了对应的类,称之为包装类(Wrapper Classes),也有教材称为外覆类或数据类型类。

基本数据类型对应的包装类如下图:

2、装箱和拆箱

2.1、什么是装箱和拆箱?

前面已经提到了,JAVA为每一个基本数据类型都提供了一个包装器类,在JAVA SE5之前,如果要生成一个数值为10的Integer对象,需要这么做:

Integer integer = new Integer(10); 而在JAVA SE5开始就提供了自动装箱功能,如果要生成数值为10的Integer对象,只需要像下面这样做就行了:

Integer integer = 10; 这样写会触发自动装箱,能直接根据数值就能创建对应的Integer对象,而不用new操作。

那么拆箱是怎么样的呢?只需要像下面这样做就行了:

Integer integer = 5;//装箱 int i = integer;//拆箱 简而言之,装箱就是基本数据类型转换为包装器类型,拆箱就是包装器类型转换基本类型。

2.2、装箱和拆箱的过程是什么?

通过上面的介绍,知道了什么是装箱何拆箱。不过装箱和拆箱的具体过程是什么呢?其实装箱和拆箱是调用了两个函数来实现的,下面通过一段代码来说明:

 public class Main {
    public static void main(String[] args) {
            Integer integer = 5;
            int i = integer;  
    }
}  

反编译这段代码生成的class文件:

从反编译的结果来看,装箱的时候调用了Integer.valueOf(int i)这个函数,拆箱的时候调用了Integer.intValue()这个函数。

总的来说,装箱的时候是调用的包装器的valueOf这个函数,拆箱的时候调用的是包装器的xxxValue这个函数(xxx是包装器对应的基本数据类型)。

2.3、装箱和拆箱关键源码分析

通过上面的介绍,我们知道了装箱和拆箱关键在于valueOf和xxxValue这两个函数,xxxValue这个函数没有什么值得注意的,就是把包装器中的值装换为对应的基本数据类型。而valueOf这个函数在不同的包装器中,实现方法有很大的区别。

  下面,先介绍在Integer包装器类中,该方法是怎么实现的,源码如下:
public static Integer valueOf(int i) {
       if(i >= -128 && i <= IntegerCache.high)
           return IntegerCache.cache[i + 128];
       else
           return new Integer(i);
}

 

 private static class IntegerCache {
   static final int high;
   static final Integer cache[];

   static {
       final int low = -128;

       // high value may be configured by property
       int h = 127;
       if (integerCacheHighPropValue != null) {
           // Use Long.decode here to avoid invoking methods that
           // require Integer's autoboxing cache to be initialized
           int i = Long.decode(integerCacheHighPropValue).intValue();
           i = Math.max(i, 127);
           // Maximum array size is Integer.MAX_VALUE
           h = Math.min(i, Integer.MAX_VALUE - -low);
      }
       high = h;

       cache = new Integer[(high - low) + 1];
       int j = low;
       for(int k = 0; k < cache.length; k++)
           cache[k] = new Integer(j++);
  }

   private IntegerCache() {}
}

从上面的源码可以知道,通过valueOf创建Integer对象的时候,如果数值在区间[-128,127],那么便返回指向IntegerCache.cache数组中已经存在的对象的引用;否则创建一个新的Integer对象。简而言之,创建Integer包装器时,有一个数值在[-128,127]的缓冲池。当创建的对象数值在[-128,127]之间时,那么不需要再在内存中开辟一个空间存储,只需要将当前对象的引用指向该缓冲池中对应的对象,这样效率上得到了提高,资源也没有浪费。当然,这是Integer包装器类的value函数,其他的包装器不是这样,有兴趣的可以自己查看源码,这里不一 一详解。

posted @ 2020-07-20 18:00  发哥讲Java  阅读(211)  评论(0编辑  收藏  举报