Skip to main content

04 - OOP: Fundamental Concepts

Object-oriented programming in Java: classes, objects, constructors, encapsulation, access modifiers, this and static members.

What do you think about this article?

At a Glance

Object-oriented programming in Java: classes, objects, constructors, encapsulation, access modifiers, this and static members.

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
First Class: Student
// 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;
    }
}
Creating and Using Objects
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.

Constructors
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).

Access Modifiers
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

Using this
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

static keyword
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 final for 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

Student Class
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;
    }
}
Exam Class
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);
    }
}
Test Main
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

Frequently asked questions

What is Object-Oriented Programming (OOP) and how does it model software?

OOP models software as a collection of objects that interact with each other, where each object represents a real-world entity with state (attributes) and behavior (methods).

What is the purpose of a constructor in an object?

A constructor is a special method called when creating an object with it, allowing initializing the object.

How does encapsulation protect an object's data?

Encapsulation protects an object's data by hiding it from the outside and providing controlled methods to access it (getters/setters).

What are static members in OOP, and how do they differ from instance members?

Static members belong to a class rather than an instance of the class, meaning there is only one copy shared among all instances.

Sources and further reading

Try These Tools

Free developer tools related to this topic.

Commenti

Caricamento commenti...

Sign in to comment

Discuss this article in the community

Join the Telegram group to discuss with other developers, ask questions and share your experiences.

Did you like this article?

Explore other content on the blog or discover my projects