社交媒体

数据类型与三个转换大坑

数据类型与三个转换大坑

钩子:1500 塞进 byte,变成了负数

先看一段代码:

int i = 1500;
byte j = (byte) i;
System.out.println(j);

输出是 -36。

image-HKHF.png

1500 好好的,塞进 byte 就成了负数。没有报错,没有警告,程序照常跑,数据已经错了。

这是 Java 类型转换的第一个坑。这一篇我们把 8 种基本类型和转换规则一次讲清楚,顺便把新手最容易踩的坑提前排掉。

01 Java 数据类型的分类

Java 的数据类型分两大类:基本数据类型和引用数据类型。

基本类型一共 8 种,先看这张表,建议收藏:

分类 类型 字节 取值范围
整数 byte 1 -128 ~ 127
整数 short 2 -32,768 ~ 32,767
整数 int 4 约 ±21 亿
整数 long 8 约 ±9.2 × 10^18
浮点 float 4 约 ±3.4 × 10^38(7 位有效数字)
浮点 double 8 约 ±1.8 × 10^308(15 位有效数字)
字符 char 2 Unicode 所有字符
布尔 boolean - true / false

几个新手常问的点:

  • int 是 Java 里整数的默认类型,你直接写 100,它就是 int。
  • double 是小数的默认类型。float 赋值要加 f:float f = 1.5f,不加直接编译报错。
  • boolean 只有 true 和 false,它和数字之间没有转换关系,这点和 C 语言不一样。
  • long 赋值建议加大写 L:long t = 100000000000L。小写 l 的话,1l 看起来太像 11,别问我是怎么知道的。

02 自动类型转换,小转大随便转

容量小的类型可以自动转成容量大的类型,编译器不拦你:

07-自动类型转换方向图.png

byte → short → int → long → float → double

char 也能自动转成 int,比如字符 a 参与运算时会自动变成 97。

方向记住就行:小的往大的流。

有人会问,long 是 8 个字节,float 才 4 个字节,为什么 long 能自动转 float?因为 float 的存储方式是"有效数字 + 指数",能表示的范围比 long 大得多,只是精度不如 long。所以 long 转 float 也会丢精度,记住这个伏笔。

03 强制类型转换,坑全在这一节

反方向转就要强制转换,语法是把目标类型写在括号里。

坑 1:溢出,数据悄悄变错

就是开头那段代码:

int i = 1500;
byte j = (byte) i;
System.out.println(j); // -36

byte 只保留 int 的最低 8 位。1500 的二进制低 8 位是 220,按有符号数解释就是 -36。

数据没有丢在明面上,它直接错了。数据库 id、金额、时间戳,这些字段一旦溢出都是线上事故。所以选类型之前先想清楚数据的量级。

坑 2:精度,小数说没就没

double d = 99.5;
int m = (int) d;
System.out.println(m); // 99

强制转 int 不四舍五入,直接砍掉小数部分。想要四舍五入,用 Math.round(d)。

坑 3:编译器比你想象中严格

byte b = 10;
b = b + 1; // 编译报错

右边 b + 1 的结果是 int 类型,往 byte 里塞需要强制转换,编译器直接报 incompatible types。新手经常在这卡半小时。写全就是这样:b = (byte)(b + 1),不过实际开发里建议直接用 int。

04 引用类型的转换,先知道有这么回事

这块后面讲面向对象时还会细说,现在先记两句:

  • 子类转父类(向上转型)是自动的,Dog 当 Animal 用没问题。
  • 父类转子类(向下转型)要强转,转之前用 instanceof 检查,不然运行时会抛 ClassCastException。
Animal a = new Dog();
Dog d = (Dog) a;   // 没问题,a 本来就是 Dog

Animal a2 = new Cat();
Dog d2 = (Dog) a2; // 编译能过,运行直接抛异常

05 和 String 互转,天天都在用

int 转 String:

String s1 = String.valueOf(i);
String s2 = "" + i; // 偷懒写法,面试可以说说原理

String 转 int:

int i1 = Integer.parseInt(s);

注意 parseInt 遇到 "abc" 这种会抛 NumberFormatException,解析用户输入前记得 try 一下。

基本类型和包装类(Integer、Double 这些)的互转就是自动装箱拆箱,留到讲集合的时候细说。现在记住两个方向就行:Integer.valueOf(a) 把 int 变 Integer,a.intValue() 把 Integer 变回 int。


本文示例代码均已本地实测通过,可直接运行。

系列下一篇:《运算符与 i++ 的坑》——有个坑和今天的三号坑是亲戚,先剧透一句:++i 和 i++ 在面试里出现频率极高。


橙码酱,分享更有用的技术知识,助你成为更优秀的开发者。