作者主页:Designer 小郑
作者简介:Java全栈软件工程师一枚,来自浙江宁波,负责开发管理公司OA项目,专注软件前后端开发(Vue、SpringBoot和微信小程序)、系统定制、远程技术指导。CSDN学院、蓝桥云课认证讲师,全栈领域优质创作者。热爱技术、专注业务、开放合作、乐于分享,期待你我共同成长!
主打方向:Vue、SpringBoot、微信小程序
目录
- 一、基本数据类型转换
- 1.1 为什么要进行转换
- 1.2 自动类型转换(隐式转换)
- 1.2.1 自动类型转换1——直接赋值
- 1.2.2 自动类型转换2——运算时转换
 
- 1.3 强制类型转换(显示转换)
- 1.3 类型转换小结
 
- 二、自动装箱和自动拆箱
- 2.1 包装类是什么?
- 2.2 为什么要用包装类?
- 2.3 自动装箱
- 2.4 自动拆箱
- 2.5 性能比较
- 2.5.1 测试基本类型
- 2.5.2 测试包装类
- 2.5.3 测试小结
 
 
- 三、课时小结
 
一、基本数据类型转换
在学习基本数据类型转换之前,首先要了解为什么要进行基本数据类型转换。
1.1 为什么要进行转换
在上一节课时中,提到了 Java 数据类型的层级,如下图所示。

Java 作为一个强类型的编程语言,在不同数据类型之间进行转换时,需要进行手动 / 自动转换。
byte 的数据范围是 -128 到 127,如果将数值 128 直接赋值给 byte 类型的数据,IntelliJ IDEA 会编译报错,如下图所示。

 所以需要进行数据转换,请看以下代码:
public class Main {
    public static void main(String[] args) {
        int a = 128;
        byte b = (byte) a;
        System.out.println("答案 = " + b);
    }
}
最终输出结果为:
答案 = -128
因为 128 超过了 byte 的数据范围,则重新计数赋值,第一个值为 -128。
通过以上一个简单的例子,同学们只需简单了解下为什么要进行数据类型转换即可。
即只要参与运算的基本数据类型不一致时,就会发生数据类型的转换。
Java 中基本数据类型的转换主要分为两类
- 自动转换类型(隐式转换)
- 强制转换类型(显示转换)
接下来逐个讲解。
1.2 自动类型转换(隐式转换)
自动类型转换,顾名思义就是自动进行数据类型转换。
即由 Java 编译器进行自动处理,Java 代码不需要经过任何处理。
小类型到大类型是自动提升的,那什么是小类型和大类型呢?如下图所示,箭头非被指结点为相对小类型,反之箭头被指结点为相对大类型,如 short 相对于 int 来说就是小类型。

1.2.1 自动类型转换1——直接赋值
小类型变量赋值给大类型时,会触发自动类型转换,比如:
public class Main {
    public static void main(String[] args) {
        long a = 1;
    }
}
数值 1 是 int 类型,而承载的变量为 long 类型,则数值 1 会被自动转换为 1L。
1.2.2 自动类型转换2——运算时转换
小类型变量和大类型变量进行运算时,会将小类型提升为大类型,再进行数学运算,如下所示。
public class Main {
    public static void main(String[] args) {
        int a = 1;
        long b = 5L + a;
    }
}
比如变量 a 为 int 类型,在计算 5L + a 时,会首先将 a 转换为 1L,再计算 5L + 1L = 6L,最终得出 6L 结果。
简单来说 long + int 会自动转换为 long + long 再进行计算。
同理 int + double 也会自动转换为 double + double 再进行计算,如下代码所示。
public class Main {
    public static void main(String[] args) {
        int a = 1;
        double b = 3.14 + a;
    }
}
1.3 强制类型转换(显示转换)
大类型转为小类型时,需要强制类型转换,可能会导致数据丢失。
比如 int 类型的取值范围是 -2^31到2^31-1,byte 类型的取值范围是 -2^7到2^7-1。
当 int 类型转换为 byte 类型时,会出现数据溢出的情况,如下代码所示。
public class Main {
    public static void main(String[] args) {
        int a = 128;
        byte b = (byte) a;
        System.out.println("b = " + b);
    }
}
最终输出的结果为 b = -128,即发生了数据溢出情况,也可以理解为数据丢失。
同理,在 double 类型强制转换为 int 时,也会出现数据精度丢失(数据丢失),如下代码所示。
public class Main {
    public static void main(String[] args) {
        double a = 3.1415926;
        int b = (int) a;
        System.out.println("b = " + b);
    }
}
输出结果为 b = 3,即发生了数据精度丢失情况,也可以理解为数据丢失。
1.3 类型转换小结
关于 Java 的数据类型转换,同学们需要理解以下三点:
- 大转小:强制类型转换,如下:
int a = 6;
byte b = (byte) a;
提示:对于 byte 和 int 类型之间的转换中需要注意,当把一个 int 数值赋值给 byte 变量时,不管是否超过范围,都需要强制转换。
- 小转大:自动类型转换,如下:
int a = 6;
long c = a;
- 默认定义类型
整数的默认类型为 int。
 整数带有后缀 L 时类型为 long。
 浮点数的默认类型为 double。
 浮点数带有后缀 f 时类型为 float。
提示:关于 String 的类型转换,将在后续的课时中讲解,因为 String 不属于 Java 的基本数据类型。
二、自动装箱和自动拆箱
在学习自动装箱和自动拆箱之前,首先了解什么是包装类。
2.1 包装类是什么?
在 jdk1.4 中,新增了 8 个基本数据类型的对应包装类,如下表所示。
| 基本类型 | 包装类 | 
|---|---|
| byte | Byte | 
| short | Short | 
| int | Integer | 
| long | Long | 
| float | Float | 
| double | Double | 
| char | Character | 
| boolean | Boolean | 
基本数据类型的对应包装类的方式基本相同,但在 JVM 上的分配有所不同,具体将在后续的课时中讲解,同学们只需知道在时间或空间上,基本数据类型优于对应包装类即可。
2.2 为什么要用包装类?
从 jdk1.5 开始,定义集合需要使用包装类。定义普通数组,使用基本类型和包装类都可,如下代码所示。
public class Main {
    public static void main(String[] args) {
        /**
         * 普通数组的定义方法
         */
        int[] a = new int[10];
        /**
         * 集合的定义方法
         */
        List<Integer> arr = new ArrayList<>();
        /**
         * 对基本类型的集合定义需要转为包装类
         */
        // List<int> arr = new ArrayList<>(); // 编译错误
    }
}
关于集合的用法,会在下面的课时中讲解,同学们只需要了解包装类的使用场景即可。
2.3 自动装箱
自动装箱是什么?基本类型自动转换为包装类型就是自动装箱。
请看以下代码:
public class Main {
    public static void main(String[] args) {
        /**
         * 直接赋值
         */
        Integer a = 666;
        /**
         * 包装类的静态工厂方法
         */
        Integer b = Integer.valueOf(666);
        /**
         * 构造器赋值,在现有 JDK 中已被废弃
         */
        Integer c = new Integer(666);
    }
}
在对 Integer 类型的变量赋值时,666 这是一个基本数据类型,而变量 a、b、c 为包装类。
自动装箱,就是将一个基本类型直接赋值给包装类型的过程。
如果没有自动装箱,以上代码无法通过 JVM 编译。
2.4 自动拆箱
自动拆箱是什么?包装类型自动转换为基本类型就是自动拆箱。
请看以下代码:
public class Main {
    public static void main(String[] args) {
        Integer a = 666;
        int b = 666;
        System.out.println("判断 1 = " + (a == b));
        System.out.println("判断 2 = " + Objects.equals(a,b));
    }
}
代码中分别定义基本类型和包装类,赋同样的值,最后判断是否相等,输出为:
判断 1 = true
判断 2 = true
其中变量 a 在比较之前,自动拆箱为基本类型,然后在于 b 进行比较,最后得出 true 的结果。
如果不进行自动拆箱,两个不同类型的变量无法进行比较。
就好比拿 苹果 和 电视 比较性能,这是不可行的。
Java 只能将包装类 Integer 拆箱为 int 才能和 int 值进行比较。
这就是 自动拆箱。
2.5 性能比较
同学们学习自动装箱、自动拆箱之后,还需要了解它们的性能差距。
因为,这将影响你在实战开发中,决定常用哪个,最终影响你的程序性能。
2.5.1 测试基本类型
首先对基本数据类型进行测试,代码如下所示。
public class Main {
    private static final long MAX_NUMBER = 1000000000;
    public static void main(String[] args) {
        long start = System.currentTimeMillis();
        long sum = 0;
        for(long i = 0; i < MAX_NUMBER; i ++) {
            sum += i;
        }
        long end = System.currentTimeMillis();
        System.out.printf("耗时 = " + (end - start) + ",计算结果 = " + sum);
    }
}
最后输出结果:
耗时 = 304,计算结果 = 499999999500000000
2.5.2 测试包装类
接着对包装类进行测试,代码如下所示。
public class Main {
    private static final Long MAX_NUMBER = 1000000000L;
    public static void main(String[] args) {
        long start = System.currentTimeMillis();
        Long sum = 0L;
        for(Long i = 0L; i < MAX_NUMBER; i ++) {
            sum += i;
        }
        Long end = System.currentTimeMillis();
        System.out.printf("耗时 = " + (end - start) + ",计算结果 = " + sum);
    }
}
最后输出结果:
耗时 = 6374,计算结果 = 499999999500000000
2.5.3 测试小结
由此可见,使用包装类虽然简便,但频繁自动装拆箱会带来性能低下的问题。
所以在实战开发中,建议使用基本数据类型。
如果一定要使用包装类的场景下,再去使用包装类。
在 2.1 小节 也提到过,基本类型无论是在时间还是空间上都是优于引用类型(如包装类)的。
三、课时小结
在本节课时中,讲解了低转高、高转低的 Java 基本类型转换,接着学习了包装类的概念,再引申出自动装箱、自动拆箱的概念,最后分别进行了性能测试。在下节课时中,将学习 Java 变量、常量及其作用域的知识。




















