7

Found the following in my notes, but I am unable to make sense of it:

Primitive type wrapper classes implement caching for a limited number of values.
This guarantees that a limited number of deeply equal wrapper objects are also shallowly equal: If o1.equals( o2 ) then o1 == o2.
For example, new Integer( 0 ) == new Integer( 0 ).
In general this does not always work.
For example, new Integer( 666 ) == new Integer( 666 )
may not hold.
The reason for caching is that it saves memory.
In general caching works for “small” primitive values.

I don't understand what is meant by this, or what the difference is between a deep (.equals()) and shallow(==) equals. I know in practice, .equals must be used to objects and == for Integral values, but the actual reasoning for this alludes me.

I assume by the names that shallow maybe just checks that both the values are of the same type and name, which deep checks that both variables point to the same object? I don't see how the caching would come into play here though, or why it would be useful.

Joachim Sauer
  • 278,207
  • 54
  • 523
  • 586
Albatross32
  • 239
  • 2
  • 4
  • 5
  • 1
    Well, your notes are completely wrong. `new Integer( 0 ) == new Integer( 0 )` will **never, ever, *ever*** be true, nor will `new Integer( 666 ) == new Integer( 666 )`. I suggest you ask your professor for clarification on what he meant, because if he expects this on an exam, he knows little about Java. – Mark Peters Apr 18 '11 at 13:32

5 Answers5

7

When you do == you are comparing the references for equality. This means you're saying "is the address in memory the same for both Objects?"

When you do .equals() you are comparing the Objects themselves for equality. This means you're saying "do these two Objects consider themselves equal?"

The example that was given was poor. The only caching done for these numbers that's mandated by the JLS is the .valueOf() method. The constructor is not cached.

Furthermore, the JLS only specifies the minimum you must cache [-128:127]. JVM implementations may cache more if they so choose. This means Integer.valueOf(500) == Integer.valueOf(500) may be false on some machines, but true on others.

class biziclop {

    public static void main(String[] args) {
        System.out.println(new Integer(5) == new Integer(5));
        System.out.println(new Integer(500) == new Integer(500));

        System.out.println(Integer.valueOf(5) == Integer.valueOf(5));
        System.out.println(Integer.valueOf(500) == Integer.valueOf(500));
    }
}

Results in:

C:\Documents and Settings\glow\My Documents>java biziclop
false
false
true
false

C:\Documents and Settings\glow\My Documents>

See a more detailed answer here (the comments are a gem!): Why do people still use primitive types in Java?

Community
  • 1
  • 1
corsiKa
  • 76,904
  • 22
  • 148
  • 194
  • Hi, how are the outputs of System.out.println(Integer.valueOf(5) == Integer.valueOf(5)); System.out.println(Integer.valueOf(500) == Integer.valueOf(500)); different?? – Bhavuk Mathur Sep 21 '15 at 22:15
  • 1
    That's the entire point of the answer: `5` is small enough that the JVM caches it, while `500` isn't. Although it could be, so on some rare machines it could be the same (both true) but on most machines `5` will be cahced and thus return the same Integer object while `500` won't be so `valueOf` will create `new Integer`s. – corsiKa Sep 21 '15 at 22:17
6

Well, actually shallow/deep dissection is different from ==/equal dissection:

  1. == compares for object identity, that is you checking whether operands are the same in fact (two references to the same area of memory), whereas equals compares for object equivalence, that is "logical" value of two, possibly not identical objects, is the same. If for two objects

    a == b
    

    then it's true that

    a.equals(b) // if a != null
    

    , but opposite isn't true in all cases.

  2. shallow/deep distinction makes sense only for equals comparison. Shallow means that you compare only immediate contents of two objects to find whether they "equal" in your sense, whereas deep means that you compare contents of your objects recursively until all you need to compare is primitive fields. If you define equals method of your objects as sequence of calls to equals on instance fields of these objects, you use deep comparison. If you define equals using == operator to compare compound types, such as Strings, then you use shallow comparison -- and that's incorrect in Java.

Morale of all of this is that you must never use == to compare two compound objects, unless you consider them equal only if they are the same.

Victor Sorokin
  • 11,395
  • 1
  • 32
  • 48
  • What you say is true, but it looks as though the lecturer was using "shallow" to mean reference identity, and "deep" to mean equivalence. The logic is certainly sound. – Ernest Friedman-Hill Apr 18 '11 at 15:31
2

First off: new Integer(0) == new Integer(0) will never evaluate to true, as new always creates a new object, sidestepping any autoboxing-caching mechanism that might exist.

What you probably heard about was autoboxing (i.e. automatic conversion of primitive values to their respective wrapper classes when necessary). Autoboxing uses a mechanism that's also accessible using the wrapper classes valueOf() methods. In other words: auto-boxing an int to an Integer works pretty much the same as calling Integer.valueOf(int).

Integer.valueOf(0) == Integer.valueOf(0) will evaluate to true, because common values (i.e. values with a low absolute value) are cached. You'll get the same Integer object when you call valueOf(0) twice in a row. This is not necessarily true with higher values (such as 666 in your example).

Joachim Sauer
  • 278,207
  • 54
  • 523
  • 586
1

equals() tests whether two objects are essentially the same, but it can return true for two distinct objects; i.e., two different paper clips are "equals". "==" for reference types tests whether two references refer to the same object -- i.e., a paper clip is == only to itself. == tests identity, which equals tests equivalence.

You could have two distinct Integer objects with a 0 in them (they are equals()); caching means saving objects and reusing them when possible.

Ernest Friedman-Hill
  • 77,245
  • 10
  • 138
  • 182
1

What you call "shallow equal" is identity: two references (i.e. objects) are identical if they are the very same instances. If you know what pointers are in other languages, you can compare identity to pointer equality.

What you call "deep equal" is equality: two objects a and b are equal if a.equals(b) returns true (and hopefully vice versa). The correctness of equality strongly depends on the way the equals method is implemented. See the Javadoc of the Object class for more details.

Laurent Pireyn
  • 6,457
  • 1
  • 26
  • 37