27

I have a piece of code which I need to understand:

public static void main(String[] args) {
    Character c = new Character('a');
    Character cy = new Character('a');
    char cx = 'a';

    System.out.println(c == cx);
    System.out.println(cx == cy);
    System.out.println(c == cy);
}

Output:

true
true
false

I am unable to understand why only the third statement is failing.

EDIT: This question is different to the .equals vs == question as this about primitive versus object comparison.

Boann
  • 48,794
  • 16
  • 117
  • 146
Fr_nkenstien
  • 1,923
  • 7
  • 33
  • 66
  • 5
    not quite, char primitive to object matching is working whereas the object to object matching is not...so i wondered why – Fr_nkenstien Apr 11 '16 at 10:12
  • Why is `new Object() == new Object()` false? – user253751 Apr 11 '16 at 20:53
  • 2
    "This question is different to the .equals vs == question as this about primitive versus object comparison." No, it really isn't, since understanding that difference naturally explains this one. `==` does reference comparison; once you recognize that, the answer is trivial. – jpmc26 Apr 11 '16 at 23:54
  • See also http://stackoverflow.com/questions/2831945/is-it-guaranteed-that-new-integeri-i-in-java – Raedwald Apr 12 '16 at 08:49
  • @jpmc26 Except that that's wrong. `c` is a reference but `c == cx` doesn't do a reference comparison. The question is not the same. – Boann Apr 12 '16 at 13:38
  • @Boann The question is why `c == cy` returns `false`, not why `c == cx` returns `true`. Granted the OP may be confused on the latter point, but that could have been researched or asked if they applied the knowledge about reference comparison to `c == cy`, instead of wrongly assuming that the other comparisons implied it should be `true`. – jpmc26 Apr 12 '16 at 15:40

4 Answers4

45

c and cy refer to different instances of the Character class (each time you invoke a constructor, you create a new instance), so comparing these references returns false.

On the other hand, when you compare either of them to the primitive cx, they are unboxed to char, and the char comparison returns true.

Had you used Character.valueOf('a') instead of new Character('a'), you would have gotten the same instance in both calls, and the reference comparison would have returned true (since valueOf returns a cached Character instance if the argument <= 127).

Eran
  • 387,369
  • 54
  • 702
  • 768
  • 8
    This part of Java is very confusing (not only) for beginners unfortunately. Since Java 5 there is autoboxing, which tries to be helpful but makes the behaviour of `==` even for tricky. Before autoboxing, I believe the compiler would have rejected the first two comparisons. – Thilo Apr 11 '16 at 10:02
  • 6
    Note that `Character a = Character.valueOf('a')` can be shortened to `Character a = 'a'` and that even `valueOf` will return instances that are not equal for non-ASCII characters. – Thilo Apr 11 '16 at 10:03
  • 1
    Good IDEs can be configured to give a warning when boxing and unboxing will occur, as it does here. – Danikov Apr 11 '16 at 12:53
  • @Thilo I don't see any auto-boxing the question, only auto-*un*boxing. – CodesInChaos Apr 11 '16 at 15:16
25
 System.out.println(c == cx);
 System.out.println(cx == cy);

Since one is primitive and another is a wrapper class of it, unboxing happens and primitive comparison takes place (==).

Whereas:

 System.out.println(c == cy);

is an Object comparison. Different instances are getting compared so == won't work in this case.

Boann
  • 48,794
  • 16
  • 117
  • 146
Suresh Atta
  • 120,458
  • 37
  • 198
  • 307
-1

Charcter class is not singleton, so always a new object will be creating when calling the contructor and new objects refer to their respective references.So (c == cy) gives you false

SpringLearner
  • 13,738
  • 20
  • 78
  • 116
  • 1
    why do the other two comparisons give us true, then? – Thilo Apr 11 '16 at 10:09
  • @Thilo for other comparison(involving primitive) boxing and autoboxing will happen – SpringLearner Apr 11 '16 at 10:27
  • 1
    Even for Singletons each invocation of the constructor creates a new instance. It's just that invoking the constructor is made harder. – Hulk Apr 11 '16 at 10:46
  • @Hulk In singleton constructor is called once – SpringLearner Apr 11 '16 at 10:51
  • 1
    Yes, that is what the pattern is trying to achieve. Still, their constructor is not special in any way (except that it has the private-modifier), and *if* you invoke the constructor a second time, you get a separate instance. – Hulk Apr 11 '16 at 10:56
  • @Hulk the only way would be using reflection... and that's off-topic – SparK Apr 11 '16 at 12:22
  • 2
    @SparK as is Singleton - it has nothing to do with the question. – Hulk Apr 11 '16 at 12:32
-2

it's obvious why the last comparision gives false: both Characters are explicitly initialized with new, thus being different objects

why the first two comparisions give true, however, is only partly clear: the char value is definitely used to retrieve a pre-stored Character instance, but I don't know how exactly the pre-defined Character objects are mapped to this pre-stored instance

I would expect, though, it works like "=="-comparision for String objects: if at compile time one of the compared instances is a pre-stored Character then the compiler inserts a call to equals() replacing the "=="-comparision

Egor Hans
  • 206
  • 1
  • 11
  • 3
    It's the opposite (as others have already correctly explained): [15.21.1. Numerical Equality Operators == and !=](https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.21.1): `If the operands of an equality operator are both of numeric type, or one is of numeric type and the other is convertible (§5.1.8) to numeric type, binary numeric promotion is performed on the operands (§5.6.2). Note that binary numeric promotion performs value set conversion (§5.1.13) and may perform unboxing conversion (§5.1.8).` So what's happening is unboxing, not boxing. – Hulk Apr 11 '16 at 11:59
  • 1
    The char value is not at all ("definitely") used to retrieve a Character instance - instead the other side of the `==` is converted to a primitive character. And the compiler never replaces `==` with equals. Not for String objects, not for Character objects, not for any type of object. – Erwin Bolwidt Apr 13 '16 at 15:16
  • But how come then that for Strings, `==` behaves just like `equals()`? It can't be array unboxing, that would do ref compare again, and from all I know operators can't be carried over as natives... – Egor Hans Jun 14 '16 at 13:04