Why Java Is a Purely Object-Oriented Language... Or Why Not
Java—is it actually object-oriented? Let's take a look deep into Java to try to figure it out.
Join the DZone community and get the full member experience.
Join For FreeSome years back when I started learning Java, I got to know that Java follows the Object-Oriented Programming paradigm and that everything in Java is an object—either a String (which was a char array in C) or an array itself.
But later on I found people saying on the Internet that Java is actually not purely Object-Oriented, as everything in Java is not an object; for example:
- All primitive types (char, boolean, byte, short, int, long, float, double) are not objects because we are not able to do any object-like operations (using "." and calling methods) on them.
- I have also found some people some saying that all static content (variables and methods) does not belong to any object so they are non-object things.
Due to my little knowledge and less experience, I easily accepted these reasons and started to believe that Java is not a purely Object-Oriented Programming Language.
But later on I found that for every object JVM creates two objects:
- The object itself.
- And one Class level object (referred by ClassName.class syntax) which gets created only once while the Classloader loads the class into memory. All static content of that class belongs to this Class object and all other objects of that class refer to this class-level object for all static content.
For example, in the following statement, there will be two objects created:
Employee emp = new Employee();
One is emp itself, and another one is the class-level object of the employee class, which we can refer by Employee.class. And this class level object holds all the static content of Employee class either it is a variable or method. If we are accessing any static content through the emp object, it points to the Employee.class object to access that.
That is the reason why a static variable gets changed for every object even if we change it for a single emp object because all emp objects are pointing same copy of that variable from the Employee.class object.
Now the 2nd point gets canceled because static content belongs to an object. But the 1st point is still there, and we still have primitive data types in Java, and they are not objects.
As mentioned earlier, primitive types are not objects because we can’t perform any object-related functionality on them. To overcome this problem Java introduced Wrapper classes for every primitive type (e.g. Integer for int, Long for long, Character for char). Now we can create objects for primitive types and perform all object-related operations on them.
And due to autoboxing (automatic unboxing-boxing, boxing-unboxing), we can directly assign a primitive literal to its Wrapper class reference. But we still can’t perform these operations on primitive variables—we always need to create objects of the respective Wrapper class.
For example:
Integer obj = new Integer(5); // here we can do i.toString();
int i = 5; // but we can't do i.toString() here
So far it is clear that primitive types are not objects, but that’s actually an end-user perspective (Java developers are end-users of Java because we are using it, not creating it).
JVM internally treats all primitive types as objects, and proof of this can be found in source code or the Javadoc of the class Class. According to the source code of class Class:
Instances of the class Class represent classes and interfaces in a running Java application. An enum is a kind of class and an annotation is a kind of interface. Every array also belongs to a class that is reflected as a Class object that is shared by all arrays with the same element type and number of dimensions. The primitive Java types (boolean, byte, char, short, int, long, float, and double), and the keyword void are also represented as Class objects.
And the Javadoc code of Class.isPrimitive() method:
public boolean isPrimitive()
Determines if the specified Class object represents a primitive type.
There are nine predefined Class objects to represent the eight primitive types and void. These are created by the Java Virtual Machine, and have the same names as the primitive types that they represent, namely boolean,byte, char, short, int, long, float, and double.
These objects may only be accessed via the following public static final variables, and are the only Class objects for which this method returns true.
Returns:
true if and only if this class represents a primitive type
Since:
JDK1.1
See Also:
Boolean.TYPE, Character.TYPE, Byte.TYPE, Short.TYPE, Integer.TYPE, Long.TYPE, Float.TYPE, Double.TYPE, Void.TYPE
If you open the Javadoc of class Class and do a Ctrl + F for the word “primitive,” you will find many reasons to believe that JVM treats all primitive types as objects internally.
Let’s open the Integer.TYPE entry from above. In this section you will find:
public static final Class< Integer> TYPE
The Class instance representing the primitive type int.
And if you write the following line in your program using Eclipse:
Integer.TYPE i = 5;
You will get a compilation error saying Integer.TYPE cannot be resolved to a type with a hint from Eclipse to change it to an int.
Why Should We Use Primitive Types
So if JVM creates objects for all primitive types, why do we need to use primitive types instead of creating objects with respective Wrapper classes? That’s because JVM creates these native objects for primitive types internally, and those objects are very lightweight and more optimized than their respective wrapper class objects; because of this they have less functionality (e.g. we can’t call methods on them because they don’t have any).
We should use primitive types:
- Because they are fast (e.g. the following program takes 9 seconds to run on my machine, while it takes 0 seconds if I convert Long sum to long sum... if that's any indication why we use primitives).
public static void main(String[] args) {
long millis = System.currentTimeMillis();
Long sum = 0L; // uses Long, not long
for (long i = 0; i <= Integer.MAX_VALUE; i++) {
sum += i;
}
System.out.println(sum);
System.out.println((System.currentTimeMillis() - millis) / 1000);
}
- They allow us to use the native equality operator "==":
new Integer(3) == new Integer(3); // false
new Integer(100) == new Integer(100); // false
Integer.valueOf(5) == Integer.valueOf(5); //true
Integer.valueOf(200) == Integer.valueOf(200); //false
The 4th statement here outputs false because the 256 integers closest to zero [-128; 127] are cached by the JVM, so they return the same object for those. Beyond that range, though, they aren't cached, so a new object is created.
So we can say JVM treats all primitive types as objects internally, but we can’t use them in that way; instead, we have Wrapper classes for that.
This is why Java actually is a purely Object Oriented Language. Please let me know in comments what you think—is Java is a purely Object Oriented Language or not?
Published at DZone with permission of Naresh Joshi, DZone MVB. See the original article here.
Opinions expressed by DZone contributors are their own.
Comments