I know the correct way to do this is Days.MONDAY.name().equals(day). But I'm wonder why Days.MONDAY.equals(day) fails when both prints MONDAY.
I know I'm missing something with equals() and toString(). I wanna clearly know what is it.
String day = "MONDAY";
System.out.println("main().Days.MONDAY : " + Days.MONDAY); // Prints MONDAY
System.out.println("main().day : " + day);// Prints MONDAY
System.out.println("main().Days.MONDAY.equals(day) : " + Days.MONDAY.equals(day)); // Why is this false when below is OK.
System.out.println("main().Days.MONDAY.toString().equals(day) : " + Days.MONDAY.toString().equals(day));// This is true
System.out.println("main().Days.MONDAY.name().equals(day) : " + Days.MONDAY.name().equals(day)); // This is true and I know this is the correct way
Edit: This is the enum.
enum Days{
MONDAY,TUESDAY,WEDENSDAY,THURSDAY,FRIDAY,SATURDAY,SUNDAY;
}
The equals method of an Enum compares the Static instances of the Enum. Because any representation of an Enum is pointing to the same object instance.
So the equals method of the Enum is not comparing the Name or toString it compares the instances.
String day="MONDAY";
The above line create Object inside Constant Pool , Where as
public enum Days{
MONDAY <-- Created in HEAP
}
Now Coming to
Days.MONDAY.equals(day) --> Why False ?
equals() method of Enum compares the instances of the Enum not the data as String#equals() does !!
Days.MONDAY.toString().equals(day) --> Why true ?
because it is String#equals() method which is overloaded !!
Look at is-it-ok-to-use-on-enums-in-java. Based on this, Java's implementation of equals on Enum simply performs ==. Since the Enum and the String day in your example are not the same object, it returns false.
The methods of the class Object have a strictly defined contract.
One of those methods is the Object.equals() method - here is its documentation.
To be able to maintain the symmetry requirement, it is practically impossible to return true in any implementation of equals() unless the two objects being compared are of the same class. equals() is supposed to represent some sort of equivalent between their properties, but objects which are not of the same class do not have the same properties.
Do not confuse the Days object Days.MONDAY with the string returned from Days.MONDAY.toString(). Its toString() just returns a string that represents it, and two strings are objects that can be equal. But Days.MONDAY.toString() is not the object itself (try Days.MONDAY.equals( Day.MONDAY.toString() ) and you'll get false here, too!
When you send an object to the print() or println() methods of System.out or any other PrintWriter, print() will take that object's toString() value and print it. This is the reason why they "print the same thing". It is not actually the MONDAY object that's being printed (it's hard to define "printing an object"), it's the string "MONDAY" that's returned from its toString() method.
All this would hold true even if Days was not an enum but some other object that is not a string, though in the particular case of an enum, its equals() method is indeed a comparison of references rather than attributes.
Related
It prints true for both of the following print statements in the sample code. I understand, its as per the logic of equals method of String class as:
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
...
}
But I am unable to figure out how their hashcode remains unchanged. Does the condition, this == anObject has any relationship with the hashCode method of String class? If yes then how are they equal.
Please help me to understand this.
It is true that value of a string can be modified through reflection(where it losses its immutability nature). But in this case the hashcode remains unchanged. Why?
import java.lang.reflect.Field;
public class StringHacker {
public static void main(String[] args) throws Exception {
String myMonth = "January";
char[] yourMonth = {'M', 'a', 'y'};
Field value = String.class.getDeclaredField("value");
value.setAccessible(true);
value.set(myMonth, yourMonth);
System.out.println(myMonth.equals("January"));
System.out.println(myMonth.equals("May"));
}
}
The output is:
true
true
But in this case the hashcode remains unchanged. Why?
The answer is that String::hashCode caches its result in a private field. So if you do this:
String s = /* create string */
int hash = s.hashcode();
/* use reflection to mutate string */
int hash2 = s.hashCode();
you will find that hash and hash2 are the same value. This is just one more reason why it is a bad idea to use reflection to mutate strings.
(But if you read the code for String you can see how hashCode is implemented and then use reflection to clear the cached hashcode value.)
The hashcode does not change because String is an immutable class.
That means by contract its value will not change. As the same value must always have the same hashcode, there is no need ever to change the hashcode. Even worse, an object with a hashcode changing over time may get you in big trouble, e.g. when dealing with Set and Map.
An object must not change its hashcode!
If you alter a string's value via reflection you're actively breaking the contract and thus causing undefined, chaotic and possibly catastrophic behaviour.
You mention hashcode in your question, but never call it nor display it's value, nor compare hoshcode values. So to answer your question :
Does the condition, this == anObject has any relationship with the hashCode method of String class?
The answer is an emphatic "no" (other, of course, than the obvious case that two references to the same object will obviously be calling the same method and get returned the same result). Likewise, hashcode() is also not called/considered by the equals() method.
So let's consider ==, equals(), and hashcode(), and how these play out in your example. Firstly, though, it must be mentioned that you are using reflection in a way that it was never intended to be used. There are situations where calling value.set(object, value) is valid and necessary - but changing the value of an immutable class like "String" is not one of them. Upshot is that it's not surprising to get weird results by doing things like that.
Let's start by restating that every object (such as a String) lives at its own location in the computer's memory. For example, consider code like :
String myName = "Fred";
String yourName = "Fred";
String databaseName = fetchNameFromDatabase(); // returns "Fred"
boolean mineIsYours = (myName == yourName); // true
boolean mineIsDatabases = (myName == databaseName); // false
boolean mineEqualsDatabases = myName.equals(databaseName); // true
All 3 Strings will have the same value "Fred" - but there's a neat trick. When the Java compiler compiles the program, it will load all hard-coded strings into the .class file. Since Strings are immutable, it saves some space by creating unique values in a "String pool" - so for my example, "Fred" will only be created ONCE, and myName and yourName will both be pointing to the SAME instance in memory - hence mineIsYours will be true.
Strings created dynamically (eg read from the database) would not use this String pool, so will be different instances even though they may have the same value - hence the importance to test equality using equals() rather than ==.
Can you now see what's happening in your program ? Let's look at a few specific lines :
String myMonth = "January";
"January" is a hard-coded constant, so it's put in the String pool, and myMonth is pointing to the location of that instance in memory.
value.set(myMonth, yourMonth);
The value of myMonth - ie, the value of that instance in memory that myMonth is pointing to - is changed to be "May".
System.out.println(myMonth.equals("January"));
Calls "equals" on myMonth, passing in the instance of the hard-coded String that the Java compiler put into the String pool for "January". However, this instance is THE SAME INSTANCE that myMonth was initialised to (remember my variable mineIsYours was true) !! Yes, THE SAME INSTANCE that you changed the value of to be "May".
So, when you changed myMonth's instance value in the String pool from "January" to "May", you didn't just change it for that one myMonth variable, but for EVERY hard-coded "January" value in the program !
System.out.println(myMonth.equals("May"));
The value of the instance that myMonth is pointing to has been changed to "May", so this is true.
So where is hashcode() used in all this ? As I mentioned earlier, it isn't. Not at all.
From your question, I'm wondering : is your understanding that two objects are equal if their hashcodes match ? If so, no - not at all. There is NO - repeat NO - requirement that hashcodes be unique, which means the idea of "equal if hashcodes match" obviously fails.
The purpose of hashcode() is to give a wide spread of values for different instances of the class. This is used in structures like HashMap,etc to put objects into different "buckets" for quick retrieval.
The implicit connection between equals() and hashcode() is that :
1) where one is created (or rather, overridden), then the other
should be as well, and
2) hashcode() calculation should use the
exact same fields as equals() - no more and no less.
if ((File_1[i].ID.equals(File_2[j].ID))
&& (File_1[i].Relation.equals(File_2[j].Relation)))
The first condition here, (File_1[i].ID.equals(File_2[j].ID) shows false when it is supposed to be true. They both have equal values.
Am I doing something wrong? This is unusual.
ID: fa001
ID: fa001
These are the values of the first 2 variables that are compared, but it shows up as false.
The original poster has said the ID is a String type and there are whitespaces around the String. In order to remove the whitespaces of String s:
s = s.trim();
However, if ID is a type you have created, make sure you implement the .hashCode() method. From the Javadocs:
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.
Also make sure that .equals() is overridden from class Object to allow for your definition of whether the values of your new object type are equal.
Depending on the TYPE of ID (int, string, char[], etc) the .equals method can do some weird things. Assuming they are strings, try comparing ID.trim(), which will remove any witespace around the ID.
I see a lot of the following line in projects I took over:
log.debug(submitObject(" + object + ")");
log.debug(registerUser(" + user + ")");
and so on.
In the logs this prints out something like:
SubmitObject(java.lang.Object#13a317a)
Is it useful to log just the object type and its hashcode? Say I want to know the name of the user object but I only have the hashcode, would it be possible for me to reconstruct the object based on the hashcode?
From the javadoc for object.toString()
Returns a string representation of the object. In general, the
toString method returns a string that "textually represents" this
object. The result should be a concise but informative representation
that is easy for a person to read. It is recommended that all
subclasses override this method. The toString method for class Object
returns a string consisting of the name of the class of which the
object is an instance, the at-sign character `#', and the unsigned
hexadecimal representation of the hash code of the object. In other
words, this method returns a string equal to the value of:
getClass().getName() + '#' + Integer.toHexString(hashCode())
Returns: a string representation of the object.
I myself always override the toString() of a custom object so it prints out all the fields of the object. Should I start printing the object code instead?
You could use ReflectionToStringBuilder from org.apache.commons, if you do not have access to source code, or if you do not want implement toString for change existing code.
For Example:
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("User : "
+ reflectionToStringBuilder.toString(user ,
ToStringStyle.MULTI_LINE_STYLE))
}
"LOGGER.isDebugEnabled() is very important as toString Operation, or reflectionToStringBuilder, will be executed before calling log.debug, so you do not want such expensive operations.
ReflectionToStringBuilderJavaDoc: http://commons.apache.org/proper/commons-lang/javadocs/api-2.6/org/apache/commons/lang/builder/ReflectionToStringBuilder.html
No, keep overriding toString() which is much more useful. The default toString() is practically useless except that it at least shows what the class instance is.
That hash code is a randomly assigned value. It is only useful if you want to check you had the same object in a previous log, or a different one (i.e. very rarely)
The output of the below code is false
String str = "3456";
String str1 = "3456";
System.out.println(Integer.valueOf(str).equals(str1));
I didn't understand it. I thought it will return true. As I am preparing for SCJP, understanding the reason behind it may be helpful. Can someone please help?
An Integer will never be equal to a String.
Both classes have very strict equals() definitions that only accept objects of their respective types.
Integer.equals():
The result is true if and only if the argument is not null and is an Integer object that contains the same int value as this object.
String.equals():
The result is true if and only if the argument is not null and is a String object that represents the same sequence of characters as this object.
That's actually a quite common way to implement equals(): only objects of the same class (and occasionally subclasses) can be equal. Other implementations are possible, but are the exception.
One common exception are the collections such as List: every List implementation that follows the convention will return true when compared to any other implementation, if it has the same content in the same order.
Usually, when implementing equals(), one of the first things to do is to check whether the objects are of one and the same type.
public boolean equals(Object obj) {
if (!(obj instanceof SomeType)) return false;
...
}
This is also applied in the Integer and String classes, which answers the question why do you receive false as a result.
The general contract of the equals() methods states (among other things) that the objects that are being compared need to be of the same class. That's why you'll never be able to compare Apples with Oranges.
For the full contract of the equals() method, see the javadocs.
a Integer Object can't equals with String Object
use :
boolean a = str.equals(str1);
OR
boolean a = (Integer.parseInt(str) == Integer.parseInt(str1));
So I'm learning Java and I'm trying to understand equals, but I really don't understand it. So my question is: how does equals works?
Thanks
equals is a method you use to discover if two given objects are the same. The default implementation of equals for an object is: They are the same if they have the exact same reference.
Sometimes, you don't want this. Say you have a ComplexNumber class, and two instances with value 1+i. You don't want them not to be equal just because they are different instances. In essence, they represent the same number. In this case, you should override equals to make sure it behaves as intended.
HashMaps use info from equals to know if the key you passed is already there.
From Effective Java book:
Always override hashcode when you
override equals
I'd also add to that: specially if you're using a Hashmap =)
Hashmaps uses also hashcode() to search faster for the keys, and the result for hashcode() must be consistent with the equals result. In other words, if x.equals(y), then x.hashcode() == y.hashcode() (or you may have undefined behavior for your hashmap). You may have x and y with x.hashcode() == y.hashcode() and !x.equals(y)
If you want a more specific answer, please make a more specific question =).
The equals method will compare values for equality.
the method equals is defined in the object class so which means that every other class can use this method to compare how it works: it will first check if its referring to its self then the haschode's of the object and if those are equal if so, it will then check each field in that object against the fields of the object you are comaparing to why you might ask co's the haschode could be the same but it can still contain other value's in the fields the odds are low but its needed to compare more in depth then.
equals() means "meaningfully equivalent." It's not the same as ==, which means "these are the same object." All classes have the equals() method, inheirited from the Object class. For example, say you write a Car class that stores make, model and owner:
Car carOne = new Car("Buick", "LeSabre", "John Doe");
Car carTwo = carOne;
Here, equals() and == will both return true, because both references point to the same car. But, for
Car carOne = new Car("Buick", "LeSabre", "John Doe");
Car carTwo = new Car("Buick", "LeSabre", "John Doe");
there are two distinct objects, so == returns false. However, since both cars are Buick LeSabres owned by John Doe, your equals() should be written return true (assuming for this example that nobody owns more than one car of the same type).
Also, as Samuel pointed out, if you override equals(), you should also override hashCode(); the reasons for that are outside the scope of this question, and well-documented elsewhere.