Java 纯新手,问个关于类型的问题 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
zhoudaiyu
V2EX    Java

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

  •  
  •   zhoudaiyu
    PRO
    2020-03-22 08:20:37 +08:00 via iPhone 5230 次点击
    这是一个创建于 2031 天前的主题,其中的信息可能已经有所发展或是发生改变。

    图中的第一个 println 为啥打印的是 1.0 而不是 1?这个表达式应该永远执行 Integer.valueOf(1)吧?为什么被强转成 float 了?
    27 条回复    2020-03-23 17:52:11 +08:00
    Cbdy
        1
    Cbdy  
       2020-03-22 08:24:04 +08:00 via Android
    因为这两行调用的是两个不同的 println,和 Java 方法的重载机制有关
    zhoudaiyu
        2
    zhoudaiyu  
    OP
    PRO
       2020-03-22 08:34:54 +08:00 via iPhone
    @Cbdy 怎么讲?
    hanshijun
        3
    hanshijun  
       2020-03-22 08:35:53 +08:00
    三目运算符会进行自动类型上升
    aneureka
        4
    aneureka  
       2020-03-22 08:37:33 +08:00 via iPhone
    因为你这个三元表达式返回的是 float,就算你返回的值是 int 也会被类型转换为 float
    xuanbg
        5
    xuanbg  
       2020-03-22 08:54:25 +08:00
    三元表达式的结果必须是同一个类型。在这里 integer 被隐式转换成 float 了。
    humpy
        6
    humpy  
       2020-03-22 09:03:19 +08:00   27
    两个操作数分别是 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 expressios 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
        7
    zhoudaiyu  
    OP
    PRO
       2020-03-22 09:04:30 +08:00
    @humpy 好详细啊,太感谢了
    geelaw
        8
    geelaw  
       2020-03-22 09:30:33 +08:00   5
    @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
        9
    hhhsuan  
       2020-03-22 11:38:33 +08:00
    又学会一种回字的写法
    ae86
        10
    ae86  
       2020-03-22 12:19:16 +08:00
    路过,跟着楼主一起学习
    yeqizhang
        11
    yeqizhang  
       2020-03-22 14:18:21 +08:00 via Android
    这种问题没遇到还真不知道,网上教程也没看到提到过。之前有网上做面试题,有一道题就是这个,我做错了,这面试题真偏……
    table cellpadding="0" cellspacing="0" border="0" width="100%"> shuqin2333
        12
    shuqin2333  
       2020-03-22 16:15:54 +08:00
    学习了
    zxCoder
        13
    zxCoder  
       2020-03-22 18:59:38 +08:00
    学习了
    lewis89
        14
    lewis89  
       2020-03-22 19:38:38 +08:00
    @zhoudaiyu #2 你用 Command + B 可以点进去 看下重载到哪个函数了
    banmuyutian
        15
    banmuyutian  
       2020-03-22 20:12:05 +08:00
    学习了
    jiom
        16
    jiom  
       2020-03-22 22:52:36 +08:00
    学习了
    757384557
        17
    757384557  
       2020-03-23 09:04:59 +08:00
    第一次看到这种问题,学习了
    niu0619
        18
    niu0619  
       2020-03-23 09:55:56 +08:00
    学习了
    yuanshuai1995
        19
    yuanshuai1995  
       2020-03-23 11:02:48 +08:00
    学写了
    yibinhp
        20
    yibinhp  
       2020-03-23 11:19:07 +08:00
    学写了
    wozhizui
        21
    wozhizui  
       2020-03-23 11:52:09 +08:00
    学习了,
    pengjl
        22
    pengjl  
       2020-03-23 14:20:03 +08:00
    学习了
    sunziren
        23
    sunziren  
       2020-03-23 16:30:02 +08:00
    学到老,活到老
    sunziren
        24
    sunziren  
       2020-03-23 16:30:16 +08:00
    学到老,活到老,学习了
    rancc
        25
    rancc  
       2020-03-23 17:04:32 +08:00
    学习了
    gotonull
        26
    gotonull  
       2020-03-23 17:30:36 +08:00
    学习了
    zhiguang
        27
    zhiguang  
       2020-03-23 17:52:11 +08:00
    又能 zb 了
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2929 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 36ms UTC 14:33 PVG 22:33 LAX 07:33 JFK 10:33
    Do have faith in what you're doing.
    ubao snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86