1. Reference variables
In the Java language, there are two kinds of variables: primitive variables and everything else. As it happens, we're going to talk about "everything else" now.
In fact, it would be more correct to say that there are primitive variables and reference variables. So what are these reference variables?
Unlike primitive types, whose variables store values directly, reference variables store references to objects. That is, there is an object somewhere in memory, and the reference variable simply stores the address of this object in memory (a reference to the object).
Only primitive types store values directly inside variables. All other types store only an object reference. By the way, you have already encountered two such types of variables —
String variables and array variables.
Both an array and a string are objects stored somewhere in memory.
String variables and array variables store only references to objects.
int a, int b and double d are primitive variables that store their values inside themselves.
String str variable is a reference and stores the address (reference) to a
String object in memory.
When assigning a primitive value to a variable of a primitive type, its value is copied (duplicated). When assigning a reference variable, only the address of the object is copied — the object itself is not copied.
2. What are references all about?
What's the fundamental difference between reference variables and primitive variables?
A primitive variable is like a box: you can store some value in it. A reference variable is more like a piece of paper with a phone number on it.
A car vs keys to the car
Imagine you decide to give your friend a car for his birthday. You won't wrap it in a box and carry it with you: the car is too big for that.
It is much more convenient to present just the car keys in a box large enough to contain them. Your friend will understand everything when he gets the keys out of the box. There's no need to carry the entire car with you when you can simply hand over the keys.
A person vs her phone number
Or here's another comparison: a person and her phone number. A phone number is not the person, but a phone number can be used to call her, ask her for some information, or provide instructions.
Similarly, a reference is used to interact with an object. All objects interact with each other using references. Instead of "exchanging people", we simply exchange phone numbers.
When assigning a value to a primitive variable, its value is copied (duplicated). When assigning a value to a reference variable, only the address (phone number) of the object is copied — the object itself is not copied.
A reference offers one more advantage: you can pass an object reference to some method, and the method will be able to modify (change) the object by using the reference to it, calling its methods and accessing data inside the object.
3. Assigning references
When assigning reference variables, only the object's address in memory is assigned. Objects themselves do not appear or disappear.
This approach avoids copying large amounts of memory. If you need to pass a very large object to a method, we just pass the object reference and that's it. The reference takes up much less space.
The size of all reference variables (regardless of their type) is the same — 4 bytes (like an int). But! If your application is running on a 64-bit Java machine, then all references will be 8 bytes (64 bits) in size.
What's more, references can only be assigned to each other. You cannot change references or assign arbitrary values to reference variables:
|This is allowed|
|But this is not allowed|
|And this is not allowed|
And what does a reference variable store if nothing has been assigned to it yet?
It stores a null reference.
null is a special Java keyword meaning the absence of a reference (an empty reference). The
null value can be assigned to any reference variable.
All reference variables are
null unless they have had some kind of reference assigned them.
Local variables that have not been assigned a value are considered uninitialized for both primitive and reference types.
If a variable stores a reference to some object, and you want to clear the variable's value, then just assign it a null reference.
5. Passing references to methods
If a method has parameters that are reference types, then values are passed to the method in the same way as when working with non-reference variables. The parameter is simply assigned the value of the other variable.
fill method is called, the
array parameter is assigned a reference to the
data array. The
value variable is assigned a reference to the string object ("Hello").
This is what memory looks like before calling the
This is what memory looks like when the
fill method is running:
array variables refer to (store references to) the same container in memory.
value variable stores a reference to the string object (
The cells of the array also just store references to the
In fact, no objects are duplicated — only references are copied.
6. Comparison with the C/C ++ language
In interviews, sometimes Java programmers are asked how data is passed to methods in Java? And sometimes the question is whether data is passed by reference or by value?
This question comes from C++, but isn't very meaningful in Java. In Java, parameters are always simply assigned the values of the arguments. So the correct answer would be "by value".
But be prepared to explain your position, since you may immediately hear the retort: "primitive types are passed by value, and reference types are passed by reference."
This origin of this issue stems from the fact that many Java programmers were C++ programmers in the past. In that programming language, the question of how parameters are passed to methods was very important.
In Java, everything is unambiguous: primitive types store values and reference types also store a value — a reference. It's a question of whether a variable is considered a value.
In C++, a variable could store both a reference to an object and the object itself. The same was true about primitive types: a primitive variable could store a value or declare the variable as a reference to an
int. So, to avoid confusion, C++ programmers always refer to the object to a reference as a reference, and the object itself — as a value.
In C++, you could easily have the situation where one variable contains an object, but the other contains a reference to that object. Accordingly, the question of what a variable stores — the object itself or just a reference to it — was very important. When an object was passed to a method, it was copied (if passed by value), and not copied (if passed by reference).
In Java, this duality does not exist, so the correct answer is: arguments are passed to Java methods by value. It's just that when we're talking about reference variables, this value is a reference.