How to Get the "Object Reference" of an Object in Java When Tostring() and Hashcode() Have Been Overridden

How do you get the object reference of an object in java when toString() and hashCode() have been overridden?

What exactly are you planning on doing with it (what you want to do makes a difference with what you will need to call).

hashCode, as defined in the JavaDocs, says:

As much as is reasonably practical, the hashCode method defined by class Object does return distinct integers for distinct objects. (This is typically implemented by converting the internal address of the object into an integer, but this implementation technique is not required by the Java™ programming language.)

So if you are using hashCode() to find out if it is a unique object in memory that isn't a good way to do it.

System.identityHashCode does the following:

Returns the same hash code for the given object as would be returned by the default method hashCode(), whether or not the given object's class overrides hashCode(). The hash code for the null reference is zero.

Which, for what you are doing, sounds like what you want... but what you want to do might not be safe depending on how the library is implemented.

After override hashCode, toString() return the same value for the same object but after using == return false

From your comment:

I copied this from diffrent comenatry: But to save memory we're using StringPool. If we have the same value, refereance is also the same it's working just for creating String not by constructor. If i had String s = new String("a"); String s2 = new String("a"); I used 2 space in memory, but when i use String s = "a"; String s2 = "a" I use 1 space in memory. So that's mean toString() return "new String()"?

Your source should have said:

...it's working just for creating String using string literals.

That way it might have been clearer, because there are many ways to create new String objects without directly calling the constructor. String literals are those things surrounded by " (including the quotes), such as "a" or "b" or "Welcome to Stack Overflow".

Only string literals1 are pooled automatically. You can manually put a string into the pool by calling intern().

When you concatenate two strings (e.g. stringA + stringB), a new string is generally created, as described here.

Now let's look at what Object.toString does:

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())

Note that strings are being concatenated here, so a new string object is being created here, hence the output.

And to answer the question of:

So that's mean toString() return "new String()"?

Yes, but not directly. The compiler will turn the + operators in Object.toString into some code using StringBuilder (or rather, "the compiler has turned..." since the Object class has already been compiled). At the end, it will call StringBuilder.toString, and that will create a new String object.


1Constant expressions of strings, to be more accurate.

Hashcode and Equals for object reference?

Use

System.identityHashCode

and

==

Java - Overriding hashCode and toString

Sure, a1 and a2 have the same hash code, but they weren't considered equal because you didn't override equals to consider two A objects with the same ele to be equal. A map will use equals to the final ruler on equality after it uses the hash code. The map will place both objects in the same bucket, but because they aren't equal, it will keep both.

Override equals so that it returns true if the other object is an A and they both have the same ele. Then you will see that val2 will be returned for both get calls.

Java8: Hashmap overriden tostring behaviour

You can do this to get what the Object.toString method would return:

String s = m.getClass().getName() + "@" + Integer.toHexString(m.hashCode());
System.out.println(s);

Java String objects equality and reference

Strings in Java are immutable. You aren't "changing the value of y", you're creating a new string and assigning it to y. Since you haven't assigned anything else to x, it will still reference the previous string you had there.

How to print the address of an object if you have redefined toString method

Strictly speaking, you can't print the address of an object in pure Java. The number that looks like an object address in the String produced by Object.toString() is the object's "identity hashcode". It may or may not be related to the object's current address:

  • The specs do not say how the identity hashcode number is calculated. It is deliberately left unspecified.

  • Since the number is a hashcode, it cannot change. So even though it is (typically) related to an object address, that will be the object's address at the time when the hashcode was first accessed. This could be different to its current address, and it will be different if the GC has moved the object since the first time the object's identity hashcode was observed.

  • On a 64bit JVM (with a large enough heap size / not using compressed oops) addresses won't fit into an identity hashcode number which is returned as an int.

Anyhow, the way to get this number is to call System.identityHashCode(obj).


If you really want an object's current address, you can get it using JNI and a native method (and some abstraction breaking), or by using methods in the Unsafe class (see How can I get the memory location of a object in java?). But beware that both of these approaches are non-portable. Also, the object addresses that they give you are liable to "break" when the GC moves the object which renders them problematic for many (probably most) potential use-cases.


For the doubters, this is what the Java 10 javadocs say on the "hashcode != address" point:

"(The hashCode may or may not be implemented as some function of an object's memory address at some point in time.)"

Emphasis added. Indeed, with recent JVMs, the default algorithm does NOT derive the hashCode from a memory address at all. It has been that way since at least Java 7.

You can confirm this by including -XX:+PrintFlagsFinal in the command line options to find out what the hashcode flag defaults to, and then looking at the OpenJDK source code to see what it means. (The code is in the "vm/runtime/synchronizer.cpp" file in some versions, but YMMV.)

How do I print my Java object without getting SomeType@2f92e0f4?

Background

All Java objects have a toString() method, which is invoked when you try to print the object.

System.out.println(myObject);  // invokes myObject.toString()

This method is defined in the Object class (the superclass of all Java objects). The Object.toString() method returns a fairly ugly looking string, composed of the name of the class, an @ symbol and the hashcode of the object in hexadecimal. The code for this looks like:

// Code of Object.toString()
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}

A result such as com.foo.MyType@2f92e0f4 can therefore be explained as:

  • com.foo.MyType - the name of the class, i.e. the class is MyType in the package com.foo.
  • @ - joins the string together
  • 2f92e0f4 the hashcode of the object.

The name of array classes look a little different, which is explained well in the Javadocs for Class.getName(). For instance, [Ljava.lang.String means:

  • [ - an single-dimensional array (as opposed to [[ or [[[ etc.)
  • L - the array contains a class or interface
  • java.lang.String - the type of objects in the array


Customizing the Output

To print something different when you call System.out.println(myObject), you must override the toString() method in your own class. Here's a simple example:

public class Person {

private String name;

// constructors and other methods omitted

@Override
public String toString() {
return name;
}
}

Now if we print a Person, we see their name rather than com.foo.Person@12345678.

Bear in mind that toString() is just one way for an object to be converted to a string. Typically this output should fully describe your object in a clear and concise manner. A better toString() for our Person class might be:

@Override
public String toString() {
return getClass().getSimpleName() + "[name=" + name + "]";
}

Which would print, e.g., Person[name=Henry]. That's a really useful piece of data for debugging/testing.

If you want to focus on just one aspect of your object or include a lot of jazzy formatting, you might be better to define a separate method instead, e.g. String toElegantReport() {...}.



Auto-generating the Output

Many IDEs offer support for auto-generating a toString() method, based on the fields in the class. See docs for Eclipse and IntelliJ, for example.

Several popular Java libraries offer this feature as well. Some examples include:

  • ToStringBuilder from Apache Commons Lang

  • MoreObjects.ToStringHelper from Google Guava

  • @ToString annotation from Project Lombok



Printing groups of objects

So you've created a nice toString() for your class. What happens if that class is placed into an array or a collection?

Arrays

If you have an array of objects, you can call Arrays.toString() to produce a simple representation of the contents of the array. For instance, consider this array of Person objects:

Person[] people = { new Person("Fred"), new Person("Mike") };
System.out.println(Arrays.toString(people));

// Prints: [Fred, Mike]

Note: this is a call to a static method called toString() in the Arrays class, which is different to what we've been discussing above.

If you have a multi-dimensional array, you can use Arrays.deepToString() to achieve the same sort of output.

Collections

Most collections will produce a pretty output based on calling .toString() on every element.

List<Person> people = new ArrayList<>();
people.add(new Person("Alice"));
people.add(new Person("Bob"));
System.out.println(people);

// Prints [Alice, Bob]

So you just need to ensure your list elements define a nice toString() as discussed above.

How to get the unique ID of an object which overrides hashCode()?

System.identityHashCode(yourObject) will give the 'original' hash code of yourObject as an integer. Uniqueness isn't necessarily guaranteed. The Sun JVM implementation will give you a value which is related to the original memory address for this object, but that's an implementation detail and you shouldn't rely on it.

EDIT: Answer modified following Tom's comment below re. memory addresses and moving objects.



Related Topics



Leave a reply



Submit