我有两个问题。
1)有人告诉我,在比较两个Float
或Double
数据时,请使用compareTo
代替equals
。我不知道原因。是否有任何示例显示使用equals
导致错误的地方?
2)参见此代码:
float f2=(float)1.123450;
Float f3=new Float(1.123450);
System.out.println(f3==f2); // result is true
我认为使用==
意味着两个数据指向相同的内存地址。但f3
和f2
的地址是否相同? new Float(...)
不会创建新空间吗?
答案 0 :(得分:9)
如果两个参数都是引用类型,那么==
将测试内存位置。但是,如果==
(或!=
)的其中一个参数是数字而另一个可转换为数字(使用拆箱),则通过比较拆箱后的数值来完成比较。因此,在这种情况下的比较是基于浮点值(在这种情况下是相同的)来完成的。有关详细信息,请参阅Java Language Specification §15.21.1。
但请注意,Float.NaN == Float.NaN
为false
。
答案 1 :(得分:6)
一般来说,==
是正常的,除非您需要处理舍入或算术错误,在这种情况下,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的幂,如10000意味着小数点后4位。
if (Math.round(a * factor) == Math.round(b * factor)) // within a multiple
答案 2 :(得分:1)
在Java中,您有两种(主要)类型
参考
当且仅当它们属于double
,float
,int
,long
等类型时,原始类型才被视为原始类型。
引用类型是使用“Object”存储数据的任何类型。当你在课堂上创作时,你真的是在“伪装”中创建一个引用类型。参考类型的一些示例包括String
,Double
,Integer
等。
因此,就类型而言,当您将float x
与Float y
进行比较时,您实际上是在比较两种不同的类型!
在Java中,==
的运算符(大多数情况下)只比较相同类型的对象。但是,有时,语言将允许比较其他类型,例如x == y
是x
是基元而y
是引用类型(如上所定义)的情况。
当执行x
和y
之间的比较时,执行称为装箱和拆箱的操作。但要理解拳击,你必须从内存语义的角度理解原始类型和引用类型之间的区别。 (不要让那吓到你!)
原始类型存储在称为堆栈的内存位置,这在碎片访问方面速度快且不灵活。这很容易。
引用类型不同:当引用类型实例化时使用new
运算符(在执行Float x = <something>;
时隐式调用) - 即{{1转换为Float x = <something>;
)因此,当实例化Float x = new Float(<something>);
或其他引用类型时,对象被创建并存储在堆上,但指向该对象(在堆上)的指针是存储在堆栈中。
这意味着为了检索存储在Float
中的值,计算机必须使用存储在堆栈中的地址,并转到堆中的该内存地址。
我们使用堆来存储引用类型,因为堆栈在称为“动态内存分配”的东西上不是很好,这是分配和释放内存而不关心它周围的其他对象的地方。
现在进行拳击和拆箱:
拳击(也称为包装)是获取原始类型对象并将其存储为引用类型(因此x
变为float x
)的过程,因此这两个对象是相同的类型。 (这有点像用纸包装圣诞礼物)所以,在幕后,Float x
是一种拳击(自动装箱)
Integer k = 6
Integer k = 6; //Boxing
就您的问题而言,这实际上意味着什么:在您发布的代码中,发生了自动装箱和拆箱,这使得该语句有效。 JVM非常聪明,能够做到你的意思 - 但这并不意味着你应该养成它的常规习惯,因为装箱和拆箱会对你的代码性能产生严重影响!
此外,如果int m = k; //Unboxing
和x
都是y
类型,那么您将比较参考资料!
祝你好运!