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)
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.
Javadoc for Object.toString() says:
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())
Therefore, I am questioning myself if I'm abusing this when I am overriding toString() of a class Foo just so that a ComboBox control (doesn't matter it's JavaFX or Swing control) can render a list of Foo correctly without me doing anything explicit in the ComboBox.
class Foo {
private String name;
public final String getName() { return name; }
public final void setName(String n) { name = n; }
#Override
public String toString() {
return name;
}
}
List<Foo> foos = getFoos(); // Get list of Foos from somewhere
ComboBox comboBox = ....; // Some ComboBox control
comboBox.addItems(foos); // Add the list to the ComboBox
The default implementation of toString() that most IDE generates are JSON representation of the class. I am suspecting this allows easy serialization/deserialization of class objects. Although I do not need to serialize or deserialize through this method, but I am definitely breaking this possibility by overriding like this.
Edit
I've read the comments of many people, as well as the answer given by VGR. I can see that the general consensus is that there is no hard and fast rule on this. I see that it is generally agreed that toString() is better left for debugging purposes.
The biggest reason why I am doing this "hack" is because I have ComboBox in quite a number of different places. Of course the indisputably correct and clean way is to use a "renderer" to do this job, but it is causing a significant amount of code duplication.
I will mull over this for a few days before I decide which is the best way to do it. Thanks a lot for the bunch of comments and answer.
For Swing, you definitely need to override the toString method of some class. That’s how Swing model objects work. (Do not use cell renderers to convert a value to String; that will break accessibility, keyboard navigation, and built-in sorting of JTables.)
Usually you’d want to separate your display logic from your data, such as by creating a wrapper class, but since you are just returning the raw value of a property (as opposed to formatting it or concatenating it with other information), what you’re doing is fine.
JavaFX is another matter: Controls use cell factory callback objects to determine what text appears in a cell, so a data class probably should not override toString with a display value in a JavaFX application.
I’m not familiar with IDEs’ auto-generated toString methods, but converting an object to JSON in a toString method is a horrible idea in my opinion. Swing model objects should have a toString method that returns a human-readable form of the object; most other classes should return a one-line string with a summary of the object’s state (which does not have to be every property in the object), like getClass().getName() + "[" + getName() + "]".
In summary, you are not abusing toString. For Swing, you’re doing the right thing. For JavaFX, it’s better to return a string useful for debugging.
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.
I've been working in my project (I'm also using EMF Compare). I need to keep an unique ID for each object that I'm using, that's why I decided to use the IdentityHashCode, as far as I understand, this value is the same through the compilation.
I have given the object as a parameter in the method of another class, but when I try to get the hashcode this is not the same that I can see when I print the value of the object.
Something like this:
System.out.println("The Object is: "+obj)
System.out.println("The hash ID is: +Integer.toHexString(System.identityHashCode(obj)));
But as a result I get this:
The Object is : ***xxxxxxxxxxxxxx***.EntityImpl#18e588c (name: Comment) has been removed.
The hash ID is: 1ec1758
As you can see the two values (18e588c and 1ec1758) are totally different, but I can't understand why. Until now the only thing that I have done (and it works) is to get the String of the object and then use the substring method to get 18e588c (for this example)
I'd appreciate any answer.
I need to keep an unique ID for each object that I'm using, that's why I decided to use the IdentityHashCode, as far as I understand, this value is the same through the compilation.
No. It's got nothing to do with compilation, and it's not guaranteed to be unique.
It's not clear what you're trying to do, but you simply shouldn't regard hash codes as unique - they're not guaranteed to be.
The Object.hashCode documentation specifies:
As much as is reasonably practical, the hashCode method defined by class Object does return distinct integers for distinct objects.
That's not the same thing as guaranteeing it though.
You're also being confused by the result of calling toString() - I suspect your class actually overrides hashCode(), and Object.toString() calls the potentially-overridden hashCode() method rather than using the identity hash code:
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())
If you call obj.hashCode() you'll see the same value that's shown by toString.
I appear to have a fundamental gap in my understanding of an EditText object. I have an Activity+Layout with a single EditText object. After I type a few characters into the EditText object and hit the Enter key, I retrieve the text in my onKey() listener. When I use the toString() method to retrieve the text I get back a weird string like:
android.widget.EditText#43749ff0
Despite the fact the EditText.mText property does show the string I entered, "123" during my tests. Why is toString() returning a different result and what appears to be some kind of "uninitalize" value? How do I get the desired string currently in the mText property and what is that strange value?
-- roschler
Passing glance at the API suggests you should use the getText() method. toString() is a general method that applies to Object and all its subclasses (i.e., everything that isn't a primitive, to my knowledge). It's often overridden to supply more useful strings, but by default, it reports something just like what you posted - a sparse description and the object's hashcode. To be clear, the API defines toString() as:
getClass().getName() + '#' + Integer.toHexString(hashCode())
You can't use the 'toString'-method on this, use 'getText().toString()' in stead.
You are calling toString() on a View Object, which probably does not have a toString() defined.
I believe you want to call this:
editText.getText().toString()
Try EditText.getText().toString()
Take a moment to read the java API: http://download.oracle.com/javase/6/docs/api/java/lang/Object.html#toString%28%29
toString
public String 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.