Why Java is not 100% Object-Oriented?
While languages like C++ and Java are known to be object-oriented languages, they’re not purely object-oriented languages like the Smalltalk language.
Java checks off most of the OOP properties which is why it’s also considered an object-oriented language however, it lacks certain qualities that must be satisfied for a language to be purely object-oriented.
Object-oriented programming is a programming paradigm that is based on objects that have both data and methods and aims to include modularity and reusability.
Programming paradigms is a method for solving problems using the tools and techniques available for a particular approach.
Before we dive in further to understand why Java is not 100% object oriented, let’s take a look we mean by a language being purely object-oriented.
Imagine going to a restaurant and giving your order to the chef via waiter, we specified our order according to our needs, the quantity, type, and any allergen warnings, now the waiter would probably go up to the chef and the chef will start making the food.
Here waiter is our object, what we(developers) are doing is communicating with our waiter (object) on a high level of abstraction.
Since we don’t know how the food is being made or if the waiter goes directly to the chef or takes more orders on his way, the entire process is hidden in the object itself. Thus,
Object-oriented programming is a methodology that organizes software designs around objects rather than functions and logic.
Let’s dive a bit deep into Object-Oriented Programming basics:
- Object: It’s a real-world entity with attributes, properties, and behavior. An object contains member functions and variables that are defined in the class. Every object is unique in terms of its state and attributes. It’s also referred to as an instance of the class and is dynamically allocated on heap memory.
- Class: It’s a template of an object (or a user-defined data type). Variables, constants, and various member functions are defined inside a class. It’s a logical entity that binds data and functions together in a single unit.
A class can exist without an object, but an object cannot exist without a class.
Through the process of abstraction, a programmer hides all but the relevant data about an object to reduce complexity and increase efficiency. Everything in OOP is grouped as self-sustainable objects.
There are four pillars on which OOP rests.
- Abstraction: It allows us to hide the implementation and relevant data about an object to reduce complexity and increase efficiency and shows only the essential information to the user.
- Encapsulation: It allows us to bind data and functions of a class in a single unit which is done to protect data and functions from external misuse providing security. A class is the best example of encapsulation.
- Inheritance: It allows us to inherit an existing class’s properties into a newly created (child) class. It provides code reusability.
- Polymorphism: It allows us to create methods with different signatures but the same name which helps us to create sensible and resilient code.
Criterion for Purely OOP Language
For a language to be fully object-oriented it needs to have all the above-mentioned concepts including the features that treat everything in the program as objects.
Thus for a language to be fully object-oriented following are the must-have qualities:
- Abstraction
- Encapsulation
- Inheritance
- Polymorphism
- All predefined types are objects
- All operations are performed by sending messages to objects
- All user-defined types are objects.
Despite the fact that it supports the four pillars of OOPs, Java is not 100% object oriented due to the following reasons:
-
Existence of Primitive data types: It's data that’s not an object and has no properties or any methods. Unlike Smalltalk which is a pure object-oriented programming language where primitive values such as Integers, Booleans, and characters are objects, in languages like Java and C++ these primitive data types are not treated as objects, rather they’re predefined types that are immutable (We’ll learn more about primitive and non-primitive data types further in this article).
-
Use of Static: Whenever a class is declared static, it can be used without an object similarily, we can't call a static function or a static variable using a dot(.) operator or object which defies OOP principles.
- Wrapper class: While the Wrapper class does provide a way to convert primitive data type into an object and vice versa, we can communicate with objects without calling their methods (using arithmetic operators). Wrapper class does not make Java purely object-oriented (we’ll learn more about it further in the article so keep reading!! )
Now the question arises in our minds if Object Oriented Programming is so beneficial, why then did Java founders decide to create primitive data types in the first place thereby, making Java not 100% object oriented?
The need for primitive data types
Primitive data types can be accessed faster and consume less memory, unlike objects. While we can use Wrapper classes to use these primitive data types as objects, wrapper classes are also stored in memory just like an object is thus it slows down the process since each time a wrapper type is used JVM has to look up the object in memory to get a value unlike primitive data types which for efficiency contains the value directly.
Primitive v/s Non-Primitive
Primitive data type | Non-primitive data type |
---|---|
They are pre-defined data types | They are user-defined data types |
When changes are made in the copied variable it’s not reflected in the original ones | When changes are made in the copied variable it is reflected in the original ones |
They cannot call methods for carrying out certain operations | They can be used to call methods to perform certain operations |
The size depends on the type of the data structure | In the case of non-primitive data structure, size is not fixed |
They are stored in stack | Reference variable is stored in stack and the original object is stored in heap |
A primitive type starts with a lowercase letter | Non-primitive types start with an uppercase letter |
A primitive type has always a value | Non-primitive types can be null |
Primitive data structure is a kind of data structure that stores the data of only one type | Non-primitive data structure is a type of data structure that can store the data of more than one type. |
Examples of the primitive data structure are integer, character, and float | Examples of the non-primitive data structure are Array, Linked list, and stack. |
Since primitive data types are immutable, the variable might be assigned a new value but there’ll be no change in existing value in ways where non-primitive data types as objects and functions can be altered. However, we can convert primitive data types to non-primitive data types (or object data types) and vice versa using a wrapper class.
Wrapper Class
It’s a class that helps us to use primitive data types as objects. In other words, we can convert primitive data types to non-primitive and vice versa using the wrapper class.
Wrapper classes come under java.util package.
Following are the 8 primitive types according to wrapper classes
Primitive data type | Wrapper Class |
---|---|
byte | Byte |
boolean | Boolean |
char | Character |
double | Double |
float | Float |
int | Integer |
long | Long |
short | Short |
Now we just talked about why we have primitive data types for better efficiency in Java programming. Why would we ever need to use our primitive data types as objects which is a move against a relatively more efficient approach isn't it? Here are some reasons why:
- Sometimes we need objects if we wish to modify the arguments passed into the method since primitive types are passed by value .
- For collection framework we use wrapper classes since data structures like ArrayList and Vector only store objects and not primitive types.
-
When we need an object for the sake of synchronization and multithreading. Synchronization in Java is the capability to control the access of multiple threads to any shared resource. Multithreading in Java is a process of executing multiple threads simultaneously.
-
java.util package only handles objects in which case we might need a primitive to object type conversion using a wrapper class
1. Primitive Data Type to Object Using Wrapper Class
A wrapper class can be used to convert primitive data type to object
We use the valueOf() method of the Wrapper class to convert the primitive types to the objects.
2. Object to Primary Data Type Using Wrapper Class
Wrapper class can be used to convert an object to Primary data type as well
Here objects are changed into corresponding primitive types using the intValue(), doubleValue(), and booleanValue() methods respectively
Even after using Wrapper classes, Java fails to be a pure OOP language. If say, we create an Integer instead of an int which is then followed by some operation, Java is going to use primitive int since it internally uses the operations where primitive types are converted automatically into objects (or vice versa) by the Java compiler This process is known as Autoboxing and Unboxing
Autoboxing and Unboxing
In Autoboxing, primitive types are automatically converted to their corresponding wrapper class objects with the help of the Java compiler Autoboxing has a great advantage while working with Java collections since we know that data structures like ArrayList and Vector only store objects and not primitive types It reduces the previously used valueOf() method each time an instance is created. The compiler as discussed before in the article works under the hood and performs the valueOf() operation to create an instance of it which is why multiple instances with the same value point to the same memory location
Output
We know Data structures like ArrayList can only store an object of the int type, we're getting the desired output even after using a primitive data type
Here 5 is a primitive data type, due to Autoboxing this primitive data type is converted into an Integer object for storing in the list
In Unboxing wrapper class objects are converted into their corresponding primitive types automatically by the online Java compiler
Here we're getting the desired output even though the get() method returns an object
Due to unboxing the object is converted to primitive type int and then assigned to variable a, automatically
Learn More
Interested so far? Learn more about Object creation in Java here
Conclusion
- Java is not 100% objects-oriented because of the existence of primitive data types, use of static keywords and wrapper classes.
- Object-oriented programming is a methodology that organizes software designs around objects rather than functions and logic.
- A Wrapper class provides a way to use primitive data types as objects and vice versa.
- Primitive data types can be accessed faster and consume less memory unlike objects.
- A primitive data type is pre-defined data or a data that's not an object and has no properties or methods.
- Wrapper class does not make Java 100% object oriented due to Autoboxing and Unboxing.
- We need wrapper classes since data structures like ArrayList and Vector only store objects and not primitive types.
- Java compiler automatically does the primitive data type to object using autoboxing (or vice versa using unboxing).