There are two types of variables in Java, primitive and reference type. All the basic types e.g. int, boolean, char, short, float, long and double are known as primitive types. JVM treats them differently than reference types, which is used to point objects e.g. String, Thread, File, and others. Reference variables are not pointers but a handle to the object which is created in heap memory. The main difference between primitive and reference type is that primitive type always has a value, it can never be null but reference type can be null, which denotes the absence of value. So if you create a primitive variable of type int and forget to initialize it then it's value would be 0, the default value of integral type in Java, but a reference variable by default has a null value, which means no reference is assigned to it.
If you try to access any field or invoke a method on a null reference, you will be greeted with NullPointerException in Java. It's very important for every Java developer to understand the difference between primitive and reference variables in different cases e.g. while assigning values, comparing values, passing them as method arguments, and returning them from methods, to avoid nasty errors e.g. null pointer exception.
In short, the main difference between the two types is that primitive types store actual values but reference type stores handle objects in the heap. Head First Java 2nd Edition also explains this key concept clearly, So you can also take a look there to understand it a bit more.
Here is a classification of all primitive and reference types in Java :
You can see that modification on one primitive variable doesn't affect the copy but it does in the case of the reference variable. This sometimes creates confusion between programmers that Java is not passed by value for the reference type, which is not correct, Java is always passed by value, be it references or primitive variables.
Here is a diagram which clearly shows the difference about how assignment operator works differently on primitive and reference variable in Java :
You can see that primitive variables are rightly compared using the == operator, but when we compared two String objects with the same contents i.e. "JPY", they are not equal using == operator, that's why the second line is not printed, but when I compared them using equals() method, they are considered equal. This means you should always use the equals() method to compare reference types.
If you try to access any field or invoke a method on a null reference, you will be greeted with NullPointerException in Java. It's very important for every Java developer to understand the difference between primitive and reference variables in different cases e.g. while assigning values, comparing values, passing them as method arguments, and returning them from methods, to avoid nasty errors e.g. null pointer exception.
In short, the main difference between the two types is that primitive types store actual values but reference type stores handle objects in the heap. Head First Java 2nd Edition also explains this key concept clearly, So you can also take a look there to understand it a bit more.
Difference between Primitive vs Reference variable
Now, we know the purpose of both types of variables, it's time to take a deep dive into some more differences between primitive and reference variables in Java.1. Default value and Null
The first difference between primitive and reference types is that the former can never be null if no value is assigned they take their default value e.g. boolean variable will be initialized with a false, byte, short, char,int and long will be initialized with zero, and float and double variables will be initialized with 0.0 value in Java.Here is a classification of all primitive and reference types in Java :
2. What do they store?
The second difference is that primitive types stores values but reference type stores handle objects in heap space. Remember, reference variables are not pointers like you might have seen in C and C++, they are just a handle to object so that you can access them and make some changes to the object's state.3. Assigning value using Assignment Variable (=)
When you assign a value to primitive data types, the primitive value is copied, but when you assign an object to reference type, the handle is copied. which means for reference type object is not copied only the handle is copied, i.e. the object is shared between two reference variables, known as aliases. An implication of this is modification done by one variable will affect to other.int i = 20; int j = i; j++; // will not affect i, j will be 21 but i will still be 20 System.out.printf("value of i and j after modification i: %d, j: %d %n", i, j); List<String> list = new ArrayList(2); List<String> copy = list; copy.add("EUR"); // adding a new element into list, it would be visible to both list and copy System.out.printf("value of list and copy after modification list: %s, copy: %s %n", list, copy); Output : value of i and j after modification i: 20, j: 21 value of list and copy after modification list: [EUR], copy: [EUR]
You can see that modification on one primitive variable doesn't affect the copy but it does in the case of the reference variable. This sometimes creates confusion between programmers that Java is not passed by value for the reference type, which is not correct, Java is always passed by value, be it references or primitive variables.
Here is a diagram which clearly shows the difference about how assignment operator works differently on primitive and reference variable in Java :
4. Comparison using == operator
When you compare primitive variables using equality (==) operator, their primitive values are compared but when you compare reference variable, their address is compared, which means two objects which are logically equal e.g. two String objects with same content may be seen as not equal, as seen below :int i = 20; int j = 20; if (i == j) { System.out.println("i and j are equal"); } String JPY = new String("JPY"); String YEN = new String("JPY"); if (JPY == YEN) { System.out.println("JPY and YEN are same"); } if (JPY.equals(YEN)) { System.out.println("JPY and YEN are equal by equals()"); } Output : i and j are equal JPY and YEN are equal by equals()
You can see that primitive variables are rightly compared using the == operator, but when we compared two String objects with the same contents i.e. "JPY", they are not equal using == operator, that's why the second line is not printed, but when I compared them using equals() method, they are considered equal. This means you should always use the equals() method to compare reference types.
5. Passing primitive and reference variable as method argument
When you pass primitive values to a method the values are passed to the method, but when you pass the reference variable, only the handle is copied. which means for primitives, changing the formal parameter's value doesn't affect the actual parameter's value.While in the case of reference types, changing the formal parameter's handle doesn't affect the actual parameter's address but changing the formal parameter's internal values does affect the actual parameter's object because they refer to the same object in memory. See Core Java Volume 1 10th Edition by Cay S. Horstmann to learn more.
For those, who are not aware of formal and actual parameters, formal parameters are those, which is listed(along with its type) in method declaration e.g. on getName(Employee e) , e is a formal parameter. While actual parameters are those which are passed to the method during invocation e.g. getName(new Employee("John")).
Here is the proof of I just said :
You can see that changing the formal parameter's value doesn't affect the actual parameter's value in the case of primitive variable but it does in the case of the reference variable, but only if you change the state of an object.
8. Memory consumption or Size
Primitive variables take less memory than reference variables because they don't need to maintain object metadata e.g. object header. An int primitive variable will take less memory than an Integer object for storing the same value e.g. 5.
That's all about the difference between primitive and reference variable in Java. Always remember that primitive variables are by default initialized to their default value, which is not null and they will not throw NullPointerException, but if you access an uninitialized reference variable it will throw NullPointerException.
Primitive variables are also copied when you assign them to another primitive variable and change on one variable will not affect other, but in the case of the reference variable, the handle is shared between multiple reference variable and any change into object's state will be visible to all reference variable.
Another key difference between primitive and reference variable to note is that former take less memory than later due to object metadata overhead e.g. memory require holding object header. An int primitive variable will always take less memory than an Integer object for storing same value.
Other related articles and interview questions you may find useful :
For those, who are not aware of formal and actual parameters, formal parameters are those, which is listed(along with its type) in method declaration e.g. on getName(Employee e) , e is a formal parameter. While actual parameters are those which are passed to the method during invocation e.g. getName(new Employee("John")).
Here is the proof of I just said :
/** * Program to demonstrate difference between primitive and reference type * variable in Java. * * @author WINDOWS 8 * */ public class PrimitiveVsReference{ private static class Counter { private int count; public void advance(int number) { count += number; } public int getCount() { return count; } } public static void main(String args[]) { int i = 30; System.out.println("value of i before passing to method : " + i); print(30); System.out.println("value of i after passing to method : " + i); Counter myCounter = new Counter(); System.out.println("counter before passing to method : " + myCounter.getCount()); print(myCounter); System.out.println("counter after passing to method : " + myCounter.getCount()); } /* * print given reference variable's value */ public static void print(Counter ctr) { ctr.advance(2); } /** * print given primitive value */ public static void print(int value) { value++; } } Output : value of i before passing to method : 30 value of i after passing to method : 30 counter before passing to method : 0 counter after passing to method : 2
6. The return value of a method
When you return primitive types from a method then the primitive value is returned but when you return a reference type, again only handle to the is returned. This means a locally created object can survive even after the method finishes its execution, if it was returned from a method or if it was stored in any member variable, why? because the object is always created in heap memory. while all primitive local variables are destroyed after the method finishes execution.7. Stack vs Heap
Primitive variables are created in the stack while reference variable is created in heap space, which is managed by Garbage Collector. See the difference between stack and heap memory in Java, for more details.8. Memory consumption or Size
Primitive variables take less memory than reference variables because they don't need to maintain object metadata e.g. object header. An int primitive variable will take less memory than an Integer object for storing the same value e.g. 5.
That's all about the difference between primitive and reference variable in Java. Always remember that primitive variables are by default initialized to their default value, which is not null and they will not throw NullPointerException, but if you access an uninitialized reference variable it will throw NullPointerException.
Primitive variables are also copied when you assign them to another primitive variable and change on one variable will not affect other, but in the case of the reference variable, the handle is shared between multiple reference variable and any change into object's state will be visible to all reference variable.
Another key difference between primitive and reference variable to note is that former take less memory than later due to object metadata overhead e.g. memory require holding object header. An int primitive variable will always take less memory than an Integer object for storing same value.
Other related articles and interview questions you may find useful :
- What is the difference between C++ and Java constructors? (answer)
- Difference between SOAP and REST Web Service in Java? (answer)
- Difference between HashMap, TreeMap and LinkedHashMap in Java? (answer)
- What is the difference between direct, non-direct and mapped buffer in Java? (answer)
- What is the difference between Factory pattern and dependency Injection? (answer)
- How do you calculate the difference between two dates in Java? (answer)
- Difference between Composition and Inheritance in OOP? (answer)
- 10 differences between JavaScript and Java? (answer)
- Difference between Maven, ANT and Jenkins in Java world (answer)
- Difference between ArrayList and LinkedList in Java? (answer)
- What is difference between transient and volatile variable in Java? (answer)
- Some key difference between Vector and ArrayList in Java? (answer)
- Difference between get() and load() method in Hibernate? (answer)
Actually, only Instance Variables get a default value. Local variables do not get a default value, you must initialize them manually. If you don't initialise a loval variable before using it the compile will return an error.
ReplyDeleteThanks @Joseph, that's true, but not just instance variable but static variable also get initialized with default value. In short, member variable get initialized with default value e.g. 0 for int, 0.0 for float and double, false for boolean, and null for reference type.
ReplyDeleteLocal variables doesn't automatically initialized by default value, you must initialize them before using and compiler check for that. If you use them without initializing, you will get error.
Once again Thanks to @Joseph, for such nice comment, which add value into article.
Thank you for this article, it is very thorough.
ReplyDeleteOne comment though, in Program to demonstrate difference between primitive and reference type, I suppose you meant to write:
print(i) and not print(30)
Thanks, i really helped
ReplyDeleteWhat is the term handle refer to....is it the object reference variable ?
ReplyDelete