Win a copy of Java 9 Revealed this week in the Features new in Java 9 forum!
  • Post Reply Bookmark Topic Watch Topic
  • New Topic

Any hint on why == and equals() are like irregular Latin verbs?  RSS feed

 
Fred Wolf
Greenhorn
Posts: 9
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi all,

other thing that is puzzling me - normally programming languages should be orthogonal - you should get from an API what you would expect
and verbs should be used in an identical fashion across classes and interfaces. So far I thought that Java was comparably modern and hence orthogonal

After studying for the Java 8 OCA exam it seems to me that this is partially like irregular latin verbs and less like a well structured instruction set
If you look at the attached chart, I dont see any system what to expect from == and equals() despite that one has to learn i verbatim
Normally I like to see some elegant logical structure behind a language :-) at least a programming language

Any suggestions how to best learn this apart from accepting that that's the was it is - and basta ;-). Is there any regularity which I did not see yet?

Thanks, Wolfgang


Bildschirmfoto-2017-06-12-um-21.33.36.png
[Thumbnail for Bildschirmfoto-2017-06-12-um-21.33.36.png]
Semantics of Equality operators function
 
Henry Wong
author
Sheriff
Posts: 23026
120
C++ Chrome Eclipse IDE Firefox Browser Java jQuery Linux VI Editor Windows
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Fred van de Code wrote:
Any suggestions how to best learn this apart from accepting that that's the was it is - and basta ;-). Is there any regularity which I did not see yet?


First, where do you get the chart that you included? Second, I would probably recommend using some other source materials -- as it is ... well ... wrong (with a few of the boxes).

Henry
 
Fred Wolf
Greenhorn
Posts: 9
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
After missing something similar in e.g an OCA Study Guide I "hacked my way through examples" and made some notes, resulting in the chart
I would really appreciate a better one ... Have you got a suitable pointer to some better content? In this case lets delete the chart
 
Henry Wong
author
Sheriff
Posts: 23026
120
C++ Chrome Eclipse IDE Firefox Browser Java jQuery Linux VI Editor Windows
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Fred Wolf wrote:
I would really appreciate a better one ... Have you got a suitable pointer to some better content? In this case lets delete the chart


The wrapper section is backwards. Wrappers behave similar to the String operations ... the == operator is for reference comparison, and the equals() method is for value comparison.

The == row for "others" is wrong. It is not "mostly"; it is always a reference comparison.

The equals() row for "others" is debatable. And arguably, not very useful. In most cases, where the instance represents some sort of data, then the equals() method is overridden, and it is a value comparison. For the cases, where it is not representative of data, then the equals() method is not overridden, and it is a reference comparison. However, should these cases be even counted? As there is no reason to compare the values, when they don't have a value? 

Henry
 
Campbell Ritchie
Sheriff
Posts: 54033
130
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
. . . and welcome to the Ranch
 
Campbell Ritchie
Sheriff
Posts: 54033
130
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Fred Wolf wrote:. . . I thought that Java was comparably modern and hence orthogonal . . .
Apart from the fact that orthogonal doesn't mean same . . .

Java® is twenty‑one years old. There are only a few languages still in common use which are much older. If you look in the TIOBE index, you will find the top hundred languages discussed on the Net. I counted twelve older than Java® in this month's list, though Lisp appears about four times. [SQL doesn't appear in Tiobe, but I think it is older than Java®.] So Java® is already battle‑scarred. Each upgrade causes problems, because Sun and Oracle (unlike some language manufacturers) maintain backward compatibility. That means that code written and compiled in 1999 can still be executed today exactly as it had been when it was compiled. Now, let's look at this code in the pre‑2004 setting, without boxing:-That will print true…false.
Now let's imagine you recompile that code with post‑2004 code (Java5, supporting boxing and unboxing). Let's imagine that the definition of == has changed to support unboxing. So the == operator and equals() method behave as shown in the diagram?
Now, if you compile and run the same code, will it print true…true ? You have to maintain the meaning of == as it had been, so it still shows referential equality, not content equality. I think it was Rob Spoor who first explained that to me. Now the code will behave the same on old and on new JDKs.

There are other errors in the diagram; I think that equality of content is incorrect for some primitive types, too. The contents of the double 2.0 and the int 2 are different, but they will return true from ==. And there are a few primitive values with identical content which return false from ==. As Henry says, please tell us where that table comes from. We need to know to avoid that source
 
Jesper de Jong
Java Cowboy
Sheriff
Posts: 15890
82
Android IntelliJ IDE Java Scala Spring
  • Likes 2
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Your chart contains many things that are incorrect.

The == operator

== really always means: "compare values", but you have to be carefully think about what this means for primitive types vs. reference types.

For primitive types, it's easy: it just compares the values.

For reference types, it also compares values, but it compares the values of the references themselves, and not the values contained in the objects that the references point to. So, an == comparison between references is only true if the two references point to the exact same object. It's false if they point to two distinct objects, even if the member variables of those two objects have the same values.

Note that there is no special handling for strings or wrapper classes with regards to ==. These are handled just like any other reference type. So the columns in your chart for strings, wrappers and other types are incorrect.

The equals() method

equals() is just a method, like any other method. What it means depends on the implementation of the particular class of the object that you're calling it on.

The implementation in class Object does the same as ==. So, if the object you are calling it on is of a class that doesn't override the equals() method of class Object, then equals() behaves the same as == (see above).

Of course, many classes, including String and the wrapper classes, do implement equals() in such a way that they compare the content of the member variables of the objects. So, for example, if you have two separate String objects with the same content, then a.equals(b) will return true.

Things that make it confusing

The rules above are how it works, but there are some optimizations that make it seem like these rules are sometimes broken. In reality the rules above are not broken, it just seems that way.

String literal optimization

For example, the compiler optimizes how string literals are handled. If you use the same string literal more than once in one program, then the compiler is smart enough to detect that and create just a single String object for that literal, which is reused. So, if you create two variables with two times the same string literal, then == between them will be true - because there is, in fact, only one String object that both variables refer to.


Wrapper type optimization and autoboxing

This one is confusing for a lot of people, and you can only understand it if you know how autoboxing works and about a specific optimization that's present in the wrapper classes.

First of all, autoboxing. If you assign a primitive literal value to a variable of a wrapper type, then that is automatically translated to a call to WrapperType.valueOf(...). For example:

Then, the second part. The valueOf(...) method of class Integer doesn't simply return a new Integer object every time you call it. If the value is between -128 and 127, it will return an object from an internal cache. This is an optimization to avoid creating lots of unnecessary objects, for values that are supposedly frequently used. Note that if the value is outside of the range of the cache, it will return a new object.

The == operator reveals this:

As you can see it seems like == on Integer objects sometimes does value comparison, and sometimes does reference comparison. But this is not really so. It always does reference comparison, but due to the optimization, you get the same Integer object if it's in the range of the cache.
Bildschirmfoto-2017-06-12-um-21.33.36.png
[Thumbnail for Bildschirmfoto-2017-06-12-um-21.33.36.png]
Corrected chart
 
Campbell Ritchie
Sheriff
Posts: 54033
130
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Jesper de Jong wrote:. . . . The valueOf(...) method of class Integer doesn't simply return a new Integer object every time you call it. If the value is between -128 and 127, it will return an object from an internal cache.  . . .
That is one reason why I made sure to write new Integer(123), another being that the valueOf(int) method wasn't available in those olden days.
It is also possible that values outwith the range −128…127 will be cached; read more about it in the valueOf(int) method and the Java® Language Specification (=JLS). The JLS can be difficult to read, but I think that is one of its easier parts.
 
Fred Wolf
Greenhorn
Posts: 9
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Cool insights - thanks a lot
 
  • Post Reply Bookmark Topic Watch Topic
  • New Topic
Boost this thread!