2012-10-25 44 views
1

我有2个问题。java float:== equals compareTo

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

2)见以下代码:

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

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

我想使用==指两个数据点到同一存储器地址。但是f3f2具有相同的地址吗? new Float(...)是否创造了新的空间?

+0

有点相关:http://stackoverflow.com/questions/1551235/java-strings-compareto-vs-equals?rq=1 –

+0

什么f1.equals(F2)给? – smk

+0

从[该文档(http://docs.oracle.com/javase/6/docs/api/java/lang/Float.html#compareTo(java中。lang.Float)):“这个方法施加的Float对象的自然排序['compareTo']与'equals'一致。” –

回答

7

如果两个参数都引用类型,然后==将测试的存储器位置。然而,如果其中一个参数到==(或!=)是数字,另一种是转换为数字(使用拆箱),那么比较是通过开箱后比较数值进行。所以在这种情况下的比较是基于浮点值(在这种情况下是相同的)进行的。详细信息请参见Java Language Specification §15.21.1

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

+6

另外请注意,一般来说,你想比较两个浮动/双打,看看他们是否非常接近,而不是如果他们完全相等。这是由于浮点数可能累加的舍入误差,特别是当十进制数不能精确地表示为浮点数(例如0.1)时。 – yshavit

+0

@yshavit - 是的,这是一个非常好的观点,在讨论“equals”,“compareTo”和“==”之间的差异时,迷失于单个值。 (但是,我现在看到彼得改变了他的回应,专注于这一点。) –

5

一般来说==,除非你需要处理的舍入或运算错误,在这种情况下的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 
+2

来自[Float.equals()的文档](http://docs.oracle.com/javase/6/docs/api/ java/lang/Float.html#equals(java.lang.Object)):_“如果'f1'和'f2'都表示'Float.NaN',那么equals方法返回'true',即使'Float。 NaN == Float.NaN'的值为“false”。“_ –

0

在Java中,你有两个(主)类型,

  1. 基元
  2. 参考

    原始类型被认为是原语,当且仅当它们double类型,floatint,long等等。

    引用类型是一种使用“对象”来存储数据的任何类型。当你在课堂上创作时,你真的创造了一个“伪装”的参考类型。参考类型的一些示例是String,Double,Integer等等。

    所以,就类型而言,当你比较float xFloat y,你真的比较了两种不同的类型!

    在Java中,==的运营商,大部分的时间,只比较平等类型的对象。然而,有时该语言将允许其它类型的比较,如在x == y的情况下x是一个原始和y为引用类型(如上所定义)。

    当执行xy之间的比较时,执行称为装箱和拆箱的操作。但要理解拳击,你必须从内存语义的角度理解基本类型和引用类型之间的区别。 (不要让这种吓唬你!)

    基本类型存储在内存位置称为栈,这是速度快,在支离破碎的准入方面不是很灵活。这很容易。

    引用类型是不同的,但:当引用类型是使用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很聪明,你的意思是什么 - 但是,这并不意味着你应该做的是日常习惯,因为装箱和拆箱可以对你的代码的性能造成严重影响!

    此外,如果xy都是Float类型,那么您会比较参考文献!

    祝你好运!