The Fundamentals of Object-Oriented Programming for Java Beginners
By: Anna Reed
Tags: Java, Programming, Coding, Object Oriented, Software Development

Object-Oriented Programming (OOP) is a method of coding that uses succinct, modular “objects” to organize data and functions. It is a concept that can be used to build complex and expansive programs and spans multiple coding languages. I first learned of it while learning to code in Ruby, for example.

Recently, I began looking into learning Java — a language with a long history known for its use in OOP. Other newcomers to Java might be surprised to find several references to four “fundamentals,” “principles,” or “pillars” (the language used varies, but they’re all referring to the same concepts) of Object-Oriented Programming inside Java’s documentation. While not often taught outside the context of Java, these four fundamentals are applicable across languages and can help give anyone a greater understanding of OOP.

1. Encapsulation

In Object-Oriented Programming, we use classes to define the types of objects used in our application. For instance, an online marketplace would likely have a “Product” class, with class-specific variables such as “name” and “price.” It might also have class-specific methods, for instance a function that adds an instance of a Product to the user’s cart. Here’s what that class might look like in Java:

public class Product{

private String name;

private double price; public void addToCart() {

//method is defined here

System.out.println("Added " + this.name + " to cart!");

}

}

Notice the keywords “public” and “private.” Public variables and methods can be accessed from anywhere in the program. Private variables and methods can only be accessed by the object they belong to. Encapsulation is the ability to designate variables and methods as private. So, for instance, if we were to create a new Product object called newProduct and then try to access its name…

public class Main {

public static void main(String[] args) {

Product newProduct = new Product();

System.out.println(newProduct.name);

}

}

This would return an error, because price is a private variable and therefore can’t be accessed by Main. On the other hand, if we were to do this…

public class Main {

public static void main(String[] args) {

Product newProduct = new Product();

newProduct.addToCart();

}

}

No error would appear, and running the program would result in newProduct’s addToCart() method being employed. This is because addToCart() is not a private method.

2. Inheritance

In our previous example, our theoretical retail application defined a Product class for the products being sold. But what if we wanted to sell different kinds of products? A clothing product would still be a Product with a name, price, and the ability to be added to a user’s cart, but it may also have other attributes —a size, for instance. Likewise, a food product likely has some sort of sell-by date. To further customize objects of our Product class, we can create subclasses that inherit its properties while inserting some of their own.

public class Product{

private String name;

private double price; public void addToCart() {

//method is defined here

System.out.println("Added " + this.name + " to cart!");

}

} public class Clothing extends Product {

private String size;

} public class Food extends Product {

private String sellBy;

}

In the above example, “extends” is Java syntax that defines Clothing and Food as subclasses of the Product class. This means that any Clothing or Food option will have access to the name and price attributes as well as the addToCart() method, in addition to the variables defined within the classes themselves. Inheritance is the ability of a class to inherit properties from a different class.

3. Abstraction

Let’s continue using the code above. Imagine the online store being created is a very specific type of marketplace, and it only sells clothing and food. In this case, we never want to see an object of the Product class being created — we only want objects of the Clothing and Food classes. To ensure that this is the case, we can make the Product class abstract.

abstract class Product{

private String name;

private double price; public void addToCart() {

//method is defined here

System.out.println("Added " + this.name + " to cart!");

}

} public class Clothing extends Product {

private String size;

} public class Food extends Product {

private String sellBy;

}

Notice that the keyword “public” in the first line of code has been replaced with “abstract” — this ensures that Product objects cannot be created. Instead, the Product class may only be inherited from by other classes. Attempting to create an object of the Product class will now result in an error.

public class Main {

public static void main(String[] args) {

Product newProduct = new Product();

//This code won't run!

}

}

Abstraction, like encapsulation, controls access to certain aspects of code. Both classes and methods can be made abstract.

4. Polymorphism

Up until now, the addToCart() method has been identical for both Clothing and Food objects, but this doesn’t have to be the case. Polymorphism means that the same method can have a different implementation for each subclass.

abstract class Product{

private String name;

private double price; public void addToCart() {

//method is defined here

System.out.println("Added " + this.name + " to cart!");

}

} public class Clothing extends Product {

private String size; public void addToCart() {

System.out.println("Added " + this.name + ", size " + this.size + ", to cart!");

} } public class Food extends Product {

private String sellBy;

}

Now, performing the addToCart() method on a Clothing object will result in both the name and size of the added object being printed. This differs from the Product and Food versions of the same method, but retains the same name for ease of use. To change the implementation of any subclass’s inherited method, all we have to do is re-define the method inside of that subclass.