类型转换与使用valueOf

时间:2014-08-05 07:16:04

标签: java casting standards primitive

我需要将long变量转换为double。 long变量的值不是文字,它是另一个方法返回的值,比如System.currentTimeMillis()。我需要将其转换为double进行十进制计算,例如将毫秒转换为秒,而不会丢失小数部分。

所以一种方法是使用Double.valueOf()然后将.doubleValue()输出除以1000.

long then = System.currentTimeMillis();
long now = System.currentTimeMillis();
double timeElapsed = Double.valueOf(now - then).doubleValue() / 1000;

这是正确的做法吗?或者我应该简单地按如下方式投射它们?

double timeElapsed = ((double) now - (double) then) / 1000;

我想知道哪种方法最好。

请破坏您的意见/建议。

感谢。

3 个答案:

答案 0 :(得分:4)

There is no Double.valueOf(long)

您的第一个示例中实际发生的是now - then正在计算中,结果为long,然后将其隐式地强制转换为double并传递给Double.valueOf(double) }。基本上就是这样:

double timeElapsed = Double.valueOf((double)(now - then)).doubleValue() / 1000;

如你所见,这没有任何意义!另请注意,自动取消装箱会自动将Double转换为double,因此doubleValue() 无意义。

演员是正确的方法:

double timeElapsed = (double)(now - then) / 1000.0;

只要您使用1000.0代替1000,就相当于:

double timeElapsed = (now - then) / 1000.0;

顺便提一句,Double.valueOf(double)的目的只是为了让您明确选择double并根据需要将其转换为DoubledoubleValue()的目的恰恰相反。两者都不适合您的场景。 (这通常适用于原始包装类的所有valueOf / *Value方法。)

顺便说一句,为了降低精确损失的风险(在您的情况下通常不是很大的风险),通常情况下执行以上操作会比以下更好:

double timeElapsed = ((double)now - (double)than) / 1000.0;

可以找到对您的示例中发生的事情的一些解释here。允许自动扩展原始转换,并且JLS将long分类为double作为扩展转换。

但是,longdouble案例存在风险,主要风险是并非long的所有值都可以由double表示,并且信息可以在转换中无声地丢失。考虑以下简单测试(在http://ideone.com/zCmQzg运行):

for (long a = 1; ; a *= 7) {
    long x = Double.valueOf(a).longValue();
    if (x != a) {
        System.out.println("Conversion fails at input=" + a + " output=" + x);
        break;
    }
}

此测试在某些值时会失败(例如Double.valueOf(11398895185373143L)不符合您的预期),因为long的基数2尾数超出{{1}的尾数范围,因此得到保证。 1}}。另一个简单的测试:

double

输出:

long x = 123456789123456789L;
System.out.println(x);
System.out.println(String.format("%20f", Double.valueOf(x))); // implicit
System.out.println(String.format("%20f", (double)x)); // explicit, same thing

注意最后的数字。

这种危险存在任何时间将整数转换为double,包括在上面的示例中 - 但是,值得注意的是因为将123456789123456789 123456789123456784.000000 123456789123456784.000000 传递给long在我看来,可以比其他人更能抓住一个失控的人。

答案 1 :(得分:-1)

我要去

double timeElapsed = (now - then) / 1000.0;

但是,除非你在紧密的循环中做了这么多次,否则没关系。做任何看起来最清楚的事情。

有人声称“没有Double.valueOf(长)”。好吧,Java的行为好像有Double.valueOf(2L)完全符合人们的想法。在您的代码中,除非测试运行多年,否则Double.vaueOf(now - then)将完全按照您的想法执行。我认为Double.valueOf(long)确实存在。它只是不在Javadocs中。如果我写double d = 3 + 4.5那不存在吗?

我在这里同意其他人认为Double.valueOf(现在 - 然后).doubleValue()是愚蠢的,但应该避免它,因为它增加了混乱,而不是因为它“没有用处”。随着自动装箱和拆箱的出现,许多方法没有用处,除非可能要清楚。如果你认为明确的Double让事情变得更清楚(在这个例子中,我认为不是,但你的里程可能会有所不同),你应该以这种方式编写代码。

例如,我仍然经常使用“不必要的”double primitive = someDouble.doubleValue()来提醒自己和其他程序员,否则会发生自动拆箱,并且可能会抛出神秘的NPE

答案 2 :(得分:-1)

我已经写了以下两种方法:

public static void cast() {
    long l = 123L;
    double d = (double)l / 1000;
}

public static void valueOf() {
    long l = 123L;
    double d = Double.valueOf(l) / 1000;
}

正如您所看到的,这是您的代码的简化版本;我这样做是为了让实验更清洁。

现在,我编译了代码,然后使用javap -v打印字节码:

  public static void cast();
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=4, locals=4, args_size=0
         0: ldc2_w        #2                  // long 123l
         3: lstore_0
         4: lload_0
         5: l2d
         6: ldc2_w        #4                  // double 1000.0d
         9: ddiv
        10: dstore_2
        11: return
      LineNumberTable:
        line 3: 0
        line 4: 4
        line 5: 11

  public static void valueOf();
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=4, locals=4, args_size=0
         0: ldc2_w        #2                  // long 123l
         3: lstore_0
         4: lload_0
         5: l2d
         6: invokestatic  #6                  // Method java/lang/Double.valueOf:(D)Ljava/lang/Double;
         9: invokevirtual #7                  // Method java/lang/Double.doubleValue:()D
        12: ldc2_w        #4                  // double 1000.0d
        15: ddiv
        16: dstore_2
        17: return
      LineNumberTable:
        line 8: 0
        line 9: 4
        line 10: 17

正如我们所看到的,2种方法的代码相似,但在第二种情况下,我们({预期)调用valueOf()然后调用doubleValue()

所以,似乎除非你有一些非常特殊的原因,你应该使用铸造。它在CPU使用方面更短,更清晰,更便宜。