OOP Concepts in Java
OOP - Object-Oriented Programming
Object referring to real-world entities like car, shoes, fruits, even person and animal.
Object-oriented Programming(OOP) refers to a methodology where programmer try to design a program mimicking those entities, using classes and objects paradigm. OOP simplifies the software development and maintenance by providing some concepts:
Procedural-oriented Programs VS OOP
Procedural-oriented Programs | Object-oriented Programs |
---|---|
The procedural-oriented programs are based on functions. Functions are less reusable. It is very difficult to copy a function from one program and reuse in another program because the function is likely to reference the global variables and other functions. In other words, functions are not well-encapsulated as a self-contained reusable unit. | OOP grouping data structures and algorithms of a software entity inside a "box". The basic unit of OOP is a class, which encapsulates both properties and methods. Class also specifies the public interface for external objects to use this "box". Since classes are well-encapsulated, it is easier to reuse these classes, ex: by inheritance or by instantiation. |
The procedural languages (such as C, Fortran, Cobol and Pascal) are not suitable of high-level abstraction for solving real life problems. because forced programmers to think in low-level on how to use if-else, for-loop, array, method, pointer, which is very hard to abstract real problems. | OOP languages permit higher level of abstraction for solving real-life problems. OOP languages (such as Java, C++ and C#) let you think in the problem space, and use software objects to represent and abstract entities of the problem space to solve the problem. |
Class
Programmers create a data structure, and defines data types and also functions that can be applied to the data structure. In OOP, we called this data structure as class.
A class is a prototype that defines and describes the attributes and behaviors common to all objects of the same kind. It's a logical entity from which an object can be created.
As example, we can have class Student.
Object
An object is an instance of a class. If a class is a logical entity, instances considered "real" - since it's a realization of a class. All the instances of a class shared similar properties, and have same behavior, as described in the "prototype" (class definition).
As example, from class Student, we can have three instances "Bill", "Paul", and "Steve".
Keyword class
is used in Java to define a class. The syntax for class definition in Java is:
[accessModifier] class ClassName { // class body contains members (variables and methods) ...... }
Class naming convention: A class name shall be a noun or a noun phrase made up of several words. The first letter of every word in class name must be in upper case (PascalCase). Use a singular noun for class name. Choose a meaningful and self-descriptive class name. For examples: Student, Employee, Files, SecurityManager, SpringApplication, etc.
Inside a class, we will define member variables and member methods. The syntax for variable definition is:
[accessModifier] type variableName [= initialValue]; [accessModifier] type variableName1 [= initialValue1] [, type variableName2 [= initialValue2]] ... ;
Variable Naming Convention: A variable name shall be a noun or a noun phrase made up of several words. The naming following camelCase format: the first letter of the first word must be in lower case, while the first letter of every subsequent word is uppercase, e.g: height, firstName, birthDate, and mailingAddress1.
The syntax for method declaration in Java is as follows:
[accessModifier] returnType methodName ([parameterList]) { // method body or implementation ...... }
Method Naming Convention: A method name shall be a verb, or a verb phrase made up of several words. Similar like variable naming, the format for method naming also following camelCase format. For example: getLastName(), setBirthDate(), calculateDiscount(), and isPrimeNumber().
About accessModifier, please check Encapsulation in Java.
Now, let's create our Student class:
import java.time.LocalDate;
public class Student {
private String firstName;
private String lastName;
private LocalDate birthDate;
/**
* @return the firstName
*/
public String getFirstName() {
return firstName;
}
/**
* @param firstName the firstName to set
*/
public void setFirstName(String firstName) {
this.firstName = firstName;
}
/**
* @return the lastName
*/
public String getLastName() {
return lastName;
}
/**
* @param lastName the lastName to set
*/
public void setLastName(String lastName) {
this.lastName = lastName;
}
/**
* @return the birthDate
*/
public LocalDate getBirthDate() {
return birthDate;
}
/**
* @param birthDate the birthDate to set
*/
public void setBirthDate(LocalDate birthDate) {
this.birthDate = birthDate;
}
public void display() {
System.out.println("Student's name: " + this.firstName + " " + this.lastName);
System.out.println("Student's birthdate:" + this.birthDate.toString());
}
}
To create an instance of a class, you have to:
- Declare an instance identifier (instance name) of a particular class.
- Initialize the instance using the "new" operator.
For examples, we can create instances of Student as follows:
Student student1 = new Student();
Student student2;
student2 = new Student();
When an instance is declared but not initialized, it holds a special value called null.
To reference a member variable or method, you must use the dot operator (.) in the instance to reference the desired member variable or method.
student1.setFirstName("Bill");
student1.setLastName("Gates");
student1.setBirthDate(LocalDate.of(2005, Month.OCTOBER, 28));
student1.display();
student2.setFirstName("Steve");
student2.setLastName("Ballmer");
student2.setBirthDate(LocalDate.of(2006, Month.MARCH, 24));
student2.display();
class Student contains three private member variables: firstName (String), lastName (String), and birthDate (LocalDate); and six public member methods: getFirstName(), setFirstName(..), getLastName(), setLastName(..), getBirthDate(), and setBirthDate(..). Do you notice all the set* and get* methods?
The public Getters and Setters
For example, in our Student class. To allow other classes to read the value of a private variable firstName
, we need to create a get method called getFirstName()
. This is what we called getter or accessor method. Other classes now can invoke these public accessor methods to retrieve the firstName of Student class instances. A getter may not only return the value of the variable, but also can process the variable, or several other things. But, the getters shall not modify the variable.
We also create a set methodsetFirstName(...)
to allow other classes to modify the value of a private variable firstName
. A set not only updating the value of private variable with value in the parameter, but also can provide data validation, or transform the value in parameter into internal representation.
Constructors
A constructor is a block of code that resembles a special method that has the same name as the class name. It's not a method as it doesn't have a return type, and the purpose is for initialization of the newly created object. In the above Student class, we can create a constructor to accept firstName and lastName:
public Student(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
A constructor is different from an ordinary method in the following aspects:
- The name of the constructor method is the same as the class name. By class name's convention, it begins with an uppercase (instead of lowercase for ordinary methods).
- Constructor has no return type. It implicitly returns void. No return statement is allowed inside the constructor's body.
- Constructor can only be invoked via the "new" operator. It can only be used once to initialize the instance constructed. Once an instance is constructed, you cannot call the constructor anymore.
- Constructors are not inherited.
A constructor with no parameter is called as default constructor. Since parameter list is empty, we initialize the member variables to their default value. For example:
public Student() {
// can do something/initialization here
}
but we doesn't need default constructor for now, and we forced firstName and lastName initialization when the Student class is instantiated via it's constructor. We also can remove setFirstName(..) and setLastName(..), so when we putting together our Student class will looks like:
import java.time.LocalDate;
import java.time.Month;
public class Student {
private final String firstName;
private final String lastName;
private LocalDate birthDate;
/**
* @return the firstName
*/
public String getFirstName() {
return firstName;
}
/**
* @return the lastName
*/
public String getLastName() {
return lastName;
}
/**
* @return the birthDate
*/
public LocalDate getBirthDate() {
return birthDate;
}
/**
* @param birthDate the birthDate to set
*/
public void setBirthDate(LocalDate birthDate) {
this.birthDate = birthDate;
}
public Student(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
public void display() {
System.out.println("Student's name: " + this.firstName + " " + this.lastName);
System.out.println("Student's birthdate:" + this.birthDate.toString());
}
public static void main(String[] args) {
Student student1 = new Student("Bill", "Gates");
Student student2;
student2 = new Student("Steve", "Ballmer");
student1.setBirthDate(LocalDate.of(2005, Month.OCTOBER, 28));
student1.display();
student2.setBirthDate(LocalDate.of(2006, Month.MARCH, 24));
student2.display();
}
}
Do you notice the final statement in front of firstName and lastName variable declaration?
And when we run, we get the result:
Student's name: Bill Gates Student's birthdate:2005-10-28 Student's name: Steve Ballmer Student's birthdate:2006-03-24
Package
A package is a namespace that organizes a set of related classes and interfaces. The analogy is like this; if classes are similar like files in our computer, packages are similar to folders. We are using folders to organizes our files by placing related files into specific folders. Then it makes sense to group related classes and interfaces into packages.
Some well known packages in Java APIs are:
- java.io - provides for system input and output through data streams, serialization and the file system.
- java.lang - provides classes that are fundamental to the design of the Java programming language.
- java.net - provides the classes for implementing networking applications.
- java.nio - defines buffers, which are containers for data, and provides an overview of the other NIO packages.
- java.util - contains the collections framework, legacy collection classes, event model, date and time facilities, internationalization, and miscellaneous utility classes (a string tokenizer, a random-number generator, and a bit array).
- etc...
Creating package
package
statement should be the first line of the source file, and it applies to all types declared in the file.
package com.dariawan.codes;
public class Student {
// class members here
}
The class file also need to be in the package/folder in the same directory structure as the package. In above example, Student class must be under com/dariawan/codes
folder of source root folder.
The import Keyword
If a class wants to use another class in the same package, we doesn't need to declare package name of those class. But if the class is in different package, we need to call the class by it's full name (including package name) or do import.
import com.dariawan.codes.Student;
or, to do full package import
import com.dariawan.codes.*;
Best Practices for OOP
Here some best practices in OOP, to save your time without sacrificing security and ease of use:
- DRY (Don’t Repeat Yourself). You should never have two blocks of identical code in two different places. Instead, have one that can be used for different applications.
- Single Responsibility. Simply put, a class should always have only one functionality, one specialization. That way, it can be called and/or extended on its own when new uses arise for it, without causing coupling between different functionalities. Don't create a general class that do everything: access database, create logs, doing validations, etc.
- Open Closed Design. Make all methods and classes Closed for modification but Open for an extension. That way, tried and tested code can remain static but can be modified to perform new tasks as needed. Even if you expect your Java code to change in the future, you should encapsulate it by making all variables and methods access modifiers as restricted as possible, and slowly refactor it.
Putting it together, all the OOP concepts like Inheritance, Polymorphism, Encapsulation, and Abstraction should applicable here.