一、基本数据类型

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、概述

这种借助于非面向对象技术的做法有时也会带来不便,比如引用类型数据均继承了 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文件:




Java 的基本数据类型 java中基本的数据类型_编程语言


从反编译的结果来看,装箱的时候调用了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函数,其他的包装器不是这样,有兴趣的可以自己查看源码,这里不一 一详解。