【问题标题】:I new an Integer instance but it gives me a Long instance [duplicate]我新建了一个 Integer 实例,但它给了我一个 Long 实例 [重复]
【发布时间】:2014-04-30 16:37:19
【问题描述】:

最近遇到一个Java的坑,代码在这里:

    Number value = new Integer(10);
    value = value instanceof Long ? new Long(-value.longValue()) : new Integer(-value.intValue());

    System.out.println(value instanceof Integer);
    System.out.println(value.getClass());

我认为输出是:

是的
类 java.lang.Integer

但是,我错了,正确的输出正好相反:


类 java.lang.Long

我不明白为什么。所以我用javap -c反汇编了类文件,下面两行(指令)对我来说很奇怪:

50: i2l           
51: invokestatic  #10                 // Method java/lang/Long.valueOf:(J)Ljava/lang/Long;

为什么?我想要与对象value 相同的实例,为什么它给了我不同的?

非常感谢您的帮助。

【问题讨论】:

  • 条件运算符的结果类型不能超过一个,总是一个,在编译时决定。
  • 如果您将两个结果都转换为 Number,那么它应该可以按预期工作。上面的应该给出一个编译错误,因为Integer不能转换为Long,但是javac做了一些奇怪的事情。
  • 这是一个很好的例子,说明为什么不应该使用三元运算符;因为你不懂三元运算符。只需使用 if 语句,因为 a) 你理解它 b) 它被初级 Java 开发人员理解(而三元则不是)

标签: java


【解决方案1】:

三元运算符 ? 接受两个操作数,即 new Long(-value.longValue())new Integer(-value.intValue() )

根据Java语言规范http://docs.oracle.com/javase/specs/jls/se8/html/jls-5.html#jls-5.6.2,两个操作数都将首先被拆箱(Long->long)和(Integer->int),参见http://docs.oracle.com/javase/specs/jls/se8/html/jls-5.html#jls-5.1.8,然后应用以下规则:

如果任一操作数是 double 类型,则另一个操作数将转换为 double。 否则,如果任一操作数的类型为浮点型,则另一个将转换为浮点型。 否则,如果任一操作数是 long 类型,则另一个将转换为 long。 否则,两个操作数都转换为 int 类型。

由于在拆箱步骤之后,您的操作数之一是 long 类型,因此另一个将转换为 long。这应该可以解释你的结果。

【讨论】:

    【解决方案2】:

    编译器需要格式化你的条件语句以返回一个类型并且不超过一个:

    value = value instanceof Long ? new Long(-value.longValue()) : new Integer(-value.intValue());
    

    三元运算符需要决定强制转换两种可能的返回类型之一,以便返回类型一致。

    我发现以与编写方法相同的方式理解这一点最简单:

    public Long getNumber(int n) {
        if (value instanceof Long) {
            return new Long(-value.longValue());
        } else {
            return new Integer(-value.intValue()); // Not consistent with return type
        }
    }
    

    您需要在此实例中指定一致的返回类型。如果您将它们全部返回为Number,它应该可以正常工作:

    public Number getNumber(int n) {
        if (value instanceof Long) {
            return (Number) new Long(-value.longValue());
        } else {
            return (Number) new Integer(-value.intValue());
        }
    }
    

    同样:

    value = value instanceof Long ? (Number) new Long(-value.longValue()) : (Number) new Integer(-value.intValue());
    

    为您提供所需的输出。

    概述了 Java 三元运算符如何决定这些转换的规则here in the Java Docs

    它们是基于信息保存的逻辑:

    If either operand is of type double, the other is converted to double.
    
    Otherwise, if either operand is of type float, the other is converted to float.
    
    Otherwise, if either operand is of type long, the other is converted to long.
    
    Otherwise, both operands are converted to type int.
    

    只是为了说明这些规则背后的逻辑,以免它们看起来那么随意。

    Double 具有先例,因为它是最具体的,即您可以想象将double 切割成int 会丢失信息((int) 0.555 -> 0),而不是将int 转换为double不会丢失信息((double) 1 -> 1.0

    然后Float,因为float 的精度低于double,但高于longint

    接下来是long,因为它是更精确的版本int,最后它们被视为ints

    因此,由于int 是最不具体的,它通常会转换为其他Number 格式。

    【讨论】:

      猜你喜欢
      • 2020-05-28
      • 1970-01-01
      • 1970-01-01
      • 2019-02-22
      • 1970-01-01
      • 2014-04-21
      • 2015-12-25
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多