As discussed in 2-1 and 2-2, when a primitive type variable is declared, a certain memory space will be allocated based on the declared type, then the variable's initial value is stored in the allocated space. If this variable is assigned or copied to another variable, or if the variable is passed to a method as a parameter, the value of the variable is copied to the new variable or parameter.
In contrast, when an object variable is declared, we can not allocate the memory space based on the declared type because the space to store that class type is unknown. Instead, we have to use new to create the object, then store the reference to the object in the variable.
Similarly, arrays are also created with new, and array variables also store references.
So if objects or arrays are assigned, copied, or passed as parameters to other methods, the references are copied to the new variable or parameter. Some may argue that then references are the values of variables so essentially we are still pass by values. True. But keep in mind the end results are different.
Watch the Slides. Notice if an array is passed to a method as parameter, the changes made to the array elements are saved in the array and brought back to main(). This is not true if primitive type variables are passed to a method.
Try to create a public void swap(double a, double b) method to exchange the values of two double variables. Declare and initialize double x and double y in main() and see if you can swap the value of x and y by calling the swap method.