One important difference between the reference types and primitive types that merits special discussion is the way their values can be used in a method. Let's see the difference by example. First, we create the SomeClass class:
class SomeClass{
private int count;
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
}
Then we create a class that uses it:
public class ReferenceTypeDemo {
public static void main(String[] args) {
float f = 1.0f;
SomeClass someClass = new SomeClass();
System.out.println("\nBefore demoMethod(): f = " + f +
", count = " + someClass.getCount());
demoMethod(f, someClass);
System.out.println("After demoMethod(): f = " + f
+ ", count = " + someClass.getCount());
}
private static void demoMethod(float f, SomeClass someClass){
//... some code can be here
f = 42.0f;
someClass.setCount(42);
someClass = new SomeClass();
someClass.setCount(1001);
}
}
Let's look inside demoMethod() first. We have made it very simple for demo purposes, but assume it does more, and then assigns a new value to the f variable (parameter) and sets a new count value on the object of the SomeClass class. Then this method attempts to replace the passed-in reference with a new value that points to a new SomeClass object with another count value.
In the main() method, we declare and initialize the f and someClass variables with some values and print them out, then pass them as the parameters to the demoMethod() method and print the values of the same variables again. Let's run the main() method and see the results that should look like the following:
![](assets/3fe7f190-7bc0-4bc5-bf1b-90634245d199.png)
To understand the difference, we need to take into account these two facts:
- Values to a method are passed by copy
- Value of a reference type is a reference to a memory where the referred object resides
That is why when the primitive value (or String, which is immutable as we have explained already) is passed in, the copy of the actual value is created, so the original value cannot be affected.
Similarly, if the reference to an object is passed in, only its copy is accessible to the code in the method, so the original reference cannot be changed. That is why our attempt to change the original reference value and make it refer another object did not succeed, either.
But the code inside the method is able to access the original object and change its count value using the copy of the reference value because the value still points to the same memory area where the original object resides. That is why code inside the method is able to execute any method of the original object, including those methods that change the object's state (values of the instance fields).
This change of an object state, when it was passed in as a parameter, is called a side-effect and is sometimes used, when the following occurs:
- A method has to return several values but it is not possible to do it via returned construct
- The programmer is not skilled enough
- A third-party library or a framework utilizes the side-effect as the primary mechanism of getting back the result
But the best practices and design principles (the Single Responsibility Principle in this case, which we will discuss in Chapter 8, Object-Oriented Design (OOD) Principles) guide programmers to avoiding side-effects, if possible, because side effects often lead to a not-very-readable (for a human) code and subtle runtime effects that are difficult to identify and fix.
One has to distinguish a side effect and a code design pattern called Delegation Pattern (https://en.wikipedia.org/wiki/Delegation_pattern), when the methods invoked on the passed-in objects are stateless. We will talk about design patterns in Chapter 8, Object-Oriented Design (OOD) Principles.
Similarly, a side effect is possible when an array is passed in as a parameter. Here is the code that demonstrates it:
public class ReferenceTypeDemo {
public static void main(String[] args) {
int[] someArray = {1, 2, 3};
System.out.println("\nBefore demoMethod(): someArray[0] = "
+ someArray[0]);
demoMethod(someArray);
System.out.println("After demoMethod(): someArray[0] = "
+ someArray[0]);
}
private static void demoMethod(int[] someArray){
someArray[0] = 42;
someArray = new int[3];
someArray[0] = 43;
}
}
The result of the preceding code execution is as follows:
![](assets/4431c564-3f1d-4148-87b7-126c30401e9d.png)
You can see that despite the fact that, inside the method, we were able to assign a new array to the passed-in variable, the assignment of value 43 affected only the newly created array, but had no effect on the original array. Yet, the change of an array component using the passed-in copy of the reference value is possible because the copy still points to the same original array.
And, to close the discussion about reference types as method parameters and possible side effects of that, we would like to demonstrate that the String type parameter—because of the String value immutability—behaves like a primitive type when passed in as a parameter. Here is the demo code:
public class ReferenceTypeDemo {
public static void main(String[] args) {
String someString = "Some string";
System.out.println("\nBefore demoMethod(): string = "
+ someString);
demoMethod(someString);
System.out.println("After demoMethod(): string = "
+ someString);
}
private static void demoMethod(String someString){
someString = "Some other string";
}
}
The preceding code yields the following results:
![](assets/c29f1c82-c6e0-4f44-8f20-d3e72a10bcdb.png)
The code inside the method was not able to change the original parameter value. The reason for that is not – as in the case of a primitive type – that the parameter value was copied before being passed into the method. The copy, in this case, still pointed to the same original String object. The actual reason is that changing a String value does not change the value, but creates another String object with the result of the change. That is the String value immutability mechanism as we have described it in the String type and literals section. The reference to this new (changed) String object assigned to the copy of the reference value passed in and has no effect on the original reference value that still points to the original String object.
With that, we conclude the discussion about Java reference types and String.