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.
Related deep dive: 05 - Astrazione e Contratti: Interfacce e Classi Astratte.
Related deep dive: 06 - API Core di Java: String, Date e Wrapper.
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.
Commenti
Caricamento commenti...
Sign in to comment