zoukankan      html  css  js  c++  java
  • 小白的消费为何被迫升级?-java数据类型的转换

    背景

    小白最近有点烦恼,原因也很简单,不知道为何?小白的消费不知不觉被迫升级了,请看费用清单:

            for (byte b = Byte.MIN_VALUE; b < Byte.MAX_VALUE; b++) {
                if (b == 0x90)
                    System.out.print("life is Happy!");
                }

    本来小白预期输出结果:

    life is Happy!

    小白的消费为何被迫升级-java数据类型的Promotion

     

    但是什么都没有输出,这是怎么回事呢?是不是以后的幸福小日子就没了?

    小白的消费为何被迫升级-java数据类型的Promotion

     

    于是小白向柯南请教:

    小白的消费为何被迫升级-java数据类型的Promotion

     

    破案

    为了比较byte 数值(byte)0x90 和int 数值0x90,Java 通过拓宽原始类型转换

    将byte 提升为一个int[JLS 5.1.2],然后比较这两个int 数值。0x90为144,但byte指的范围为-128~127

    故没有打印出预期的值。

    究根到底

    原来java language Specification中有自动Promotion机制,让我们了解一下数字提升的问题吧

    数字提升总体的规则是向上提升,又分为一元数字提升和二元数字提升

    一元数字提升

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

    规则如下:

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

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

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

    else 保持原样。

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

    数组创建表达式的维度

    数组索引表达式的索引

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

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

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

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

    是不是很难理解?

    小白的消费为何被迫升级-java数据类型的Promotion

     

    那就举个例子吧

    小白的消费为何被迫升级-java数据类型的Promotion

     

    class Test {
     public static void main(String[] args) {
     byte b = 2;
     int a[] = new int[b]; // dimension expression promotion
     char c = '\u0001';
     a[c] = 1; // index expression promotion
     a[0] = -c; // unary - promotion
     System.out.println("a: " + a[0] + "," + a[1]);
     b = -1;
     int i = ~b; // bitwise complement promotion
     System.out.println("~0x" + Integer.toHexString(b)
     + "==0x" + Integer.toHexString(i));
     i = b << 4L; // shift promotion (left operand)
     System.out.println("0x" + Integer.toHexString(b)
     + "<<4L==0x" + Integer.toHexString(i));
     }
    }

    输出结果为:

    a: -1,1
    ~0xffffffff==0x0
    0xffffffff<<4L==0xfffffff0

    二元数字提升

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

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

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

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

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

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

    else 两个操作数都转为int

    应用场景

    • 乘除法运算符: * 、 / 、%
    • 针对数字类型的加减运算符: + 、 -
    • 数值比较运算符:< 、<= 、> 、>=
    • 数值相等比较运算符: == 、 !=
    • 整数按位运算符: & 、^ 、|
    • 某些情况下的条件运算符 ? : 中

    来个例子吧

    class Test {
     public static void main(String[] args) {
     int i = 0;
     float f = 1.0f;
     double d = 2.0;
     // First int*float is promoted to float*float, then
     // float==double is promoted to double==double:
     if (i * f == d) System.out.println("oops");
            
     // A char&byte is promoted to int&int:
     byte b = 0x1f;
     char c = 'G';
     int control = c & b;
     System.out.println(Integer.toHexString(control));
            
     // Here int:float is promoted to float:float:
     f = (b==0) ? i : 4.0f;
     System.out.println(1.0/f);
     }
    }

    其实上面的都是冰山一角罢了

    小白的消费为何被迫升级-java数据类型的Promotion

     

    更多信息可以查看jls Chapter 5. Conversions and Contexts

    参考资料

    【1】https://docs.oracle.com/javase/specs/jls/se12/html/jls-5.html#jls-5.1.2

  • 相关阅读:
    SpringBoot及Vue3.0 登录验证码实现
    SpringBoot 文件上传、下载、显示
    Redis持久化
    Redis持久化之RDB、AOF详解
    SpringBoot AOP 记录操作日志、异常日志
    JAVA后端《持续集成 持续交付 持续部署》
    MySQL Binlog 介绍
    谷歌浏览器chrome即将在2020年底停止支持flash,我们程序员该怎么办
    年薪170万的阿里P8级员工征婚有感--话说阿里真有钱,这员工要求的条件真多
    为什么百度只抓取了首页而不抓取我的网站的内页的原因分析
  • 原文地址:https://www.cnblogs.com/davidwang456/p/11515979.html
Copyright © 2011-2022 走看看