52

I'm a newbie to Java. Now I'm studying equals and == and redefinition of equals and toString.

I would like to use both the toString method that I have redefied and the default method that is inherited from the Object class.

I failed to use that super modificator to reach that method.

This is for educational purposes only. What I would like to get is more clear if you will have a look at the comments in my code.

Could you help me here?

My code is:

public class EqualTest{
    public static void main(String[] args){ 
        Employee alice1 = new Employee("Alice Adams", 75000, 1987, 12, 15);
            //System.out.super.println(alice1);

        Employee alice2 = alice1;
            //System.out.super.println(alice2);

        Employee alice3 = new Employee("Alice Adams", 75000, 1987, 12, 15);
            //System.out.super.println(alice3);

        System.out.println("alice1==alice2: " + (alice1==alice2));
        System.out.println("alice1 == alice3: " + (alice1==alice3));
        System.out.println("alice1.equals(alice3): " + alice1.equals(alice3));
    }
}

class Employee{
...
    public String toString(){
        return getClass().getName() + "[name = " + name + 
            ", salary=" + salary + ", hireDay=" + hireDay + "]";
    }

}
Kifsif
  • 3,477
  • 10
  • 36
  • 45
  • 6
    Firstly it's not called redefining it's called overriding – Aniket Thakur Aug 23 '13 at 07:12
  • 3
    But the default implementation does not return the adress of the object. It returns the class name and the hashCode of that object. From the documentation of java.lang.Object: 'getClass().getName() + '@' + Integer.toHexString(hashCode())' – Matthias Aug 23 '13 at 07:12
  • Well, yes. But the hash code is the address. Look at the documentation for Object hashCode: This is typically implemented by converting the internal address of the object into an integer, but this implementation technique is not required by the JavaTM programming language. So, the hash code is just the same hex number representing the address. But its converted into decimal. – Kifsif Aug 23 '13 at 07:22
  • 2
    Well, no. It *can* be the address, but there is no guaranteee. You were therefore never able to print the address reliably in the first place, regardless of whether or not you overrode `toString().` But I don't see any requirement here to actually get the address at all, just the original result of `toString(),` which is available via `super.toString()`, despite your unspecified 'failure'. Your actual question remains unclear. – user207421 Aug 23 '13 at 07:31
  • Why not. It is the address. At a given time it is the address represented as int. As we are are talking about more or less static environment, the address will not change. I mean, that in such a simple program, the garbage collector didn't touch the heap. So, why is it not the address in this case? – Kifsif Aug 23 '13 at 07:34
  • 3
    @Kifsif Saying `It is the address` is plain wrong. It **may be** the address (and in most cases, but not all, it probably is). Ie, if you rely on `hashCode()` for getting the address of objects it may work in some cases, but in other cases it may fail. Eg, it'd be possible according to the specs that some JVM keeps a completely random number as hashcode stored for each object. In reality, this probably wouldn't be the case, since it would entail unecessary storage overhead. Anyways, in Java you typically shouldn't be concerned with at what memory addresses objects are located. Java is not C. – Alderath Aug 23 '13 at 10:39
  • To get addresses, use Unsafe: http://stackoverflow.com/questions/1961146/memory-address-of-variables-in-java – Ciro Santilli OurBigBook.com Oct 26 '15 at 07:57

5 Answers5

88

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

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
22

If you want to achieve sort-of default toString() behavior, you can make use of System.identityHashCode() method. Default toString() will then look like this:

public String toString(Object o) {
    return o.getClass().getName() + "@" + 
           Integer.toHexString(System.identityHashCode(o));
}
Andrew Logvinov
  • 21,181
  • 6
  • 52
  • 54
1

You can call super() method to execute the corresponding superclass method.

class Employee{
...
    public String toString(){
         String s = super.toString();
        return getClass().getName() + "[name = " + name + 
            ", salary=" + salary + ", hireDay=" + hireDay + "]" + s;
    }

toString() in Object class is as follows

public String toString() {
    return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
Aniket Thakur
  • 66,731
  • 38
  • 279
  • 289
  • This won't work if this class extends a superclass that overrides `toString()`. (And you call `toString()` further up the inheritance hierarchy ...). There is a better way than this. – Stephen C Apr 17 '21 at 06:26
0

Here is an in-depth answer about overriding equals and hashcode

What issues should be considered when overriding equals and hashCode in Java?

The key point being The relation between the two methods is:

Whenever a.equals(b), then a.hashCode() must be same as b.hashCode().

Community
  • 1
  • 1
Scary Wombat
  • 44,617
  • 6
  • 35
  • 64
0

You may create another method inside your Employee class to use super toString method.

See example:

public class Employee {
    public String toString() {
        return "MyToStringMethod";
    }

    public String superToString() {
        return super.toString();
    }

    public static void main(String[] args) {
        Employee b = new Employee();
        System.out.println(b);
        System.out.println(b.superToString());
    }
}

or combine both in one method:

public class Employee {
    public String toString() {
        return super.toString() + " MyToStringMethod";
    }

    public static void main(String[] args) {
        Employee b = new Employee();
        System.out.println(b);
    }
}
Alexey Odintsov
  • 1,705
  • 11
  • 13