背景

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

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

本来小白预期输出结果:

life is Happy!

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

于是小白向柯南请教:

破案

为了比较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。

是不是很难理解?

那就举个例子吧

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);
}
}

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

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

参考资料

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

小白的消费为何被迫升级?-java数据类型的转换的更多相关文章

  1. Java数据类型的转换:隐式(自动)转换与强制转换

    原文链接:http://java.chinaitlab.com/base/725590.html 一些初学JAVA的朋友可能会遇到JAVA的数据类型之间转换的苦恼,例如,整数和float,double ...

  2. JAVA数据类型,变量,转换,常量,运算符

    java数据类型: Java基本类型共有八种,基本类型可以分为三类: 1.字符类型char,用单引号赋值 2.布尔类型boolean 3.数值类型byte.short.int.long.float.d ...

  3. Java学习笔记之:Java数据类型的转换

    一.介绍 数据类型的转换,分为自动转换和强制转换.自动转换是程序在执行过程中“悄然”进行的转换,不需要用户提前声明,一般是从位数低的类型向位数高的类型转换:强制类型转换则必须在代码中声明,转换顺序不受 ...

  4. Java数据类型及其转换&&经常用到的快捷键

    数据类型 基本数据类型分类 (8种) byte .short. int. long. char. float. double .boolean 1个字节占8位   整数型byte 1字节 -128~1 ...

  5. Java数据类型的转换

    Java数据类型,从小到大排序 byte ,short ,int ,long ,float, double,char 1.小数据类型转换大的数据类型,自动转换 int a = 3; double b ...

  6. JAVA数据类型自动转换,与强制转换

    一.数据类型自动转换 public class Test{ public static void main(String[] args){ int a = 1; double b = 1.5; dou ...

  7. Java基本语法-----java数据类型的转换

    前言 Java中可以进行不同数据类型的加减乘除运算吗?是可以的.在算术运算符中已经体验过如果两个整数(int)相除会去掉小数部分.如果需要保留小数部分,可以让除数或者被除数变为double类型的(5变 ...

  8. Java 数据类型及转换

    整形: byte(1个字节) 范围:-128~127 short(2个字节) 范围:-215~215-1 (-32768~32767) int(4个字节) 范围:-231~231-1 (-214748 ...

  9. Java数据类型 及 转换原则

    一.数据类型分类:主要分为 基本类型.引用类型两大类: 二.基本类型 转换原则 1.类型转换主要在在 赋值.方法调用.算术运算 三种情况下发生. a.赋值和方法调用 转换规则:从低位类型到高位类型自动 ...

随机推荐

  1. 【Java例题】7.5 文件题2-学生成绩统计

    5.学生成绩统计.已有一个学生成绩文件,含有多位学生的各三门课的成绩:读取这个文件中的每位学生的三门课成绩,然后计算均分:最后对这些均分按照大于或小于75分的界限,分别写到另两个文件中. packag ...

  2. 通过jmeter发送webservice接口请求

    1.webservice接口地址:http://ip:port/...?wsdl 2.接口数据类型:<cuxGmiChukuRmaTrxV><salesrepId xmlns:xsi ...

  3. 数据结构之堆栈java版

    import java.lang.reflect.Array; /* 具体原理在c++版已经说的很清楚,这里不再赘述, 就提一点:java的泛型具有边界效应,一旦离开作用域立马被替换为object类型 ...

  4. JVM实战---类加载的过程

    任何程序都需要加载到内存才能与CPU进行交流 同理, 字节码.class文件同样需要加载到内存中,才可以实例化类 ClassLoader的使命就是提前加载.class 类文件到内存中 在加载类时,使用 ...

  5. 使用Jasypt对SpringBoot配置文件加密

    # **前言** 在日前安全形势越来越严重的情况下,让我意识到在项目中存在一个我们经常忽略的漏洞,那就是我们的项目的配置文件中配置信息的安全,尤其是数据库连接的用户名和密码的安全.所以这里我们就需要对 ...

  6. Go中的指针

    学Java以来,让程序员忽略了指针和内存地址这些概念,Java帮我们封装了对象,简化了对象引用之间的关系.在Go语言中,又帮我们回忆起这些概念. 我们创建的每一个对象在内存中都有一个位置去存储,每个内 ...

  7. 低版本IE兼容 H5+CSS3 方案

    [主要是针对ie6 7 8对支持和让老浏览器支持html5+css3的一些js脚本] html5shiv.js  // 让IE8及耕地版本的IE识别section,article,nav等html5元 ...

  8. python编写环境(种类)

    python编写环境(种类) 官方推荐 cpython 转成C的字节码 jython转成Java的字节码 ironpython转成C#字节码 pypy转换成动态编译 开发快,运行快

  9. Spring.Net 依赖注入

    一.Spring.Net概念 编程模型(Ioc,DI方式) IoC:控制反转 原来创建对象的权利由程序来控制就是new实例,IoC就是改由容器来创建,相当于一个工厂, DI:依赖注入 没有IoC就没有 ...

  10. (三十二)c#Winform自定义控件-表格

    前提 入行已经7,8年了,一直想做一套漂亮点的自定义控件,于是就有了本系列文章. 开源地址:https://gitee.com/kwwwvagaa/net_winform_custom_control ...