我新增了一个Integer实例,但它给了我一个Long实例

时间:2014-04-30 16:37:19

标签: java

最近,我遇到了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());

我认为输出是:


class java.lang.Integer

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


class java.lang.Long

我无法理解为什么。所以我使用javap -c反汇编类文件,以下两行(说明)对我来说很奇怪:

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

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

非常感谢您的帮助。

2 个答案:

答案 0 :(得分:2)

三元运算符接收两个操作数,即 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。 否则,如果任一操作数的类型为float,则另一个操作数转换为float。 否则,如果任一操作数的类型为long,则另一个操作数转换为long。 否则,两个操作数都将转换为int。

由于在取消装箱步骤之后,其中一个操作数的类型为 long ,另一个操作数将转换为long。这应该可以解释你的结果。

答案 1 :(得分:1)

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

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)而不是转换intdouble不会丢失任何信息((double) 1 -> 1.0

然后Float,因为float的精确度低于double但超过longint

接下来是

long,因为它是更精确的版本int,最后它们被视为int s

因为int是最不具体的,所以通常会转换为其他Number格式。