Object-Oriented Programming
Object-Oriented Programming (OOP) is a paradigm that models software as a collection of objects that interact with each other. Each object represents a real-world entity with state (attributes) and behavior (methods).
What You Will Learn
- What is a class and what is an object
- State and behavior
- Constructors and initialization
- Encapsulation and access modifiers
- The this keyword
- Static vs instance members
Classes and Objects
Key Definitions
- Class: A template (blueprint) that defines attributes and methods
- Object: An instance of a class, a concrete entity in memory
- Attributes: Variables that represent the object's state
- Methods: Functions that define the object's behavior
// Class definition
public class Student {
// Attributes (state)
String firstName;
String lastName;
int studentId;
int yearOfStudy;
double gradeAverage;
// Methods (behavior)
void introduce() {
System.out.println("Hi, I'm " + firstName + " " + lastName);
System.out.println("Student ID: " + studentId);
}
void studySubject(String subject) {
System.out.println(firstName + " is studying " + subject);
}
boolean isDelayed() {
return yearOfStudy > 3;
}
}
public class Main {
public static void main(String[] args) {
// Create object with new
Student john = new Student();
// Assign attributes
john.firstName = "John";
john.lastName = "Smith";
john.studentId = 123456;
john.yearOfStudy = 2;
john.gradeAverage = 3.5;
// Call methods
john.introduce();
john.studySubject("Programming");
// Create multiple objects from the same class
Student james = new Student();
james.firstName = "James";
james.lastName = "Green";
james.studentId = 789012;
// Each object has its own state
System.out.println(john.firstName); // John
System.out.println(james.firstName); // James
}
}
Constructors
A constructor is a special method called when creating
an object with new. It allows initializing the object.
public class Student {
String firstName;
String lastName;
int studentId;
int yearOfStudy;
// Default constructor (no parameters)
public Student() {
this.yearOfStudy = 1; // default value
}
// Constructor with parameters
public Student(String firstName, String lastName, int studentId) {
this.firstName = firstName;
this.lastName = lastName;
this.studentId = studentId;
this.yearOfStudy = 1;
}
// Full constructor
public Student(String firstName, String lastName, int studentId, int yearOfStudy) {
this.firstName = firstName;
this.lastName = lastName;
this.studentId = studentId;
this.yearOfStudy = yearOfStudy;
}
}
// Using constructors
Student s1 = new Student(); // default constructor
Student s2 = new Student("John", "Smith", 123456); // 3-parameter constructor
Student s3 = new Student("James", "Green", 789012, 2); // full constructor
Constructor Rules
- Constructor name must be identical to the class name
- Has no return type (not even void)
- If you don't define any constructor, Java creates an empty default constructor
- If you define a parameterized constructor, the default constructor is no longer created automatically
Encapsulation
Encapsulation protects an object's data by hiding it from the outside and providing controlled methods to access it (getters/setters).
public class BankAccount {
// private: accessible only inside the class
private double balance;
private String accountHolder;
// public: accessible from anywhere
public BankAccount(String accountHolder, double initialBalance) {
this.accountHolder = accountHolder;
this.balance = initialBalance;
}
// Getter: allows READING the value
public double getBalance() {
return balance;
}
public String getAccountHolder() {
return accountHolder;
}
// Setter with validation
public void deposit(double amount) {
if (amount > 0) {
balance += amount;
System.out.println("Deposited $" + amount);
} else {
System.out.println("Invalid amount");
}
}
public boolean withdraw(double amount) {
if (amount > 0 && amount <= balance) {
balance -= amount;
System.out.println("Withdrew $" + amount);
return true;
}
System.out.println("Withdrawal not authorized");
return false;
}
}
Access Modifiers
| Modifier | Class | Package | Subclass | Everywhere |
|---|---|---|---|---|
| private | ✅ | ❌ | ❌ | ❌ |
| (default) | ✅ | ✅ | ❌ | ❌ |
| protected | ✅ | ✅ | ✅ | ❌ |
| public | ✅ | ✅ | ✅ | ✅ |
The this Keyword
public class Course {
private String name;
private int credits;
private Professor professor;
// this to distinguish parameters from attributes
public Course(String name, int credits) {
this.name = name; // this.name = attribute
this.credits = credits; // name = parameter
}
// this to call another constructor
public Course(String name) {
this(name, 3); // calls 2-parameter constructor
}
// this to pass current object
public void assignProfessor(Professor professor) {
this.professor = professor;
professor.addCourse(this); // passes this course to professor
}
// this for method chaining (fluent interface)
public Course withCredits(int credits) {
this.credits = credits;
return this;
}
public Course withProfessor(Professor professor) {
this.professor = professor;
return this;
}
}
// Using fluent interface
Course course = new Course("Programming")
.withCredits(4)
.withProfessor(profSmith);
Static vs Instance Members
public class Student {
// STATIC attribute: shared by all instances
private static int counter = 0;
private static final String UNIVERSITY = "University of Bologna";
// INSTANCE attributes: one per object
private int studentId;
private String name;
public Student(String name) {
this.name = name;
counter++; // increments for each new student
this.studentId = 2024000 + counter;
}
// STATIC method: belongs to class, not instance
public static int getStudentCount() {
return counter;
}
public static String getUniversity() {
return UNIVERSITY;
}
// INSTANCE method: operates on a specific object
public void introduce() {
System.out.println("I'm " + name + " from " + UNIVERSITY);
}
}
// Usage
System.out.println(Student.getUniversity()); // Static call
Student s1 = new Student("John");
Student s2 = new Student("James");
System.out.println(Student.getStudentCount()); // 2
s1.introduce(); // Instance call
When to use static
- Constants:
static finalfor shared immutable values - Counters: To track number of instances
- Utilities: Methods that don't depend on object state (e.g., Math.sqrt())
- Factory: Methods that create instances of the class
Complete Example: Course Management System
package edu.university.management;
public class Student {
// Static attributes
private static int counter = 0;
// Instance attributes
private final int studentId;
private String firstName;
private String lastName;
private int enrollmentYear;
private double gpa;
private int examsTaken;
// Constructor
public Student(String firstName, String lastName, int enrollmentYear) {
this.studentId = generateStudentId();
this.firstName = firstName;
this.lastName = lastName;
this.enrollmentYear = enrollmentYear;
this.gpa = 0;
this.examsTaken = 0;
}
// Private static method
private static int generateStudentId() {
counter++;
return 2024000 + counter;
}
// Getters
public int getStudentId() {
return studentId;
}
public String getFullName() {
return firstName + " " + lastName;
}
public double getGpa() {
return gpa;
}
// Method to record an exam
public void recordExam(int grade) {
if (grade >= 60 && grade <= 100) {
double total = gpa * examsTaken;
examsTaken++;
gpa = (total + grade) / examsTaken;
System.out.printf("%s passed the exam with %d%n", getFullName(), grade);
} else {
System.out.println("Invalid grade");
}
}
// Method to calculate year of study
public int getYearOfStudy() {
int currentYear = java.time.Year.now().getValue();
return currentYear - enrollmentYear + 1;
}
public boolean isDelayed() {
return getYearOfStudy() > 4;
}
// toString for string representation
@Override
public String toString() {
return String.format("Student[id=%d, name=%s, gpa=%.2f, year=%d]",
studentId, getFullName(), gpa, getYearOfStudy());
}
// Static utility method
public static int getTotalStudents() {
return counter;
}
}
package edu.university.management;
public class Exam {
private String courseName;
private int credits;
private Student student;
private int grade;
private boolean honors;
private String date;
public Exam(String courseName, int credits, Student student) {
this.courseName = courseName;
this.credits = credits;
this.student = student;
}
public void recordGrade(int grade, boolean honors) {
if (grade >= 60 && grade <= 100) {
this.grade = grade;
this.honors = (grade == 100 && honors);
this.date = java.time.LocalDate.now().toString();
student.recordExam(grade);
}
}
public String getFormattedGrade() {
if (grade == 0) return "Not taken";
return honors ? "100 with Honors" : String.valueOf(grade);
}
@Override
public String toString() {
return String.format("%s - %s: %s (%d credits)",
student.getFullName(), courseName, getFormattedGrade(), credits);
}
}
package edu.university.management;
public class ManagementTest {
public static void main(String[] args) {
// Create students
Student john = new Student("John", "Smith", 2023);
Student james = new Student("James", "Green", 2022);
// Record exams
Exam programmingExam = new Exam("Programming", 4, john);
programmingExam.recordGrade(85, false);
Exam calculusExam = new Exam("Calculus I", 5, john);
calculusExam.recordGrade(100, true);
Exam networksExam = new Exam("Networks", 3, james);
networksExam.recordGrade(78, false);
// Print status
System.out.println("\n=== Student Status ===");
System.out.println(john);
System.out.println(james);
System.out.println("\n=== Recorded Exams ===");
System.out.println(programmingExam);
System.out.println(calculusExam);
System.out.println(networksExam);
System.out.println("\n=== Statistics ===");
System.out.println("Total students: " + Student.getTotalStudents());
}
}
Conclusion
In this article we introduced the fundamental OOP concepts: classes, objects, constructors, encapsulation and static members.
In the next article we will explore inheritance, polymorphism and interfaces: the advanced pillars of object-oriented programming.
Key Points to Remember
- Class: Blueprint that defines attributes and methods
- Object: Concrete instance of a class
- Constructor: Special method to initialize objects
- Encapsulation: Hide data, expose controlled methods
- this: Reference to current object
- static: Belongs to class, not instances







