Java: Object-Oriented Programming
Object-Oriented Programming in Java
Classes, Objects, Encapsulation & Beyond
Introduction to OOP
Object-Oriented Programming (OOP) is a programming paradigm that organises code
around objects rather than functions and logic. Objects are entities that combine data
(state) and behaviour (methods) into a single unit.
The Four Pillars of OOP
Pillar Description
Encapsulation Bundling data and methods together, hiding internal details
from outside access
Abstraction Showing only essential features while hiding implementation
complexity
Inheritance Creating new classes based on existing classes, inheriting
their properties
Polymorphism Objects of different classes responding to the same method
call in different ways
This handout focuses on Encapsulation — the foundation you need before exploring
inheritance and polymorphism.
Procedural vs Object-Oriented
// PROCEDURAL APPROACH
// Data and functions are separate
String studentName = "Fawaz";
int studentAge = 19;
double studentGPA = 3.8;
public static void printStudent(String name, int age, double gpa) {
[Link](name + ", Age: " + age + ", GPA: " + gpa);
}
// OBJECT-ORIENTED APPROACH
// Data and behaviour bundled together
Student fawaz = new Student("Fawaz", 19, 3.8);
[Link](); // Object knows how to print itself
1. Classes and Objects
A class is a blueprint or template that defines the structure and behaviour of objects. An
object is a specific instance of a class — a concrete entity created from that blueprint.
Analogy: Blueprint vs House
• Class = Blueprint: Defines what a house has (rooms, doors, windows) and can do
• Object = Actual House: A real house built from the blueprint, with specific colours,
sizes
• You can build many houses (objects) from one blueprint (class), each with different
characteristics
Page 1 of 18
Java: Object-Oriented Programming
Defining a Class
public class Student {
// FIELDS (instance variables) - the DATA
String name;
int age;
double gpa;
// METHODS - the BEHAVIOUR
void study() {
[Link](name + " is studying.");
}
void printInfo() {
[Link]("Name: " + name);
[Link]("Age: " + age);
[Link]("GPA: " + gpa);
}
}
Creating Objects (Instantiation)
public class Main {
public static void main(String[] args) {
// Create objects using the 'new' keyword
Student student1 = new Student();
Student student2 = new Student();
// Set field values
[Link] = "Fawaz";
[Link] = 19;
[Link] = 3.8;
[Link] = "Ali";
[Link] = 20;
[Link] = 3.5;
// Call methods on objects
[Link](); // "Fawaz is studying."
[Link](); // Prints Ali's info
// Each object has its own copy of the fields
[Link]([Link]); // "Fawaz"
[Link]([Link]); // "Ali"
}
}
Class Anatomy
Component Also Called Purpose
Fields Instance variables, Store the state/data of each object
attributes, properties
Methods Functions, Define what objects can do
behaviours,
operations
Constructors Initialisers Initialise objects when created
Multiple Classes in a Program
// File: [Link]
Page 2 of 18
Java: Object-Oriented Programming
public class Rectangle {
double width;
double height;
double area() {
return width * height;
}
double perimeter() {
return 2 * (width + height);
}
}
// File: [Link]
public class Main {
public static void main(String[] args) {
Rectangle r1 = new Rectangle();
[Link] = 5.0;
[Link] = 3.0;
[Link]("Area: " + [Link]()); // 15.0
[Link]("Perimeter: " + [Link]()); // 16.0
}
}
2. Constructors
A constructor is a special method that is automatically called when an object is created. It
initialises the object's fields and sets up its initial state.
Constructor Rules
1. Constructor name must be exactly the same as the class name
2. Constructors have no return type (not even void)
3. Called automatically when using new
4. If you don't write one, Java provides a default no-argument constructor
Default Constructor
public class Student {
String name;
int age;
// If you write NO constructor, Java provides this implicitly:
// public Student() { }
}
// Usage:
Student s = new Student(); // Calls default constructor
// Fields get default values: name = null, age = 0
Parameterised Constructor
public class Student {
String name;
int age;
double gpa;
Page 3 of 18
Java: Object-Oriented Programming
// Constructor with parameters
public Student(String studentName, int studentAge, double
studentGPA) {
name = studentName;
age = studentAge;
gpa = studentGPA;
}
}
// Usage:
Student s = new Student("Fawaz", 19, 3.8);
[Link]([Link]); // "Fawaz"
[Link]([Link]); // 19
// This NO LONGER works (no default constructor):
// Student s2 = new Student(); // COMPILE ERROR!
Constructor Overloading
A class can have multiple constructors with different parameter lists.
public class Student {
String name;
int age;
double gpa;
// Constructor 1: No parameters (default-like)
public Student() {
name = "Unknown";
age = 0;
gpa = 0.0;
}
// Constructor 2: Name only
public Student(String name) {
[Link] = name;
age = 18; // Default age
gpa = 0.0;
}
// Constructor 3: All fields
public Student(String name, int age, double gpa) {
[Link] = name;
[Link] = age;
[Link] = gpa;
}
}
// All three ways to create a Student:
Student s1 = new Student(); // Uses Constructor 1
Student s2 = new Student("Fawaz"); // Uses Constructor 2
Student s3 = new Student("Ali", 20, 3.5); // Uses Constructor 3
Constructor Chaining with this()
One constructor can call another constructor in the same class using this(). This reduces
code duplication.
public class Student {
String name;
int age;
Page 4 of 18
Java: Object-Oriented Programming
double gpa;
String university;
// Primary constructor (most parameters)
public Student(String name, int age, double gpa, String university)
{
[Link] = name;
[Link] = age;
[Link] = gpa;
[Link] = university;
}
// Chain to primary, with default university
public Student(String name, int age, double gpa) {
this(name, age, gpa, "Princeton"); // Calls 4-param constructor
}
// Chain further, with default GPA
public Student(String name, int age) {
this(name, age, 0.0); // Calls 3-param constructor
}
// Default constructor
public Student() {
this("Unknown", 18); // Calls 2-param constructor
}
}
// this() must be the FIRST statement in the constructor
3. The 'this' Keyword
The this keyword refers to the current object — the instance on which a method or
constructor is being called.
Uses of 'this'
1. Disambiguate Field vs Parameter
public class Student {
String name; // Field
int age; // Field
// Without 'this' - PROBLEM: parameter shadows field
public Student(String name, int age) {
name = name; // Assigns parameter to itself! Field unchanged.
age = age; // Same problem.
}
// With 'this' - CORRECT
public Student(String name, int age) {
[Link] = name; // [Link] = field, name = parameter
[Link] = age; // Assigns parameter value to field
}
}
2. Call Another Constructor
public class Rectangle {
Page 5 of 18
Java: Object-Oriented Programming
double width;
double height;
public Rectangle(double width, double height) {
[Link] = width;
[Link] = height;
}
// Create a square (width = height)
public Rectangle(double side) {
this(side, side); // Calls the 2-param constructor
}
}
3. Return Current Object (Method Chaining)
public class Student {
String name;
int age;
public Student setName(String name) {
[Link] = name;
return this; // Return the current object
}
public Student setAge(int age) {
[Link] = age;
return this;
}
public void print() {
[Link](name + ", " + age);
}
}
// Method chaining (fluent interface)
Student s = new Student()
.setName("Fawaz")
.setAge(19);
[Link](); // "Fawaz, 19"
4. Pass Current Object to Another Method
public class Student {
String name;
public void enroll(Course course) {
[Link](this); // Pass this Student to the course
}
}
Page 6 of 18
Java: Object-Oriented Programming
4. Encapsulation & Access Modifiers
Encapsulation is the practice of hiding internal implementation details and controlling
access to an object's data. This is achieved through access modifiers and getter/setter
methods.
Access Modifiers
Modifier Class Package Subclass World
public ✓ ✓ ✓ ✓
protected ✓ ✓ ✓ ✗
(default) ✓ ✓ ✗ ✗
private ✓ ✗ ✗ ✗
Why Make Fields Private?
// WITHOUT encapsulation (BAD)
public class BankAccount {
public double balance; // Anyone can modify!
}
BankAccount acc = new BankAccount();
[Link] = -1000; // Oops! Negative balance allowed!
// WITH encapsulation (GOOD)
public class BankAccount {
private double balance; // Hidden from outside
public void deposit(double amount) {
if (amount > 0) {
balance += amount; // Validation!
}
}
public void withdraw(double amount) {
if (amount > 0 && amount <= balance) {
balance -= amount; // Can't go negative!
}
}
public double getBalance() {
return balance; // Read-only access
}
}
Getters and Setters
Getters retrieve field values. Setters modify field values with optional validation.
public class Student {
private String name;
private int age;
private double gpa;
// GETTER for name
public String getName() {
return name;
Page 7 of 18
Java: Object-Oriented Programming
// SETTER for name
public void setName(String name) {
if (name != null && ![Link]()) {
[Link] = name;
}
}
// GETTER for age
public int getAge() {
return age;
}
// SETTER for age with validation
public void setAge(int age) {
if (age >= 0 && age <= 150) {
[Link] = age;
}
}
// GETTER for gpa
public double getGpa() {
return gpa;
}
// SETTER for gpa with validation
public void setGpa(double gpa) {
if (gpa >= 0.0 && gpa <= 4.0) {
[Link] = gpa;
}
}
}
Naming Conventions
• Getter: getFieldName() or isFieldName() for boolean
• Setter: setFieldName(value)
// For boolean fields, use 'is' prefix
private boolean enrolled;
public boolean isEnrolled() { // Not getEnrolled()
return enrolled;
}
public void setEnrolled(boolean enrolled) {
[Link] = enrolled;
}
Complete Encapsulated Class
public class Student {
// Private fields
private String name;
private int age;
private double gpa;
private String studentId;
// Constructor
public Student(String name, int age, String studentId) {
setName(name); // Use setters for validation
Page 8 of 18
Java: Object-Oriented Programming
setAge(age);
[Link] = studentId; // ID can't change
[Link] = 0.0;
}
// Getters
public String getName() { return name; }
public int getAge() { return age; }
public double getGpa() { return gpa; }
public String getStudentId() { return studentId; }
// Setters with validation
public void setName(String name) {
if (name != null && [Link]() >= 2) {
[Link] = name;
}
}
public void setAge(int age) {
if (age >= 16 && age <= 100) {
[Link] = age;
}
}
public void setGpa(double gpa) {
if (gpa >= 0.0 && gpa <= 4.0) {
[Link] = gpa;
}
}
// No setter for studentId - it's immutable!
// Business methods
public void printInfo() {
[Link]("ID: " + studentId);
[Link]("Name: " + name);
[Link]("Age: " + age);
[Link]("GPA: " + gpa);
}
}
5. Static vs Instance Members
Instance members belong to individual objects — each object has its own copy. Static
members belong to the class itself — shared by all objects.
Comparison
Aspect Instance Static
Belongs to Each object The class
Memory One copy per object One copy total
Access [Link] [Link]
Can use 'this' Yes No
Static Fields
public class Student {
// Instance fields - each Student has their own
Page 9 of 18
Java: Object-Oriented Programming
private String name;
private int age;
// Static field - shared by ALL Student objects
private static int totalStudents = 0;
private static final String UNIVERSITY = "Princeton"; // Constant
public Student(String name, int age) {
[Link] = name;
[Link] = age;
totalStudents++; // Increment shared counter
}
// Static getter
public static int getTotalStudents() {
return totalStudents;
}
public static String getUniversity() {
return UNIVERSITY;
}
}
// Usage:
[Link]([Link]()); // 0
Student s1 = new Student("Fawaz", 19);
Student s2 = new Student("Ali", 20);
Student s3 = new Student("Sara", 18);
[Link]([Link]()); // 3
[Link]([Link]()); // "Princeton"
Static Methods
public class MathUtils {
// Static methods - no object needed
public static int add(int a, int b) {
return a + b;
}
public static int max(int a, int b) {
return (a > b) ? a : b;
}
public static double average(int[] numbers) {
int sum = 0;
for (int n : numbers) sum += n;
return (double) sum / [Link];
}
}
// Call without creating an object:
int result = [Link](5, 3); // 8
int bigger = [Link](10, 7); // 10
double avg = [Link](new int[]{1,2,3,4,5}); // 3.0
Static Method Restrictions
public class Example {
Page 10 of 18
Java: Object-Oriented Programming
private int instanceField = 10;
private static int staticField = 20;
// Instance method - can access everything
public void instanceMethod() {
[Link](instanceField); // OK
[Link](staticField); // OK
staticMethod(); // OK
}
// Static method - can only access static members
public static void staticMethod() {
// [Link](instanceField); // ERROR!
[Link](staticField); // OK
// [Link]([Link]); // ERROR! No 'this'
}
}
// Why? Static methods exist without any object,
// so there's no 'this' and no instance fields to access.
When to Use Static
• Constants: static final for values that never change (PI, MAX_SIZE)
• Counters/Trackers: Count total instances, assign unique IDs
• Utility methods: Operations that don't need object state ([Link], [Link])
• Factory methods: Alternative ways to create objects
Page 11 of 18
Java: Object-Oriented Programming
6. Object References
In Java, variables that hold objects don't actually contain the object itself — they contain a
reference (memory address) pointing to where the object is stored.
Reference vs Value
// PRIMITIVE: Variable holds the actual value
int a = 5;
int b = a; // b gets a COPY of the value
b = 10; // Changing b doesn't affect a
[Link](a); // 5 (unchanged)
// OBJECT: Variable holds a reference (address)
Student s1 = new Student("Fawaz", 19);
Student s2 = s1; // s2 gets a COPY of the reference
// Both point to the SAME object!
[Link](25); // Changes the shared object
[Link]([Link]()); // 25 (CHANGED!)
Visualising References
Student s1 = new Student("Fawaz", 19);
Student s2 = new Student("Ali", 20);
Student s3 = s1;
// Memory layout:
// s1 ──────┐
// ↓
// ┌─────────────┐
// │ name: Fawaz │ ← Object 1
// │ age: 19 │
// └─────────────┘
// ↑
// s3 ──────┘
// s2 ──────┐
// ↓
// ┌─────────────┐
// │ name: Ali │ ← Object 2
// │ age: 20 │
// └─────────────┘
// s1 and s3 point to the SAME object
// s2 points to a DIFFERENT object
Comparing Objects
Student s1 = new Student("Fawaz", 19);
Student s2 = new Student("Fawaz", 19);
Student s3 = s1;
// == compares REFERENCES (memory addresses)
[Link](s1 == s2); // false (different objects)
[Link](s1 == s3); // true (same object)
Page 12 of 18
Java: Object-Oriented Programming
// To compare CONTENT, use equals() method
// (You need to override equals() in your class - covered later)
null Reference
Student s = null; // s doesn't point to any object
// Trying to use a null reference causes NullPointerException
// [Link](); // ERROR! NullPointerException
// Always check for null before using
if (s != null) {
[Link]([Link]());
}
// Or use the conditional
String name = (s != null) ? [Link]() : "No student";
Passing Objects to Methods
public class Main {
public static void main(String[] args) {
Student s = new Student("Fawaz", 19);
[Link]([Link]()); // 19
birthday(s); // Pass reference to method
[Link]([Link]()); // 20 (CHANGED!)
}
// Method receives a COPY of the reference
// Both point to the same object!
public static void birthday(Student student) {
int newAge = [Link]() + 1;
[Link](newAge); // Modifies the original object
}
}
// Note: Reassigning the parameter doesn't affect the original
public static void tryToReplace(Student student) {
student = new Student("New Person", 99);
// Only changes the local copy of the reference
// Original variable still points to old object
}
7. Complete Example: BankAccount Class
public class BankAccount {
// Static field - shared across all accounts
private static int nextAccountNumber = 1000;
private static final double INTEREST_RATE = 0.05;
// Instance fields - unique to each account
private final int accountNumber; // Immutable
private String ownerName;
private double balance;
// Constructor
public BankAccount(String ownerName, double initialDeposit) {
[Link] = nextAccountNumber++;
Page 13 of 18
Java: Object-Oriented Programming
[Link] = ownerName;
[Link] = 0;
deposit(initialDeposit); // Use method for validation
}
// Overloaded constructor - default deposit
public BankAccount(String ownerName) {
this(ownerName, 0);
}
// Getters
public int getAccountNumber() { return accountNumber; }
public String getOwnerName() { return ownerName; }
public double getBalance() { return balance; }
// Setter with validation
public void setOwnerName(String ownerName) {
if (ownerName != null && [Link]() >= 2) {
[Link] = ownerName;
}
}
// Business methods
public void deposit(double amount) {
if (amount > 0) {
balance += amount;
[Link]("Deposited: $" + amount);
} else {
[Link]("Invalid deposit amount");
}
}
public boolean withdraw(double amount) {
if (amount > 0 && amount <= balance) {
balance -= amount;
[Link]("Withdrew: $" + amount);
return true;
} else {
[Link]("Invalid withdrawal");
return false;
}
}
public void applyInterest() {
double interest = balance * INTEREST_RATE;
balance += interest;
[Link]("Interest added: $" + interest);
}
public void transfer(BankAccount recipient, double amount) {
if ([Link](amount)) {
[Link](amount);
[Link]("Transfer complete");
}
}
// Static method
public static double getInterestRate() {
return INTEREST_RATE;
Page 14 of 18
Java: Object-Oriented Programming
public void printStatement() {
[Link]("====================");
[Link]("Account: " + accountNumber);
[Link]("Owner: " + ownerName);
[Link]("Balance: $%.2f%n", balance);
[Link]("====================");
}
}
Using the BankAccount Class
public class Main {
public static void main(String[] args) {
// Create accounts
BankAccount acc1 = new BankAccount("Fawaz", 1000);
BankAccount acc2 = new BankAccount("Ali", 500);
// Perform transactions
[Link](250); // Deposited: $250
[Link](100); // Withdrew: $100
[Link](); // Interest added
// Transfer between accounts
[Link](acc2, 200);
// Print statements
[Link]();
[Link]();
// Access static method
[Link]("Rate: " + [Link]());
}
}
Page 15 of 18
Java: Object-Oriented Programming
Practice Problems
Problem 1: Rectangle Class
Create a Rectangle class with proper encapsulation.
public class Rectangle {
private double width;
private double height;
private static int count = 0;
public Rectangle(double width, double height) {
setWidth(width);
setHeight(height);
count++;
}
public Rectangle(double side) {
this(side, side); // Square
}
// Getters
public double getWidth() { return width; }
public double getHeight() { return height; }
// Setters with validation
public void setWidth(double width) {
if (width > 0) [Link] = width;
}
public void setHeight(double height) {
if (height > 0) [Link] = height;
}
// Methods
public double area() { return width * height; }
public double perimeter() { return 2 * (width + height); }
public boolean isSquare() { return width == height; }
public static int getCount() { return count; }
}
Problem 2: Book Class
Create a Book class for a library system.
public class Book {
private String title;
private String author;
private String isbn;
private boolean available;
private static int totalBooks = 0;
public Book(String title, String author, String isbn) {
[Link] = title;
[Link] = author;
[Link] = isbn;
[Link] = true;
Page 16 of 18
Java: Object-Oriented Programming
totalBooks++;
}
// Getters
public String getTitle() { return title; }
public String getAuthor() { return author; }
public String getIsbn() { return isbn; }
public boolean isAvailable() { return available; }
// Methods
public boolean checkout() {
if (available) {
available = false;
return true;
}
return false;
}
public void returnBook() {
available = true;
}
public void printInfo() {
[Link](title + " by " + author);
[Link]("ISBN: " + isbn);
[Link]("Status: " + (available ? "Available" :
"Checked Out"));
}
public static int getTotalBooks() { return totalBooks; }
}
Problem 3: Counter with ID
Create a class that assigns unique IDs to each instance.
public class Counter {
private static int nextId = 1; // Shared counter
private final int id; // Unique ID for this instance
private int value; // Instance counter value
public Counter() {
[Link] = nextId++;
[Link] = 0;
}
public int getId() { return id; }
public int getValue() { return value; }
public void increment() { value++; }
public void decrement() { if (value > 0) value--; }
public void reset() { value = 0; }
public static int getTotalCounters() { return nextId - 1; }
}
// Usage:
Counter c1 = new Counter(); // id = 1
Counter c2 = new Counter(); // id = 2
Page 17 of 18
Java: Object-Oriented Programming
Counter c3 = new Counter(); // id = 3
[Link]([Link]()); // 1
[Link]([Link]()); // 2
[Link]([Link]()); // 3
Quick Reference Card
Concept Syntax / Example
Class Definition public class Name { fields; methods; }
Create Object ClassName obj = new ClassName();
Constructor public ClassName(params) { [Link] = param; }
this keyword [Link] | this(args) | return this;
Private Field private int value;
Getter public int getValue() { return value; }
Setter public void setValue(int v) { [Link] = v; }
Static Field private static int count = 0;
Static Method public static int getCount() { return count; }
Constant private static final double PI = 3.14159;
Key Principles
1. Make fields private — hide internal data from outside access
2. Provide getters/setters — control how data is accessed and modified
3. Validate in setters — ensure object state remains valid
4. Use static for shared data — counters, constants, utility methods
5. Understand references — objects are accessed through references, not copied
Page 18 of 18