Fading Coder

One Final Commit for the Last Sprint

Home > Notes > Content

Understanding Java Object-Oriented Programming Concepts

Notes May 18 2

Classes and Objects

Class Fundamentals

A class serves as a blueprint defining common attributes and behaviors for a group of related objects. A object is a concrete instance created from that blueprint.

In Java, the development workflow typically follows this pattern:

  1. Define the class structure first
  2. Instantiate objects from that class

Class Declaration Syntax

public class Product {
    // instance variables (attributes)
    private String productId;
    private String productName;
    private double price;
    
    // instance methods (behaviors)
    public void displayInfo() {
        System.out.println("Product: " + productName + ", Price: " + price);
    }
}

Object Creation

// Basic syntax
new ClassName();

// Common pattern: assign to variable for easier manipulation
Product prod = new Product();

Each class acts as a custom data type (reference type). When an object is instantiated, it gains access to all defined properties and methods.

Accessing Members

object.propertyName;    // accessing instance variable (no parentheses)
object.methodName();     // invoking instance method (with parentheses)

prod.productId = "P001";
prod.displayInfo();

Object Initialization

Assign values to properties using the dot operator:

object.propertyName = value;

prod.price = 99.99;

Overriding toString()

Override this method in entity classes to control what information displays when printing objects.

Encapsulation

Constructor Methods

Constructors initialize object properties during instantiation.

public class Employee {
    private int employeeId;
    private String employeeName;
    private String department;
    private double salary;
    
    // Default constructor (no parameters)
    public Employee() {
    }
    
    // Parameterized constructor (initializes all fields)
    public Employee(int employeeId, String employeeName, String department, double salary) {
        this.employeeId = employeeId;
        this.employeeName = employeeName;
        this.department = department;
        this.salary = salary;
    }
}

Key characteristics:

  • Constructors have no return type (not even void)
  • Constructor name must match the class name exactly
  • Multiple constructors with different parameter lists create overloaded constructors
  • Constructors execute automatically when objects are created
  • Pass arguments during object creation: new Employee(1001, "Alice", "IT", 5000.0);

The this Keyword

When local variables share names with instance variables, this distinguishes between them:

public void setEmployeeId(int employeeId) {
    this.employeeId = employeeId;  // this.variableName refers to instance variable
}

Important note: If no constructor is explicitly defined, the JVM automatically provides a default no-argument constructor. Once any constructor is defined manually, the JVM stops generating the default one.

Data Encapsulation Pattern

Encapsulation protects object state by controlling external access to internal data.

Step 1: Make instance variables private

private String bookTitle;
private String author;
private int publishYear;

Step 2: Provide public getter and setter methods

public class Book {
    private String bookTitle;
    
    // Setter method (mutator)
    public void setBookTitle(String bookTitle) {
        this.bookTitle = bookTitle;
    }
    
    // Getter method (accessor)
    public String getBookTitle() {
        return this.bookTitle;
    }
}

Best practice: Always encapsulate entity class properties.

Access Modifiers

Control visibility of class members:

Modifier Accessibility
public Accessible from any class
protected Accessible within same package and subclasses
default (no modifier) Accessible within same package only
private Accessible within declaring class only

Practical Example: Library Management System

Member.java (Entity Class)

package library;

public class Member {
    private String memberId;
    private String registrationDate;
    private int borrowedBooks;
    
    public String getMemberId() {
        return memberId;
    }
    
    public void setMemberId(String memberId) {
        this.memberId = memberId;
    }
    
    public String getRegistrationDate() {
        return registrationDate;
    }
    
    public void setRegistrationDate(String registrationDate) {
        this.registrationDate = registrationDate;
    }
    
    public int getBorrowedBooks() {
        return borrowedBooks;
    }
    
    public void setBorrowedBooks(int borrowedBooks) {
        this.borrowedBooks = borrowedBooks;
    }
    
    @Override
    public String toString() {
        return "Member{id='" + memberId + "', registration='" + registrationDate + "', books=" + borrowedBooks + "}";
    }
}

LibrarySystem.java (Main Application)

package library;

import java.util.Scanner;

public class LibrarySystem {
    private static Scanner input = new Scanner(System.in);
    private static Member[] members = new Member[200];
    private static int memberCount = 0;
    
    public static void displayMenu() {
        System.out.println("=== Library Management System ===");
        System.out.println("--------------------------------");
        System.out.println("1. Register New Member");
        System.out.println("2. Update Member Information");
        System.out.println("3. Search Member");
        System.out.println("4. List All Members");
        System.out.println("5. Exit System");
        System.out.println("--------------------------------");
    }
    
    public static void registerMember() {
        System.out.println("Enter member ID:");
        String id = input.next();
        System.out.println("Enter registration date (MM/DD):");
        String date = input.next();
        System.out.println("Enter number of borrowed books:");
        int count = input.nextInt();
        
        Member newMember = new Member();
        newMember.setMemberId(id);
        newMember.setRegistrationDate(date);
        newMember.setBorrowedBooks(count);
        
        members[memberCount] = newMember;
        memberCount++;
        System.out.println("Member registration successful!");
    }
    
    public static void modifyMember() {
        System.out.println("Enter member ID to modify:");
        String id = input.next();
        
        System.out.println("--------------------------------");
        System.out.println("1. Update Registration Date");
        System.out.println("2. Update Borrowed Books Count");
        System.out.println("--------------------------------");
        String selection = input.next();
        
        switch (selection) {
            case "1":
                updateRegistrationDate(id);
                break;
            case "2":
                updateBorrowedCount(id);
                break;
            default:
                System.out.println("Invalid selection!");
        }
    }
    
    private static void updateRegistrationDate(String id) {
        for (int i = 0; i < memberCount; i++) {
            if (members[i].getMemberId().equals(id)) {
                System.out.println("Enter new registration date:");
                String newDate = input.next();
                members[i].setRegistrationDate(newDate);
                System.out.println("Registration date updated!");
                return;
            }
        }
        System.out.println("Member not found!");
    }
    
    private static void updateBorrowedCount(String id) {
        for (int i = 0; i < memberCount; i++) {
            if (members[i].getMemberId().equals(id)) {
                System.out.println("Enter new borrowed books count:");
                int newCount = input.nextInt();
                members[i].setBorrowedBooks(newCount);
                System.out.println("Borrowed count updated!");
                return;
            }
        }
        System.out.println("Member not found!");
    }
    
    public static void searchMember() {
        System.out.println("Enter member ID to search:");
        String id = input.next();
        
        boolean found = false;
        for (int i = 0; i < memberCount; i++) {
            if (members[i].getMemberId().equals(id)) {
                System.out.println("ID\t\tDate\t\tBooks");
                System.out.println(members[i].getMemberId() + "\t\t" + 
                    members[i].getRegistrationDate() + "\t\t" + 
                    members[i].getBorrowedBooks());
                found = true;
                break;
            }
        }
        
        if (!found) {
            System.out.println("No member found with specified ID!");
        }
    }
    
    public static void listAllMembers() {
        if (memberCount == 0) {
            System.out.println("No members registered yet!");
        } else {
            System.out.println("ID\t\tDate\t\tBooks");
            for (int i = 0; i < memberCount; i++) {
                System.out.println(members[i].getMemberId() + "\t\t" + 
                    members[i].getRegistrationDate() + "\t\t" + 
                    members[i].getBorrowedBooks());
            }
        }
    }
    
    public static void main(String[] args) {
        while (true) {
            displayMenu();
            System.out.println("Enter your choice (1-5):");
            String choice = input.next();
            
            switch (choice) {
                case "1":
                    registerMember();
                    break;
                case "2":
                    modifyMember();
                    break;
                case "3":
                    searchMember();
                    break;
                case "4":
                    listAllMembers();
                    break;
                case "5":
                    System.out.println("Exiting system. Goodbye!");
                    System.exit(0);
                    break;
                default:
                    System.out.println("Invalid option. Please try again.");
            }
        }
    }
}

Inheritance

The static Keyword

Static Variables:

Shared across all instances. Only one copy exists in memory.

public class Configuration {
    public static String APP_NAME = "InventorySystem";
    public static int MAX_ITEMS = 1000;
}

// Access via class name (preferred)
String appName = Configuration.APP_NAME;

Static Methods:

Typically used in utility classes. Can be invoked using class name without creating objects.

public static int add(int a, int b) {
    return a + b;
}

// Call using class name
int result = Calculator.add(5, 3);

Restriction: Static methods can only access static members directly.

Static Blocks:

static {
    // Initialization code runs once when class loads
    System.out.println("Configuration initialized");
}

Compare with instance blocks (run every time an object is created):

{
    // Runs for each object instantiation
}

Inheritance Basics

Inheritance establishes a parent-child relationship between classes, enabling code reuse.

public class Vehicle {
    protected String brand;
    protected int speed;
    
    public void displayInfo() {
        System.out.println("Brand: " + brand + ", Speed: " + speed);
    }
}

public class Car extends Vehicle {
    private int doorCount;
    
    public void showDetails() {
        System.out.println("Brand: " + brand + ", Doors: " + doorCount);
    }
}

Important rules:

  • Java supports single inheritance (one direct parent per class)
  • Child classes inherit all non-private members from parent
  • Constructors are not inherited but can be invoked using super()
  • Child class automatically calls parent no-argument constructor

The super Keyword

Represents the parent class instance.

Calling parent constructor:

public class Person {
    private String name;
    
    public Person(String name) {
        this.name = name;
    }
}

public class Student extends Person {
    private int grade;
    
    public Student(String name, int grade) {
        super(name);  // invoke parent constructor first
        this.grade = grade;
    }
}

Accessing parent members:

super.brand = "Toyota";  // access inherited field

Method Overriding

Subclasses can provide specific implementations for inherited methods.

public class Animal {
    public void makeSound() {
        System.out.println("Some sound");
    }
}

public class Cat extends Animal {
    @Override
    public void makeSound() {
        System.out.println("Meow");
    }
}

Requirements:

  • Method signature must match exactly
  • Requires inheritance or implementation relationship
  • Use @Override annotation for compiler verification

Contrast with Overloading: Method overloading occurs within the same class with different parameter lists. No inheritance required.

The final Keyword

Prevents modifications:

Usage Effect
final class Cannot be subclassed
final method Cannot be overridden
final variable Cannot be reassigned
static final Compile-time constant
public static final double PI = 3.14159265359;
public static final int MAX_CONNECTIONS = 50;

Convention: Constants use UPPERCASE names.

Package Organization

Packages organize related classes into namespaces.

package com.example.inventory;  // declares package
import com.example.utils.StringHelper;  // import specific class
import com.example.utils.*;  // import all classes from package

Rules:

  • Package names are lowercase by convention
  • Without imports, classes in the same package can be accessed directly
  • Cross-package access requires imports

The Object Class

Every class implicitly extends Object. Key methods:

equals() method:

By default, compares object references (memory addresses). Many classes override this behavior.

String s1 = "Hello";
String s2 = "Hello";
s1.equals(s2);  // true because String overrides equals()

toString() method:

Returns string representation. Commonly overridden in entity classes.

hashCode() method:

Returns numeric identifier used in hash-based collections.

getClass() method:

Returns the runtime class of the object.

Custom classes should override equals() and hashCode() when needed for proper comparison in collections.

Abstract Classes and Interfaces

Abstract Classes

Define incomplete templates that must be completed by subclasses.

public abstract class Shape {
    protected String color;
    
    // Abstract method (no body)
    public abstract double calculateArea();
    
    // Concrete method
    public void displayColor() {
        System.out.println("Color: " + color);
    }
}

public class Circle extends Shape {
    private double radius;
    
    public Circle(double radius) {
        this.radius = radius;
        this.color = "Red";
    }
    
    @Override
    public double calculateArea() {
        return Math.PI * radius * radius;
    }
}

Rules:

  • Abstract classes cannot be instantiated directly
  • Classes containing abstract methods must be declared abstract
  • Subclasses must implement all abstract methods (unless they are also abstract)
  • Abstract classes may contain both abstract and concrete methods
  • static and abstract cannot be combined
  • Abstract methods cannot have bodies

Interfaces

Interfaces define contracts with only abstract methods (prior to Java 8).

public interface Drawable {
    void draw();
    void resize(int width, int height);
}

public class Rectangle implements Drawable {
    @Override
    public void draw() {
        System.out.println("Drawing rectangle");
    }
    
    @Override
    public void resize(int width, int height) {
        System.out.println("Resizing to " + width + "x" + height);
    }
}

Key points:

  • Use implements keyword for class-interface relationship
  • Interfaces cannot be instantiated
  • Classes must implement all interface methods
  • Interface methods are implicitly public (modifier can be omitted)
  • A class can implement multiple interfaces
  • Classes can extend a parent class and implement interfaces simultaneously:
public class Triangle extends Shape implements Drawable, Fillable {
    // must implement methods from both interfaces
}

Interface inheritance: Interfaces can extend other interfaces (supporting multiple inheritance):

public interface Clickable extends Drawable {
    void onClick();
}

Purpose: Interfaces enable loose coupling and define standards that different implementations can follow.

Polymorphism

Polymorphism allows a single reference to refer to objects of different types.

Definition: One entity, multiple forms

Animal cat = new Cat();  // parent type reference, child object
Animal dog = new Dog();

Reference Type Compatibility

Requirements: Must have inheritance or implementation relationship.

Behavior in polymorphic scenarios:

Member Type Access Behavior
Fields Accessed from parent class
Non-static methods Accessed from child class (override)
Static methods Accessed from parent class
class Parent {
    int value = 10;
    void display() { System.out.println("Parent display"); }
    static void show() { System.out.println("Parent show"); }
}

class Child extends Parent {
    int value = 20;
    void display() { System.out.println("Child display"); }
    static void show() { System.out.println("Child show"); }
}

Parent obj = new Child();
obj.display();    // prints "Child display"
obj.show();       // prints "Parent show"
obj.value;        // returns 10 (parent field)

Type Checking with instanceof

Determine the actual object type at runtime:

public static void describeAnimal(Animal animal) {
    if (animal instanceof Cat) {
        Cat c = (Cat) animal;
        System.out.println("Cat with " + c.getWhiskerCount() + " whiskers");
    } else if (animal instanceof Dog) {
        Dog d = (Dog) animal;
        System.out.println("Dog with " + d.getTailWagSpeed() + " speed");
    }
}

Type Conversion

Upcasting (automatic): Child reference converted to parent type

Animal pet = new Cat();  // implicit upcast

Downcasting (manual): Parent reference converted back to child type

Cat cat = (Cat) pet;  // explicit downcast

Always check with instanceof before downcasting to avoid runtime errors.

Interface Polymorphism

// Without polymorphism
UserDAOImpl userDAO = new UserDAOImpl();

// With polymorphism (recommended)
UserDAO userDAO = new UserDAOImpl();

Benefits: Loose coupling enables easier maintenance and extensibility.

Layered Architecture

Organize projects using distinct layers:

Layer Package Purpose
Presentation controller Handle user interactions
Business service Implement business logic
Data Access dao Manage data persistence

Inner Classes

Anonymous Inner Classes

Create one-time implementations without explicit class declaration.

Common uses:

  • Implement interfaces on the fly
  • Extend abstract classes quickly
  • Create single-use objects
// Interface definition
interface ClickHandler {
    void onClick();
}

// Using anonymous inner class
ClickHandler handler = new ClickHandler() {
    @Override
    public void onClick() {
        System.out.println("Button clicked!");
    }
};
handler.onClick();

// Common scenario: passing as method parameter
button.setOnClickListener(new ClickHandler() {
    @Override
    public void onClick() {
        // handle click event
    }
});

Characteristics:

  • No class name (anonymous)
  • Defined and instantiated in single expression
  • Must extend a class or implement an interface
  • Can access enclosing class members and final local variables

Related Articles

Deploying a Maven Web Application to Tomcat 9 Using the Tomcat Manager

Tomcat 9 does not provide a dedicated Maven plugin. The Tomcat Manager interface, however, is backward-compatible, so the Tomcat 7 Maven Plugin can be used to deploy to Tomcat 9. This guide shows two...

Skipping Errors in MySQL Asynchronous Replication

When a replica halts because the SQL thread encounters an error, you can resume replication by skipping the problematic event(s). Two common approaches are available. Methods to Skip Errors 1) Skip a...

Spring Boot MyBatis with Two MySQL DataSources Using Druid

Required dependencies application.properties: define two data sources and poooling Java configuration for both data sources MyBatis mappers for each data source Controller endpoints to verify both co...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.