Java 纯新手,问个关于类型的问题

2020-03-22 08:20:37 +08:00
 zhoudaiyu

图中的第一个 println 为啥打印的是 1.0 而不是 1 ?这个表达式应该永远执行 Integer.valueOf(1)吧?为什么被强转成 float 了?
4593 次点击
所在节点    Java
27 条回复
Cbdy
2020-03-22 08:24:04 +08:00
因为这两行调用的是两个不同的 println,和 Java 方法的重载机制有关
zhoudaiyu
2020-03-22 08:34:54 +08:00
@Cbdy 怎么讲?
hanshijun
2020-03-22 08:35:53 +08:00
三目运算符会进行自动类型上升
aneureka
2020-03-22 08:37:33 +08:00
因为你这个三元表达式返回的是 float,就算你返回的值是 int 也会被类型转换为 float
xuanbg
2020-03-22 08:54:25 +08:00
三元表达式的结果必须是同一个类型。在这里 integer 被隐式转换成 float 了。
humpy
2020-03-22 09:03:19 +08:00
两个操作数分别是 Integer 类型和 Float 类型,根据 [jls-15.25.2]( https://docs.oracle.com/javase/specs/jls/se14/html/jls-15.html#jls-15.25.2 ),条件表达式的结果类型是两个操作数类型提升后的类型:

「 Otherwise, general numeric promotion (§5.6) is applied to the second and third operands, and the type of the conditional expression is the promoted type of the second and third operands.」


根据 [jls-5.6]( https://docs.oracle.com/javase/specs/jls/se14/html/jls-5.html#jls-5.6 ) 描述的类型提升规则:

1. 两个操作数拆包;
2. 拆包后,一个操作数是 int,一个是 float,将 int 扩展为 float


1. If any expression is of a reference type, it is subjected to unboxing conversion ( §5.1.8 ).
2. Next, widening primitive conversion ( §5.1.2 ) and narrowing primitive conversion ( §5.1.3 ) are applied to some expressions, according to the following rules:
• If any expression is of type double, then the promoted type is double, and other expressions that are not of type double undergo widening primitive conversion to double.
• Otherwise, if any expression is of type float, then the promoted type is float, and other expressions that are not of type float undergo widening primitive conversion to float.


因此这个语句最终的结果是 float 。


---
可以写一段简单的代码看一下这个过程:

❯ cat a.java
class a {

public static void main(String[] args) {
System.out.println(true ? Integer.valueOf(1) : Float.valueOf(3));
}
}

查看它编译后的字节码,可以看到「 10: i2f 」这行确实做了 int -> float 的类型提升:

❯ javap -v a.class
...
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=1, args_size=1
0: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
3: iconst_1
4: invokestatic #3 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
7: invokevirtual #4 // Method java/lang/Integer.intValue:()I
10: i2f
11: invokevirtual #5 // Method java/io/PrintStream.println:(F)V
14: return
zhoudaiyu
2020-03-22 09:04:30 +08:00
@humpy 好详细啊,太感谢了
geelaw
2020-03-22 09:30:33 +08:00
@humpy #6 感谢查阅文档,值得注意的是这里的类型转换会尝试 unbox,导致 cond ? a : b 里面若 a 、b 具有原始类型的引用版本且其中一个是 null,则可能导致意外的空引用异常,这个可以加入 Java 反人类设计之一了。

public class HelloWorld
{
public static void main(String[] args)
{
System.out.println((Integer)null);
System.out.println((Object)(Integer)null);
System.out.println((Float)null);
System.out.println((Object)(Float)null);
System.out.println(true ? (Object)(Integer)null : Float.valueOf(1.0f));
System.out.println(true ? (Integer)null : (Object)Float.valueOf(1.0f));
// 下面这行会抛出异常
System.out.println(true ? (Integer)null : Float.valueOf(1.0f));
}
}

相应的,在 C# 里则无此问题——大多数情况下无法产生声明类型是值类型但被当作引用类型的表达式。最接近的两个情况:

可空类型的转换是正常的(这点比 Java 自然很多),表达式 true ? (int?)null : (float?)1.0f 等同于 (float?)null 。

值为装箱后的值类型的引用类型转换是正常的(这点同 Java ),表达式 true ? (IConvertible)(int?)null : (float?)1.0f 等同于 (object)null 。
hhhsuan
2020-03-22 11:38:33 +08:00
又学会一种回字的写法
ae86
2020-03-22 12:19:16 +08:00
路过,跟着楼主一起学习
yeqizhang
2020-03-22 14:18:21 +08:00
这种问题没遇到还真不知道,网上教程也没看到提到过。之前有网上做面试题,有一道题就是这个,我做错了,这面试题真偏……
shuqin2333
2020-03-22 16:15:54 +08:00
学习了
zxCoder
2020-03-22 18:59:38 +08:00
学习了
lewis89
2020-03-22 19:38:38 +08:00
@zhoudaiyu #2 你用 Command + B 可以点进去 看下重载到哪个函数了
banmuyutian
2020-03-22 20:12:05 +08:00
学习了
jiom
2020-03-22 22:52:36 +08:00
学习了
757384557
2020-03-23 09:04:59 +08:00
第一次看到这种问题,学习了
niu0619
2020-03-23 09:55:56 +08:00
学习了
yuanshuai1995
2020-03-23 11:02:48 +08:00
学写了
yibinhp
2020-03-23 11:19:07 +08:00
学写了

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/655007

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX