Reputation: 149
I have 2 questions.
1) I was told that when comparing two Float
or Double
data, use compareTo
instead of equals
. I don't know the reason. Is there any example that shows where using equals
will lead something wrong?
2) See this code:
float f2=(float)1.123450;
Float f3=new Float(1.123450);
System.out.println(f3==f2); // result is true
I think using ==
means the two data point to the same memory address. But do f3
and f2
have the same address? Doesn't new Float(...)
create a new space?
Upvotes: 4
Views: 10789
Reputation: 1062
In Java, you have two (primary) types,
Reference
Primitive types are considered primitives if and only if they are of type double
, float
, int
, long
, and so on.
Reference types are any type that uses an "Object" to store data. When you are creating in class, you're really creating a reference type "in disguise." Some examples of reference types are String
, Double
, Integer
, and so on.
So, as far as types go, when you compare float x
to Float y
, you're really comparing two different types!
In Java, the ==
's operator, most of the time, to compare only objects of equal type. Sometimes, however, the language will permit comparison of other types, such as x == y
in the case that x
is a primitive and y
is a reference type (as defined above).
When the comparison between x
and y
is performed an operation called boxing and unboxing is performed. But to understand boxing, you have to understand the difference between primitive types and reference types in terms of memory semantics. (Don't let that scare you!)
Primitive types are stored in a memory location called the stack, which is fast and not very flexible in terms of fragmented access. It's pretty easy.
Reference types are different though: when a reference type is instantiated using the new
operator (which is called implicitly when doing Float x = <something>;
-- that is, Float x = <something>;
is turned into Float x = new Float(<something>);
) So when a Float
or other reference type is instantiated, the object is created and stored on the heap, but the pointer to that object (which is on the heap) is stored in the stack.
This means that in order to retrieve the value that is stored in x
, the computer must use the address stored on the stack, and go to that memory address in the heap.
We use the heap to store reference types because the stack is not very good at something called "dynamic memory allocation," which is where memory is allocated and deallocated without concern to other objects around it.
Now for boxing and unboxing:
Boxing (also called wrapping) is the process of taking a primitive type object and storing it as a reference type (so float x
becomes Float x
), so that those two objects are the same type. (It's kind of like wrapping a christmas present in paper) So, behind the scenes, Integer k = 6
is a kind of boxing (autoboxing)
Unboxing on the other hand is the opposite of unboxing, so you can call it unwrapping. Unboxing takes a "boxed" object and takes it from a reference type back to a primitive type, so the statements can work without too much hassle.:
Integer k = 6; //Boxing
int m = k; //Unboxing
What this really means, in terms of your question: in the code that you posted, autoboxing and unboxing occurred, which made the statement valid. The JVM was smart enough to do what you meant -- but that doesn't mean you should make a regular habit of it, because boxing and unboxing can have a serious impact on the performance of your code!
Also, if both x
and y
were Float
types, you'd be comparing references!
Good Luck!
Upvotes: 2
Reputation: 533492
Generally speaking ==
is fine unless you need to handling rounding or arithmetic errors in which case compareTo() won't help you much.
If you want to compare two doubles within an error you can use
if (Math.abs(a - b) < ERR) // within error.
or a relative error
if (Math.abs(a - b) < ERR * (Math.abs(a) + Math.abs(b))/2) // within error.
or within rounding whether the factor is often a power of ten like 10000 means to 4 decimal places.
if (Math.round(a * factor) == Math.round(b * factor)) // within a multiple
Upvotes: 8
Reputation: 234795
If both arguments were reference types, then ==
would test memory locations. However, if one of the arguments to ==
(or !=
) is numeric and the other is convertible to numeric (using unboxing), then the comparison is done by comparing numerical values after unboxing. So the comparison in this case is done on the basis of the floating point values (which in this case are identical). See the Java Language Specification §15.21.1 for details.
Note, however, that Float.NaN == Float.NaN
is false
.
Upvotes: 13