Consider the following code:
Values for primitive variables such as i
and j
are stored directly in some
RAM location.
However objects are never stored in variables.
Instead all objects are creating using a different area of RAM
known as the heap.
Variables such as name1
and name2
do
not contain objects, but rather the RAM address of objects.
For this reason Java refers to non-primitive variables not as
object variables, but rather as object reference variables.
It may help to know something about how a compiler works. When compiling a program a compiler builds a table known as the symbol table. This table is added to for each variable seen in the program. It has columns for the name, type, and RAM location for each variable. Initially the RAM location is blank—the compiler fills in that column last.
Name | Type | RAM Address |
---|---|---|
args | String array ref | 100 |
i | int | 104 |
j | int | 108 |
name1 | String ref | 112 |
name2 | String ref | 116 |
⋮ | ⋮ | ⋮ |
Before producing compiled output (the .class
file), the
symbol table is filled in with actual RAM addresses to use for each
variable.
Then when producing byte code the compiler replaces the name of variables
with the RAM addresses from the symbol table.
The layout of RAM for this program would look something like the following,
when the program gets to line 14:
When producing byte code for lines 5 and 6 the Java compiler produces something like:
STORE "17" into RAM location 104 STORE "22" into RAM location 108
For lines 7 and 8 of the program above, the output is different. It becomes something like:
CREATE String object in next available heap location with initial value "Joe" ⇒ Object created at RAM location 1460 STORE "1460" into RAM location 112 CREATE String object in next available heap location with initial value "Jane" ⇒ Object created at RAM location 1520 STORE "1520" into RAM location 116
So what is produced for lines 10 and 12? The results are as you might expect. For line 10:
COMPARE contents of RAM locations 104 and 108 ⇒ set result to False (17 not equal to 22)
When the program is run you will not see “i equals j
” displayed.
You won't see “name1 equals name2
” either.
The reason is the byte code produced for line 12 is essentially the same
as for line 10:
COMPARE contents of RAM locations 112 and 116 ⇒ set result to FALSE (1460 not equal to 1520)
Many expect Java to compare the contents of RAM locations 1460 and 1520,
but that isn't what Java does.
It is only comparing the object references, not the objects themselves.
To compare the objects and not the object references you can't use the
"==
" operator.
Instead you use the "equals
" method, something like:
if ( name1.equals(name2) )
Will cause the Java compiler to produce byte code to compare the contents
of the String
objects in RAM locations 1460 and 1520.
After lines 15–15, the memory looks like this:
It should be clear that this time, you will see “i equals j
”
(lines 17–18).
You will also see “name1 equals name2
” (lines
19–20).
Note that no variable refers to the Joe
string anymore.
It should be clear that at this point (after line 16) not only does
“name1 == name2
”, but also that
“name1.equals(name2)
”.