Overriding HashCode() in Java with double values - java

I know this is asked a lot, and I don't know if I quite understand hash codes, but it's supposed to be the address and so how do I fix my particular example? If my understanding is correct, I have doubles in my class, but I can't add them to the hash code, because of
possible loss of precision
found : double
required: int
return this.area();
Here is my Shape class:
abstract class Shape implements Comparable<Shape>
{
abstract double area();
public int compareTo(Shape sh){
return Double.compare(this.area(),sh.area());
}
public int hashCode() {
return this.area();
}
public boolean equals(Shape sh) {
if ( sh instanceof Shape && this.area()==sh.area() ) {
return true;
} else {
return false ;
}
}
}
Is area() the only value I need to worry about in hashCode()?

You can use the example of hashCode in Double class :
public int hashCode() {
long bits = doubleToLongBits(value);
return (int)(bits ^ (bits >>> 32));
}
This would avoid the loss of precision caused by simply casting the double to int.
If the area is the only property that determines the hashCode, you can use the exact same code, replacing value with area.
However, I'm not sure area is a good candidate for hashCode calculation, since it is itself calculated from properties of the sub-classes of Shape. You should probably implement hashCode in each sub-class of Shape based on the specific properties of that sub-class.

Don't just add the numbers together to produce a hash code; that's very likely to get duplicate hash codes for unequal objects close together. Instead, I recommend using either the Objects.hash method from the standard Java API or the more expressive and efficient HashCodeBuilder from Apache Commons-Lang. You should include in the hashCode calculation exactly the same fields that you use to determine equals.
Of course, as #khelwood pointed out, you very likely don't want to implement equals and hashCode on this abstract object, since a 1x4 rectangle and a 2x2 rectangle probably aren't equal. Instead, you can re-declare those methods as abstract on Shape to force subclasses to implement them:
public abstract class Shape {
#Override
public abstract int hashCode();
}

You could do:
public int hashCode() {
return Double.valueOf(this.area()).hashCode();
}
-- Edition: corrected valueOf method name. Thank you #user4254704.

Related

overide the equal, toString, hashcode methods in Enum

I have one Enum like Below
public enum Game {
CRICKET("cricket"),
FOOTBALL("football"),
VOLLEYBALL("volleyball")'
private String val;
private Game(String val) {
this.val = val;
}
public String getValue() {
return this.val;
}
}
In here, Do I want to overide the equal(),hashCode(),toString() methods
based on this What issues should be considered when overriding equals and hashCode in Java?
Question is meaningless, because you cannot override equal() and hashCode() of an enum.
That is because they are defined as final in the Enum class, which implicitly is the base class of all enum types.
No, enum is not a regular class (and as Andreas pointed out, they're final methods). For example, you don't need to use equals() to compare them, as there is a single instance of each enum value. This allows you to use == instead.
if(gameType == Game.CRICKET)
You can override toString(), as by default it prints the same as name(), which is just the name of the enum (e.g. FOOTBALL).
My first question is why you would need the enum to contain a String in the first place. The point of your enum already looks like it is to differentiate each type of game within a certain list of possible games. So the enum itself here functions as a constant value. For example you could do:
public void playGame( Game myGame ){
switch(myGame){
case FOOTBALL:
playFootball();
break;
case CRICKET:
playCricket();
break;
// and so on but you get the point
}

Java TreeMap with variable Keys

I attempted to implement Fortune's algorithm in Java, and to avoid writing an AVLTree I decided to use a TreeMap with BeachNode keys.
BeachNode has the following code:
public abstract class BeachNode implements Comparable<BeachNode>{
static int idcounter=0;
int id;
public StatusNode(){
//Allows for two nodes with the same coordinate
id=idcounter;
idcounter++;
}
#Override
public int compareTo(BeachNode s) {
if(s.getX()<this.getX())
return -1;
if(s.getX()>this.getX())
return 1;
if(s.id<this.id)
return 1;
if(s.id>this.id)
return -1;
return 0;
}
public abstract double getX();
}
The getX() method of Intersection returns a value dependent on the present height of the sweep line- so it changes partway through execution.
My first question:
(I'm fairly sure the answer is yes, but peace of mind would be nice)
If I ensure that for any two BeachNodes A and B, signum(A.compareTo(B)) remains constant while A and B are in the beach tree, will the TreeMap still function despite the changes underlying the compareTo?
My second question:
How can I ensure that such a contract is obeyed?
Note that in Fortune's algorithm, we track at what sweep line positions two intersections will meet- when the sweep line reaches one of these positions, one of the intersections is removed.
This means two intersections A and B in the beach tree will never cross positions, but during a CircleEvent A.compareTo(B) will return 0- interfering with processing the CircleEvent. The contract will be broken only briefly, during the CircleEvent that would remove one Intersection.
This is my first question on StackOverflow, if it is poorly posed or incomplete please inform me and I will do my best to rectify it.
According to the TreeMap documentation, the tree will be sorted according to the compareTo method, so any changes that are not reflected in the sign of a.compareTo(b) are allowed. However, you also need to implement an equals method with the same semantics as compareTo. This is really easy if you already have a compareTo method:
public boolean equals(Object object) {
if (!(object instanceof BeachNode)) {
return false;
}
BeachNode other = (BeachNode) object;
return this.compareTo(other) == 0;
}
And, since you're overriding equals, you should override hashCode. This is also pretty easy, since you are only using a couple fields to define equality.
public int hashCode() {
int hash = 1;
hash = (17 * hash) + (Double getX()).hashCode());
hash = (31 * hash) + id;
return hash;
}
I'm not sure about your second question, but since the id of the two intersections should stay different, wouldn't they not be equal? If I'm wrong, hopefully someone who understands the algorithm can help you work that out.

How can I effectively use floats in equals()?

I have the following immutable HSL class that I use to represent a colour and aide in calculations on RGBA colours with a little more finesse.
public class HSL {
protected final float hue;
protected final float saturation;
protected final float lightness;
public HSL(float hue, float saturation, float lightness) {
this.hue = hue;
this.saturation = saturation;
this.lightness = lightness;
}
// [snip] Removed some calculation helper functions
#Override
public String toString() {
return "HSL(" + hue + ", " + saturation + ", " + lightness + ")";
}
#Override
public int hashCode() {
return
37 * Float.floatToIntBits(hue) +
37 * Float.floatToIntBits(saturation) +
37 * Float.floatToIntBits(lightness);
}
#Override
public boolean equals(Object o) {
if (o == null || !(o instanceof HSL)) {
return false;
}
HSL hsl = (HSL)o;
// We're only worried about 4 decimal places of accuracy. That's more than the 24b RGB space can represent anyway.
return
Math.abs(this.hue - hsl.hue) < 0.0001f &&
Math.abs(this.lightness - hsl.lightness) < 0.0001f &&
Math.abs(this.saturation - hsl.saturation) < 0.0001f;
}
}
While I don't foresee using this particular class in a HashMap or similar as it's an intermediary between a similar RGBA class which uses ints for it's internal storage, I'm somewhat concerned about the general case of using floats in equality. You can only make the epsilon for comparison so small, and even if you could make it arbitrarily small there are many float values that can be represented internally in multiple ways leading to different values returned from Float.floatToIntBits. What is the best way to get around all this? Or is it not an issue in reality and I'm just overthinking things?
The other answers do a great job of explaining why your current design may cause problems. Rather than repeat that, I'll propose a solution.
If you care about the accuracy only to a certain number of decimal places (it appears 4), you could multiply all incoming float values by 10,000 and manage them as long values. Then your equality and hashcode calculations are exact.
I assume you've omitted the getters from your class for brevity. If so, ensure your Javadocs clearly explain the loss of precision that will occur when passing a float into your class constructor and retrieving it from a getter.
This definition of equals() is not transitive. It really shouldn't be called equals(). This and the hashCode() issue would most likely silently bite when used in the Collections API. Things like HashSet would not work as expected and methods like remove(). For purposes here you should test for exact equality.
I think you are correct to be concerned about the general case of hashCode() diverging heavily from equals().
The violation of the general convention that hashes of two "equal" objects should have the same hashCode() will most likely lead to all sorts of unexpected behavior if this object is used in the future.
For starters, any library code that makes the usual assumption that unequal hashCodes implies unequal objects will find a lot of unequal objects where it should have found equal objects, because the hashCode check usually comes first, for performance.
hashcode is like defining a bucket that an object should reside in. With hashing, if an object is not in its right bucket, you cannot find that with the equals() method.
Therefore, all the equal objects must reside in the same bucket (i.e., their hashcode() method should return the same result) or the results would be unpredictable.
I think you could try to weaken the hashCode implementation to prevent it from violating contract with equals - I mean ensure that when equals returns true, then hashCode returns the same value but not necessarily the other way around.

Overriding the equals() method to allow for hetergenous Objects

Below is selected code from one of 5 classes for this assignment.
Each class must have a equals() method that can compare an object of its class to an object of any and all of the 5 classes.
My strategy is to convert each object value to a double for the sake of precision.
As each Class extends Number each class has a doubleValue() method to utilize.
the code would not compile unless I typecasted x to RationalN before executing doubleValue()
but when executing the code it complains when a object of another class is compared as it can't be typecasted to that Class.
I where do I go from here?
public class RationalN extends Number{
private int numerator;
private int denominator;
public RationalN(int x, int y){
if (y == 0){
throw new ArithmeticException("cannot devide by zero");
} else {
this.numerator=x;
this.denominator=y;
}
}
public double doubleValue(){
double value = (double)numerator/(double)denominator;
return (double)value;
}
public boolean equals(Object x){
if (((RationalN)x).doubleValue() == this.doubleValue()){
return true;
} else {
return false;
}
}
From what I get from your post, you want to check in equals whether the numeric value represented by your object equals the numeric value of the argument object. Therefore, comparing the classes is not appropriate. Instead, your equals() method has too look something like this:
public boolean equals(Object x) {
if(this == x)
return true;
if(x == null)
return false;
if(!(x instanceof Number))
return false;
Number n = (Number)x;
return (n.doubleValue() == this.doubleValue());
}
This, however, violates the equals() contract:
new RationalN(1, 1).equals(new Integer(1)) would return true, but new Integer(1).equals(new RationalN(1, 1)); wouldn't - the above equals() method violates symmetry. It would therefore be appropriate to introduce an abstract class implementing Number (say, MyNumber) which is extended only by your five classes and implements equals() in the above fashion (using instanceof MyNumber).
edit: I just realized that number has doubleValue() as an abstract method in the Number class. Ok this is perfect. Just implement equals in all five classes like this. Alternatively if Number is not required as an abstract class, then read below to see that you can create your own abstract class that implements equals() and save duplicated code.
public boolean equals(Object x)
{
if(x instanceof Number == false)
return false;
Number other = (Number) x;
return other.doubleValue() == doubleValue();
}
The reason why you can't do what you are doing in your equals is because you are casting whatever you are trying to compare against to a RationalN class. When this is done to a class that is not a RationalN, this results in a ClassCastException.
Since all classes extend Number and doubleValue() is declared as a method available to Number, you can now cast those classes to Number (if they are an instance of Number) and then access the method from there.
I hope this makes sense. I encourage you to read up on interfaces and polymorphism.
edit: As an aside, if you are not required to extend Number, you can create an abstract class which has the abstract method doubleValue(), and then you can provide a concrete implementation of equals(that I provided above) in the abstract class. Then have all five of your classes extend the abstract class. They would each then implement their own version of doubleValue(), but would share the equals() defined in your abstract class, and thus eliminate copy/paste of the equals() into all five classes. This would be the ideal route if you did not have to extend Number.

Why should I override hashCode() when I override equals() method?

Ok, I have heard from many places and sources that whenever I override the equals() method, I need to override the hashCode() method as well. But consider the following piece of code
package test;
public class MyCustomObject {
int intVal1;
int intVal2;
public MyCustomObject(int val1, int val2){
intVal1 = val1;
intVal2 = val2;
}
public boolean equals(Object obj){
return (((MyCustomObject)obj).intVal1 == this.intVal1) &&
(((MyCustomObject)obj).intVal2 == this.intVal2);
}
public static void main(String a[]){
MyCustomObject m1 = new MyCustomObject(3,5);
MyCustomObject m2 = new MyCustomObject(3,5);
MyCustomObject m3 = new MyCustomObject(4,5);
System.out.println(m1.equals(m2));
System.out.println(m1.equals(m3));
}
}
Here the output is true, false exactly the way I want it to be and I dont care of overriding the hashCode() method at all. This means that hashCode() overriding is an option rather being a mandatory one as everyone says.
I want a second confirmation.
It works for you because your code does not use any functionality (HashMap, HashTable) which needs the hashCode() API.
However, you don't know whether your class (presumably not written as a one-off) will be later called in a code that does indeed use its objects as hash key, in which case things will be affected.
As per the documentation for Object class:
The general contract of hashCode is:
Whenever it is invoked on the same object more than once during an execution of a Java application, the hashCode method must consistently return the same integer, provided no information used in equals comparisons on the object is modified. This integer need not remain consistent from one execution of an application to another execution of the same application.
If two objects are equal according to the equals(Object) method, then calling the hashCode method on each of the two objects must produce the same integer result.
Because HashMap/Hashtable will lookup object by hashCode() first.
If they are not the same, hashmap will assert object are not the same and return not exists in the map.
The reason why you need to #Override neither or both, is because of the way they interrelate with the rest of the API.
You'll find that if you put m1 into a HashSet<MyCustomObject>, then it doesn't contains(m2). This is inconsistent behavior and can cause a lot of bugs and chaos.
The Java library has tons of functionalities. In order to make them work for you, you need to play by the rules, and making sure that equals and hashCode are consistent is one of the most important ones.
Most of the other comments already gave you the answer: you need to do it because there are collections (ie: HashSet, HashMap) that uses hashCode as an optimization to "index" object instances, an those optimizations expects that if: a.equals(b) ==> a.hashCode() == b.hashCode() (NOTE that the inverse doesn't hold).
But as an additional information you can do this exercise:
class Box {
private String value;
/* some boring setters and getters for value */
public int hashCode() { return value.hashCode(); }
public boolean equals(Object obj) {
if (obj != null && getClass().equals(obj.getClass()) {
return ((Box) obj).value.equals(value);
} else { return false; }
}
}
The do this:
Set<Box> s = new HashSet<Box>();
Box b = new Box();
b.setValue("hello");
s.add(b);
s.contains(b); // TRUE
b.setValue("other");
s.contains(b); // FALSE
s.iterator().next() == b // TRUE!!! b is in s but contains(b) returns false
What you learn from this example is that implementing equals or hashCode with properties that can be changed (mutable) is a really bad idea.
It is primarily important when searching for an object using its hashCode() value in a collection (i.e. HashMap, HashSet, etc.). Each object returns a different hashCode() value therefore you must override this method to consistently generate a hashCode value based on the state of the object to help the Collections algorithm locate values on the hash table.

Categories