Dev Learning Lab

The labs on this site need JavaScript to run. The same content is written out below.

Learn › Java › Basic syntax

Variables and types

What is copied when you assign one variable to another?

A variable is a storage location that holds something. A variable of a primitive type such as int holds the value itself, and a variable of a reference type such as a class type holds a reference that points to where an object is. Whether you assign a variable or pass it to a method, what is copied is always "what the variable holds". So with a primitive type the original variable stays the same when you change the copy, and with a reference type the two variables end up looking at the same single object.

Checked against real execution · Checked by running 15 combinations on JDK 21

Concepts in this lab

Primitive types and reference types
These are the two kinds into which the types of Java are divided. There are eight primitive types, byte, short, int, long, float, double, char, and boolean, and a variable of one of them holds the value itself. Reference types are all the other types, such as classes, interfaces, and arrays, and a variable of one of them holds a reference to an object, not the object itself. So assigning a variable of a primitive type copies the value, and the two variables do not affect each other, but assigning a variable of a reference type copies the reference, and the two variables come to refer to the same object. A variable of a reference type can hold null, which means that it refers to no object, and a variable of a primitive type cannot hold null.
Pass by value
This is a way of calling a method in which what is copied into the parameter is not the variable written as the argument but what that variable holds. It is also called call by value, and Java always passes arguments this way and in no other way. For a primitive type the value is copied, and for a reference type the reference is copied, so the parameter and the variable of the caller refer to the same object. That is why a change that the method makes to the contents of the passed object is visible to the caller, but assigning a different object to the parameter does not change the variable of the caller.
Immutable object
This is an object whose state does not change after it is created. Because its value never changes, it is safe for several threads to use at the same time, you can pass it to other code without worrying that it will be changed, and it is well suited for caching or for use as a key in a hash collection. Declare the fields private final, provide no methods that change the state, and make the class final so that a subclass cannot change its behavior. If a field refers to a mutable object (such as a List or a Date), the constructor and the getters pass copies in and out (defensive copying) so that outside code cannot change the internals.
Heap memory
This is the memory area where every object and array created with new is stored, and it is shared by all threads. The garbage collector manages it and reclaims objects that are no longer used. Its size is set with the -Xms (initial) and -Xmx (maximum) options, and an OutOfMemoryError occurs when it runs out of space.

Try these

Running with the default settings

  1. Point a = new Point(1): new creates one Point object on the heap (x is 1). The variable a holds a reference that points to where that object is, not the object itself.
  2. Point b = a: The reference that a holds is copied and stored in b. The object is not copied. There is still only one object, and a and b refer to the same object.
  3. b.x = 99: Java follows the reference in b and changes the x of that object to 99. What b itself holds does not change. a refers to this very object too.
  4. System.out.println(b.x): b refers to an object, and the x of that object is read. The output is 99.
  5. System.out.println(a.x): The x of the object that a refers to is read. The output is 99. b was used to change the very object that a refers to.

Result of this run

Code

class Point {
    int x;
    Point(int x) { this.x = x; }
}

Point a = new Point(1);
Point b = a;                        // the reference in a is copied
b.x = 99;                           // changes the contents of the object it refers to

System.out.println(b.x);
System.out.println(a.x);

Assumptions of this model

The output of the 15 combinations (the value read from the copy and the value read from a) was checked against the result of running code with the same structure on JDK 21 on this PC. "Reference" is used here to mean a value that points to where an object is. In Java you cannot take this value out and look at it as a number, and whether it is actually a plain memory address differs from one JVM to another. The picture in which variables are placed on the stack and objects on the heap is the usual explanation for local variables, and when the JIT compiler optimizes the code, an object may not be created on the heap at all, but the result of the program is the same. The string "hi" is actually an object in the string pool, but here it is drawn simply as one object on the heap. The frame that is created when a variable is passed to a method is covered in the "Stack and heap" lab, and the difference between == and equals is covered in the "== and equals" lab.

Next lab: Operators and type conversion

Concepts in this lab

What this lab shows

Settings

Code


      
    

Diagram

Run comparison

Try these