3

我有 2 个问题。

1)有人告诉我,在比较两个FloatorDouble数据时,使用compareTo代替equals. 我不知道原因。是否有任何示例表明使用equals会导致错误?

2)查看此代码:

  float f2=(float)1.123450;
  Float f3=new Float(1.123450);

  System.out.println(f3==f2);   // result is true

我认为 using==意味着两个数据指向相同的内存地址。但是f3f2相同的地址吗?不new Float(...)创造一个新的空间?

4

3 回答 3

12

如果两个参数都是引用类型,那么==将测试内存位置。但是,如果==(or !=) 的参数之一是数字,而另一个可转换为数字(使用拆箱),则通过在拆箱后比较数值来完成比较。因此,这种情况下的比较是基于浮点值(在这种情况下是相同的)进行的。有关详细信息,请参阅Java 语言规范 §15.21.1

但是请注意,这Float.NaN == Float.NaNfalse.

于 2012-10-25T14:53:09.230 回答
8

一般来说==,除非您需要处理舍入或算术错误,否则 compareTo() 对您没有多大帮助。

如果你想在一个错误中比较两个双打,你可以使用

if (Math.abs(a - b) < ERR) // within error.

或相对误差

if (Math.abs(a - b) < ERR * (Math.abs(a) + Math.abs(b))/2) // within error.

或在四舍五入内,该因子是否通常是十的幂,如 10000 意味着小数点后 4 位。

if (Math.round(a * factor) == Math.round(b * factor)) // within a multiple
于 2012-10-25T14:54:24.887 回答
2

在 Java 中,您有两种(主要)类型,

  1. 原语
  2. 参考

    当且仅当它们的类型为doublefloatintlong等时,基本类型才被视为基本类型。

    引用类型是任何使用“对象”来存储数据的类型。当您在课堂上创建时,您实际上是在“变相”创建引用类型。引用类型的一些示例是StringDoubleInteger等。

    因此,就类型而言,当您比较float xFloat y,您实际上是在比较两种不同的类型!

    在 Java 中,==' 运算符大多数时候只比较相同类型的对象。然而,有时,该语言将允许比较其他类型,例如x == yx原始类型和y引用类型(如上定义)的情况下。

    x当执行和之间的比较时,y执行称为装箱和拆箱的操作。但是要理解装箱,就必须了解原始类型和引用类型在内存语义方面的区别。(不要让那吓到你!)

    原始类型存储在称为堆栈的内存位置中,这在碎片访问方面速度很快且不是很灵活。这很容易。

    但是引用类型是不同的:当使用操作符实例化new引用类型时(在做时隐式调用Float x = <something>;- 即Float x = <something>;转换为Float x = new Float(<something>);)所以当Float实例化一个或其他引用类型时,对象被创建并存储在堆上,但指向该对象(位于堆上)的指针存储在堆栈中。

    这意味着为了检索存储在 中的值,x计算机必须使用存储在堆栈中的地址,并转到堆中的该内存地址。

    我们使用堆来存储引用类型,因为堆栈不太擅长所谓的“动态内存分配”,即在不关心周围其他对象的情况下分配和释放内存。

    现在进行装箱和拆箱:

    装箱(也称为包装)是获取原始类型对象并将其存储为引用类型(因此float x成为Float x)的过程,因此这两个对象是相同的类型。(这有点像用纸包圣诞礼物)所以,在幕后,Integer k = 6是一种拳击(自动装箱)

    另一方面,拆箱与拆箱相反,因此您可以将其称为拆箱。拆箱采用“装箱”对象并将其从引用类型带回原始类型,因此语句可以毫不费力地工作:

    Integer k = 6; //Boxing

    int m = k; //Unboxing

    就您的问题而言,这真正意味着什么:在您发布的代码中,发生了自动装箱和拆箱,这使得该声明有效。JVM 足够聪明,可以按照你的意思去做——但这并不意味着你应该养成它的常规习惯,因为装箱和拆箱会对代码的性能产生严重影响!

    此外,如果两者x都是y类型Float,您将比较参考!

    祝你好运!

于 2012-10-25T15:16:31.323 回答