6
public class Test {
    public static final Double DEFAULT_DOUBLE = 12.0;
    public static final Long DEFAULT_LONG = 1L;

    public static Double convertToDouble(Object o) {
        return (o instanceof Number) ? ((Number) o).doubleValue()
                : DEFAULT_DOUBLE;
    }

    public static Long convertToLong(Object o) {
        return (o instanceof Number) ? ((Number) o).longValue() : DEFAULT_LONG;
    }

    public static void main(String[] args){
        System.out.println(convertToDouble(null) == DEFAULT_DOUBLE);
        System.out.println(convertToLong(null) == DEFAULT_LONG);
    }
}
4

2 回答 2

8

编辑

三元运算符在后台进行一些类型转换。在您的情况下,您正在混合原语和包装器类型,在这种情况下,包装器类型被取消装箱,然后三元运算符的结果被“重新装箱”:

如果第二个和第三个操作数之一是原始类型 T,而另一个的类型是对 T 应用装箱转换(第 5.1.7 节)的结果,则条件表达式的类型是 T。


所以你的代码基本上等同于(除了longValue应该是的错字doubleValue):

public static void main(String[] args){
    Double d = 12.0;
    System.out.println(d == DEFAULT_DOUBLE);

    Long l = 1L;
    System.out.println(l == DEFAULT_LONG);
}

长值可以缓存在某些 JVM 上,==因此比较可以返回 true。如果你做了所有的比较,equals你会得到true这两种情况。

请注意,如果您使用public static final Long DEFAULT_LONG = 128L;并尝试:

Long l = 128L;
System.out.println(l == DEFAULT_LONG);

它可能会打印错误,因为 Long 值通常只缓存在 -128 和 +127 之间。

注意:JLS要求缓存char,byteint-127 到 +128 之间的值,但没有说明long. 因此,您的代码实际上可能会在不同的 JVM 上打印两次 false。

于 2013-02-06T02:23:17.370 回答
4

要了解这种奇怪的行为,您需要分开它的作用:

(o instanceof Number) ? ((Number) o).longValue() : DEFAULT_LONG

我们这里有一个对方法的调用,该方法返回一个long和一个 的实例Long。两种不同的类型。然而,条件运算符?需要产生单一类型;要么long要么Long。为了做到这一点,第二个操作数必须被装箱或第三个操作数必须被取消装箱。

在这种情况下,JLS 说第三个操作数必须被取消装箱。 JLS 15.25

“如果第二个和第三个操作数之一是原始类型 T,而另一个的类型是对 T 应用装箱转换(第 5.1.7 节)的结果,则条件表达式的类型是 T。”

这意味着您的常量被拆箱然后再次装箱。

现在,通过调用装箱类型的valueof()方法来装箱原始类型。这些方法根据基本类型做的事情略有不同。

  • 对于浮点类型,valueof总是创建一个新对象
  • 对于整数类型,该valueof方法有时会创建一个新对象,有时会返回一个现有对象。

后者就是这里发生的事情。 Long.valueof(1L)总是返回相同的值,与的比较==是给true.


有两个“修复”......假设你想解决这个问题:

  • 在两个分支中用if/else替换三元运算符。return
  • 强制第二个操作数被装箱:

    return (o instanceof Number) ? 
            (Long) ((Number) o).longValue() : DEFAULT_LONG;
    
于 2013-02-06T02:35:13.463 回答