Java数值类型提升机制

简介: Java数值类型提升机制

【1】数值提升

数字类型提升机制被用于算术运算符上,通常使用场景为:


同一类型转换

有时可以使代码更清晰。

拓宽原始类型转换

指byte、short、int、long、float、double由低向高转换。

自动拆箱转换

基础类型引用类的拆箱方法,如r.intValue()。

数值提升用于将算术运算中的操作数转化为一个相同的类型以便于运算,具体分为两种情况:一元数值提升和二元数值提升。



【2】一元数值提升

某些运算符将一元数值提升用在了单操作数运算中,其必定能得到一个数字类型的值,规则如下:


if 操作数是编译时包装类型Byte、Short、Character或Integer,那么它会先拆箱为对应的原始类型,然后拓宽为int类型。

else if 操作数为编译时包装类型Long、Float或Double,那么就直接拆箱为对应的原始类型。

else if 操作数是编译时拆箱类型byte、short、char或int,那么就拓宽为int类型。

else 保持原样。



一元数值提升还用在以下情境的表达式中(提升为int):


数组创建表达式的维度

数组索引表达式的索引

正号运算符(+)的操作数

负号运算符(-)的操作数

按位补运算符(~)的操作数

移位运算符(>>, >>>, << )的每一个操作数。注意移位运算并不会使两边的操作数提升到相同类型,如 A << B 中若B为long类型,A并不会被提升到long。

注意:自增和自减单目运算符同样也会进行类型提升,但运算后会自动进行强制类型转换,如

byte a = 127;

a++; // a在运算后为int类型,转为byte截断后变成-128

等价于

byte a = (byte)128;


示例如下:

class Test {
    public static void main(String[] args) {
        byte b = 2;
        int a[] = new int[b];  // 维度表达式提升
        char c = '\u0001';
        a[c] = 1;              // 索引表达式提升
        a[0] = -c;             // 负号 提升
        System.out.println("a: " + a[0] + "," + a[1]);
        b = -1;
        int i = ~b;            // 按位补提升
        System.out.println("~0x" + Integer.toHexString(b)
                           + "==0x" + Integer.toHexString(i));
        i = b << 4L;           // 移位提升(左操作数)
        System.out.println("0x" + Integer.toHexString(b)
                           + "<<4L==0x" + Integer.toHexString(i));
    }
}
输出:
a: -1,1
~0xffffffff==0x0
0xffffffff<<4L==0xfffffff0


【3】二元数值提升

当二元运算符的操作数皆可转化为数字类型时,那么将采用如下二元数值提升规则:


如果任一操作数为引用类型,那么对其进行自动拆箱。


拓宽类型转换被应用于以下情况:


if 某一操作数为double类型,那么另一个也转为double

else if 某一操作数为float类型,那么另一个也转为float

else if 某一操作数为long类型,那么另一个也转为long

else 两个操作数都转为int


二元数值提升应用于以下运算符上:

乘除法运算符: * 、 / 、%

针对数字类型的加减运算符: + 、 -

数值比较运算符:< 、<= 、> 、>=

数值相等比较运算符: == 、 !=

整数按位运算符: & 、^ 、|

某些情况下的条件运算符 ? : 中

注意:混合赋值运算符同样也会自动进行强制类型转换,如

byte a = 127;

a += 1; // a在运算后为int类型,转为byte截断后变成-128


示例如下:

class Test {
    public static void main(String[] args) {
        int i    = 0;
        float f  = 1.0f;
        double d = 2.0;
        // int*float 先是被提升为 float*float,然后
        // float==double 被提升为 double==double:
        if (i * f == d) System.out.println("oops");
        // char&byte 被提升为 int&int:
        byte b = 0x1f;
        char c = 'G';
        int control = c & b;
        System.out.println(Integer.toHexString(control));
        // 此处 int:float 被提升为 float:float:
        f = (b==0) ? i : 4.0f;
        System.out.println(1.0/f);
    }
}
输出:
7
0.25


【4】进制

① 十进制(最常用的进制)

  • 十进制就是满十进一的进制
  • 十进制当中一共有10个数字
    0 1 2 3 4 5 6 7 8 9
  • 十进制如何计数
    0 1 2 3 4 5 6 7 8 9 10 11 12 。。。 19 20 。。。29 30

② 二进制(计算机底层使用的进制)

满二进一

二进制中一共有2个数字

0 1

二进制如何计数

0 1 10 11 100 101 110 111 1000

所有的数据在计算机底层都是以二进制的形式保存的,计算机只认二进制

可以将内存想象为一个一个的小格子,小格子中可以存储一个0或一个1

内存中的每一个小格子,我们称为1bit(位)

bit是计算机中的最小的单位

byte是我们最小的可操作的单位

8bit = 1byte(字节)

1024byte = 1kb(千字节)

1024kb = 1mb(兆字节)

1024mb = 1gb(吉字节)

1024gb = 1tb(太字节)


③ 八进制(一般不用)

  • 满八进一
  • 八进制中一共有8个数字
    0 1 2 3 4 5 6 7
  • 八进制如何计数
    0 1 2 3 4 5 6 7 10 11 。。。 17 20 。。。27 30


④ 十六进制


满十六进一

十六进制中一共有16个数字

由于十六进制是满16才进位,

所以十六进制中引入了a b c d e f来表示 10 11 12 13 14 15

0 1 2 3 4 5 6 7 8 9 a b c d e f

十六进制如何计数

0 1 2 3 4 5 6 7 8 9 a b c d e f 10 11 12 。。。 1a 1b 1c 1d 1e 1f

20 21 22 。。。 2a 2b 2c 2d 2e 2f 30

我们在查看二进制数据时,一般会以十六进制的形式显示

目录
相关文章
|
6月前
|
存储 算法 安全
Java集合框架:理解类型多样性与限制
总之,在 Java 题材中正确地应对多样化与约束条件要求开发人员深入理解面向对象原则、范式编程思想以及JVM工作机理等核心知识点。通过精心设计与周密规划能够有效地利用 Java 高级特征打造出既健壮又灵活易维护系统软件产品。
170 7
|
7月前
|
Java 开发者
Java 函数式编程全解析:静态方法引用、实例方法引用、特定类型方法引用与构造器引用实战教程
本文介绍Java 8函数式编程中的四种方法引用:静态、实例、特定类型及构造器引用,通过简洁示例演示其用法,帮助开发者提升代码可读性与简洁性。
|
8月前
|
安全 算法 Java
Java泛型编程:类型安全与擦除机制
Java泛型详解:从基础语法到类型擦除机制,深入解析通配符与PECS原则,探讨运行时类型获取技巧及最佳实践,助你掌握泛型精髓,写出更安全、灵活的代码。
|
8月前
|
安全 IDE Java
Java记录类型(Record):简化数据载体类
Java记录类型(Record):简化数据载体类
586 143
|
8月前
|
Java 测试技术
Java浮点类型详解:使用与区别
Java中的浮点类型主要包括float和double,它们在内存占用、精度范围和使用场景上有显著差异。float占用4字节,提供约6-7位有效数字;double占用8字节,提供约15-16位有效数字。float适合内存敏感或精度要求不高的场景,而double精度更高,是Java默认的浮点类型,推荐在大多数情况下使用。两者都存在精度限制,不能用于需要精确计算的金融领域。比较浮点数时应使用误差范围或BigDecimal类。科学计算和工程计算通常使用double,而金融计算应使用BigDecimal。
3109 102
|
8月前
|
安全 Java 编译器
Java类型提升与类型转换详解
本文详解Java中的类型提升与类型转换机制,涵盖类型提升规则、自动类型转换(隐式转换)和强制类型转换(显式转换)的使用场景与注意事项。内容包括类型提升在表达式运算中的作用、自动转换的类型兼容性规则,以及强制转换可能引发的数据丢失和运行时错误。同时提供多个代码示例,帮助理解byte、short、char等类型在运算时的自动提升行为,以及浮点数和整型之间的转换技巧。最后总结了类型转换的最佳实践,如避免不必要的转换、使用显式转换提高可读性、金融计算中使用BigDecimal等,帮助开发者写出更安全、高效的Java代码。
449 0
|
9月前
|
人工智能 前端开发 安全
Java开发不可不知的秘密:类加载器实现机制
类加载器是Java中负责动态加载类到JVM的组件,理解其工作原理对开发复杂应用至关重要。本文详解类加载过程、双亲委派模型及常见类加载器,并介绍自定义类加载器的实现与应用场景。
353 4
|
11月前
|
人工智能 JavaScript Java
Java反射机制及原理
本文介绍了Java反射机制的基本概念、使用方法及其原理。反射在实际项目中比代理更常用,掌握它可以提升编程能力并理解框架设计原理。文章详细讲解了获取Class对象的四种方式:对象.getClass()、类.class、Class.forName()和类加载器.loadClass(),并分析了Class.forName()与ClassLoader的区别。此外,还探讨了通过Class对象进行实例化、获取方法和字段等操作的具体实现。最后从JVM类加载机制角度解析了Class对象的本质及其与类和实例的关系,帮助读者深入理解Java反射的工作原理。
276 0
|
11月前
|
人工智能 Java 关系型数据库
Java——SPI机制详解
SPI(Service Provider Interface)是JDK内置的服务提供发现机制,主要用于框架扩展和组件替换。通过在`META-INF/services/`目录下定义接口实现类文件,Java程序可利用`ServiceLoader`动态加载服务实现。SPI核心思想是解耦,允许不同厂商为同一接口提供多种实现,如`java.sql.Driver`的MySQL与PostgreSQL实现。然而,SPI存在缺陷:需遍历所有实现并实例化,可能造成资源浪费;获取实现类方式不够灵活;多线程使用时存在安全问题。尽管如此,SPI仍是Java生态系统中实现插件化和模块化设计的重要工具。
558 0
|
11月前
|
设计模式 人工智能 安全
AQS:Java 中悲观锁的底层实现机制
AQS(AbstractQueuedSynchronizer)是Java并发包中实现同步组件的基础工具,支持锁(如ReentrantLock、ReadWriteLock)和线程同步工具类(如CountDownLatch、Semaphore)等。Doug Lea设计AQS旨在抽象基础同步操作,简化同步组件构建。 使用AQS需实现`tryAcquire(int arg)`和`tryRelease(int arg)`方法以获取和释放资源,共享模式还需实现`tryAcquireShared(int arg)`和`tryReleaseShared(int arg)`。
516 32
AQS:Java 中悲观锁的底层实现机制