Java Programming
Lecture 09: Introduction to Object-Oriented Programming
Course: 4343203 - Java Programming
GTU Semester 4 | Unit 2
Learning Objectives:
- Understand OOP concepts and paradigms
- Learn class and object fundamentals
- Master encapsulation and data hiding
- Implement constructors and methods
- Apply OOP principles in practical programming
What is Object-Oriented Programming?
Object-Oriented Programming (OOP) is a programming paradigm that organizes software design around objects and classes rather than functions and logic.
Core OOP Principles:
- Encapsulation: Data hiding and bundling
- Inheritance: Code reuse and extension
- Polymorphism: Multiple forms of behavior
- Abstraction: Essential features only
Benefits of OOP:
- Code reusability and modularity
- Easier maintenance and debugging
- Real-world modeling capability
- Scalable application development
- Team collaboration efficiency
OOP vs Procedural Programming:
| Aspect | Procedural | Object-Oriented |
|---|---|---|
| Focus | Functions/Procedures | Objects/Classes |
| Data Security | Less secure | More secure (encapsulation) |
| Code Reuse | Limited | High (inheritance) |
| Problem Solving | Top-down approach | Bottom-up approach |
| Maintenance | Difficult for large apps | Easier maintenance |
Classes and Objects
Class Definition:
A class is a blueprint or template that defines the structure and behavior of objects. It specifies what attributes (data) and methods (functions) the objects will have.
Object Definition:
An object is an instance of a class. It is a concrete entity created from the class template that has actual values for the attributes.
Class vs Object Analogy:
Car class defines: brand, model, color, speed()
Objects = Actual Cars
car1: Honda Civic, Red, 60 mph
car2: Toyota Camry, Blue, 45 mph
car3: Ford Focus, White, 70 mph
Basic Class Syntax:
public class ClassName {
// Instance variables (attributes)
private dataType variableName;
// Constructor
public ClassName(parameters) {
// Initialize instance variables
}
// Methods (behavior)
public returnType methodName(parameters) {
// Method implementation
return value;
}
}Simple Student Class:
public class Student {
// Instance variables
private String name;
private int age;
private String studentId;
private double gpa;
// Constructor
public Student(String name, int age, String studentId) {
this.name = name;
this.age = age;
this.studentId = studentId;
this.gpa = 0.0;
}
// Method to display student information
public void displayInfo() {
System.out.println("Student: " + name);
System.out.println("Age: " + age);
System.out.println("ID: " + studentId);
System.out.println("GPA: " + gpa);
}
}Creating and Using Objects
Object Creation Process:
// Step 1: Declare object reference
Student student1;
// Step 2: Create object using 'new' keyword
student1 = new Student("Alice Johnson", 20, "STU001");
// Or combine both steps:
Student student2 = new Student("Bob Smith", 21, "STU002");
// Create multiple objects
Student student3 = new Student("Charlie Brown", 19, "STU003");
Student[] students = {student1, student2, student3};Accessing Object Members:
// Call methods on objects
student1.displayInfo();
student2.displayInfo();
// Note: Cannot directly access private variables
// student1.name = "New Name"; // ❌ Compilation error!
// Need public methods to access private data
System.out.println(student1.getName()); // ✅ CorrectComplete Example Program:
public class StudentDemo {
public static void main(String[] args) {
// Create student objects
Student alice = new Student("Alice Johnson", 20, "STU001");
Student bob = new Student("Bob Smith", 21, "STU002");
// Use the objects
System.out.println("=== Student Information ===");
alice.displayInfo();
System.out.println();
bob.displayInfo();
// Demonstrate object independence
alice.setGpa(3.8);
bob.setGpa(3.6);
System.out.println("\n=== After GPA Update ===");
alice.displayInfo();
System.out.println();
bob.displayInfo();
// Create array of objects
Student[] classroom = {alice, bob};
System.out.println("\n=== Classroom Roster ===");
for (Student student : classroom) {
student.displayInfo();
System.out.println("---");
}
}
}Key Points:
- Each object has its own copy of instance variables
- Objects are created in heap memory
- Reference variables store memory addresses, not actual objects
- Multiple references can point to the same object
Encapsulation and Data Hiding
What is Encapsulation?
Encapsulation is the bundling of data (variables) and methods that operate on that data within a single unit (class), while hiding the internal implementation details.
Access Modifiers:
- private: Accessible only within the same class
- default: Accessible within the same package
- protected: Accessible within package and subclasses
- public: Accessible from anywhere
Benefits of Encapsulation:
- Data security and integrity
- Code maintainability
- Controlled access to data
- Implementation hiding
Implementing Encapsulation:
public class BankAccount {
// Private instance variables (encapsulated)
private String accountNumber;
private String holderName;
private double balance;
private String accountType;
// Constructor
public BankAccount(String accountNumber, String holderName,
String accountType) {
this.accountNumber = accountNumber;
this.holderName = holderName;
this.accountType = accountType;
this.balance = 0.0;
}
// Public getter methods
public String getAccountNumber() {
return accountNumber;
}
public String getHolderName() {
return holderName;
}
public double getBalance() {
return balance;
}
public String getAccountType() {
return accountType;
}
// Public setter methods with validation
public void setHolderName(String holderName) {
if (holderName != null && !holderName.trim().isEmpty()) {
this.holderName = holderName;
} else {
System.out.println("Invalid name!");
}
}
}Methods and Object Behavior
Instance Methods:
public class BankAccount {
private double balance;
// Method to deposit money
public void deposit(double amount) {
if (amount > 0) {
balance += amount;
System.out.println("Deposited: $" + amount);
System.out.println("New Balance: $" + balance);
} else {
System.out.println("Invalid deposit amount!");
}
}
// Method to withdraw money
public boolean withdraw(double amount) {
if (amount > 0 && amount <= balance) {
balance -= amount;
System.out.println("Withdrawn: $" + amount);
System.out.println("Remaining Balance: $" + balance);
return true;
} else {
System.out.println("Invalid withdrawal amount or insufficient funds!");
return false;
}
}
// Method to transfer money
public boolean transferTo(BankAccount targetAccount, double amount) {
if (this.withdraw(amount)) {
targetAccount.deposit(amount);
System.out.println("Transfer successful!");
return true;
} else {
System.out.println("Transfer failed!");
return false;
}
}
}Method Types and Features:
1. Accessor Methods (Getters):
public double getBalance() {
return balance; // Returns current balance
}
public String getAccountInfo() {
return "Account: " + accountNumber +
", Balance: $" + balance;
}2. Mutator Methods (Setters):
public void setAccountType(String accountType) {
String[] validTypes = {"Savings", "Checking", "Business"};
for (String type : validTypes) {
if (type.equalsIgnoreCase(accountType)) {
this.accountType = accountType;
return;
}
}
System.out.println("Invalid account type!");
}3. Utility Methods:
public void displayAccountStatement() {
System.out.println("=== Account Statement ===");
System.out.println("Account Number: " + accountNumber);
System.out.println("Holder Name: " + holderName);
System.out.println("Account Type: " + accountType);
System.out.println("Current Balance: $" + balance);
System.out.println("========================");
}
public boolean isEligibleForLoan() {
return balance >= 10000.0; // Minimum balance for loan
}Constructors
Constructor Basics:
A constructor is a special method that is automatically called when an object is created. It initializes the object's state.
Constructor Rules:
- Same name as the class
- No return type (not even void)
- Called automatically with 'new' keyword
- Can be overloaded
- If no constructor is defined, Java provides default constructor
Types of Constructors:
- Default Constructor: No parameters
- Parameterized Constructor: Takes parameters
- Copy Constructor: Creates object from another object
Constructor Examples:
public class Car {
private String brand;
private String model;
private int year;
private String color;
private double price;
// Default constructor
public Car() {
this.brand = "Unknown";
this.model = "Unknown";
this.year = 2023;
this.color = "White";
this.price = 0.0;
}
// Parameterized constructor
public Car(String brand, String model, int year) {
this.brand = brand;
this.model = model;
this.year = year;
this.color = "White"; // Default color
this.price = 0.0; // Default price
}
// Full parameterized constructor
public Car(String brand, String model, int year,
String color, double price) {
this.brand = brand;
this.model = model;
this.year = year;
this.color = color;
this.price = price;
}
// Copy constructor
public Car(Car otherCar) {
this.brand = otherCar.brand;
this.model = otherCar.model;
this.year = otherCar.year;
this.color = otherCar.color;
this.price = otherCar.price;
}
}Constructor Overloading and 'this' Keyword
Constructor Overloading:
public class Employee {
private String name;
private String department;
private double salary;
private String employeeId;
// Constructor 1: Basic information
public Employee(String name) {
this.name = name;
this.department = "General";
this.salary = 30000.0;
this.employeeId = generateId();
}
// Constructor 2: Name and department
public Employee(String name, String department) {
this.name = name;
this.department = department;
this.salary = 35000.0;
this.employeeId = generateId();
}
// Constructor 3: Name, department, and salary
public Employee(String name, String department, double salary) {
this.name = name;
this.department = department;
this.salary = salary;
this.employeeId = generateId();
}
// Constructor 4: All parameters
public Employee(String name, String department,
double salary, String employeeId) {
this.name = name;
this.department = department;
this.salary = salary;
this.employeeId = employeeId;
}
private String generateId() {
return "EMP" + System.currentTimeMillis() % 10000;
}
}Using 'this' Keyword:
public class Employee {
private String name;
private double salary;
// 1. 'this' to refer to instance variables
public Employee(String name, double salary) {
this.name = name; // this.name refers to instance variable
this.salary = salary; // Parameter name same as instance variable
}
// 2. 'this' to call another constructor
public Employee(String name) {
this(name, 30000.0); // Calls parameterized constructor
System.out.println("Default salary assigned");
}
// 3. 'this' to call another method
public void displayInfo() {
this.printHeader(); // Optional 'this'
System.out.println("Name: " + this.name);
System.out.println("Salary: $" + this.salary);
}
private void printHeader() {
System.out.println("=== Employee Information ===");
}
// 4. 'this' to return current object
public Employee setSalary(double salary) {
this.salary = salary;
return this; // Returns current object for method chaining
}
public Employee setName(String name) {
this.name = name;
return this; // Method chaining
}
}
// Usage with method chaining:
Employee emp = new Employee("John")
.setName("John Doe")
.setSalary(45000.0);Previous Year Exam Questions
Q1. (GTU Summer 2022) What is Object-Oriented Programming? Explain the main principles of OOP with examples.
Solution:
Object-Oriented Programming (OOP):
OOP is a programming paradigm that organizes software design around objects and classes rather than functions and logic. It models real-world entities as objects that have attributes (data) and behaviors (methods).
Main Principles of OOP:
1. Encapsulation:
Bundling data and methods that operate on that data within a single unit, while hiding internal implementation details.
public class Student {
private String name; // Encapsulated data
private double grade; // Hidden from outside access
// Public methods to access private data
public void setGrade(double grade) {
if (grade >= 0 && grade <= 100) { // Validation
this.grade = grade;
} else {
System.out.println("Invalid grade!");
}
}
public double getGrade() {
return grade;
}
}2. Inheritance:
Mechanism where a new class (child/subclass) can inherit properties and methods from an existing class (parent/superclass).
// Base class
class Vehicle {
protected String brand;
protected int year;
public void start() {
System.out.println("Vehicle is starting...");
}
}
// Derived class
class Car extends Vehicle {
private int doors;
public Car(String brand, int year, int doors) {
this.brand = brand; // Inherited from Vehicle
this.year = year; // Inherited from Vehicle
this.doors = doors;
}
// Override inherited method
public void start() {
System.out.println("Car engine is starting...");
}
}3. Polymorphism:
Ability of objects of different types to be treated as objects of a common base type, with each type responding differently to the same method call.
// Method Overloading (Compile-time polymorphism)
class Calculator {
public int add(int a, int b) {
return a + b;
}
public double add(double a, double b) {
return a + b;
}
public int add(int a, int b, int c) {
return a + b + c;
}
}
// Method Overriding (Runtime polymorphism)
class Shape {
public void draw() {
System.out.println("Drawing a shape");
}
}
class Circle extends Shape {
public void draw() {
System.out.println("Drawing a circle");
}
}
class Rectangle extends Shape {
public void draw() {
System.out.println("Drawing a rectangle");
}
}4. Abstraction:
Hiding complex implementation details and showing only essential features of an object.
abstract class Animal {
protected String name;
public Animal(String name) {
this.name = name;
}
// Abstract method - must be implemented by subclasses
public abstract void makeSound();
// Concrete method - can be inherited as-is
public void sleep() {
System.out.println(name + " is sleeping");
}
}
class Dog extends Animal {
public Dog(String name) {
super(name);
}
public void makeSound() {
System.out.println(name + " says: Woof!");
}
}Q2. (GTU Winter 2021) Write a Java program to create a class 'Rectangle' with private data members length and width. Include constructors, getter and setter methods, and a method to calculate area.
Solution:
public class Rectangle {
// Private data members (Encapsulation)
private double length;
private double width;
// Default constructor
public Rectangle() {
this.length = 1.0;
this.width = 1.0;
}
// Parameterized constructor
public Rectangle(double length, double width) {
setLength(length); // Use setter for validation
setWidth(width); // Use setter for validation
}
// Copy constructor
public Rectangle(Rectangle other) {
this.length = other.length;
this.width = other.width;
}
// Getter methods
public double getLength() {
return length;
}
public double getWidth() {
return width;
}
// Setter methods with validation
public void setLength(double length) {
if (length > 0) {
this.length = length;
} else {
System.out.println("Length must be positive!");
this.length = 1.0; // Set default value
}
}
public void setWidth(double width) {
if (width > 0) {
this.width = width;
} else {
System.out.println("Width must be positive!");
this.width = 1.0; // Set default value
}
}
// Method to calculate area
public double calculateArea() {
return length * width;
}
// Method to calculate perimeter
public double calculatePerimeter() {
return 2 * (length + width);
}
// Method to check if rectangle is square
public boolean isSquare() {
return length == width;
}
// Method to display rectangle information
public void displayInfo() {
System.out.println("Rectangle Information:");
System.out.println("Length: " + length);
System.out.println("Width: " + width);
System.out.println("Area: " + calculateArea());
System.out.println("Perimeter: " + calculatePerimeter());
System.out.println("Is Square: " + isSquare());
System.out.println("------------------------");
}
// Override toString method for easy printing
@Override
public String toString() {
return String.format("Rectangle[length=%.2f, width=%.2f, area=%.2f]",
length, width, calculateArea());
}
// Override equals method to compare rectangles
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;
Rectangle rectangle = (Rectangle) obj;
return Double.compare(rectangle.length, length) == 0 &&
Double.compare(rectangle.width, width) == 0;
}
// Test program
public static void main(String[] args) {
System.out.println("=== Rectangle Class Demo ===\n");
// Test default constructor
Rectangle rect1 = new Rectangle();
System.out.println("Rectangle 1 (default constructor):");
rect1.displayInfo();
// Test parameterized constructor
Rectangle rect2 = new Rectangle(5.0, 3.0);
System.out.println("Rectangle 2 (5.0 x 3.0):");
rect2.displayInfo();
// Test copy constructor
Rectangle rect3 = new Rectangle(rect2);
System.out.println("Rectangle 3 (copy of Rectangle 2):");
rect3.displayInfo();
// Test setters with validation
Rectangle rect4 = new Rectangle();
System.out.println("Rectangle 4 - Testing setters:");
rect4.setLength(8.0);
rect4.setWidth(8.0); // This will make it a square
rect4.displayInfo();
// Test invalid values
System.out.println("Testing invalid values:");
rect4.setLength(-5.0); // Should show error message
rect4.setWidth(0); // Should show error message
rect4.displayInfo();
// Test toString method
System.out.println("Using toString():");
System.out.println("rect2: " + rect2);
System.out.println("rect3: " + rect3);
// Test equals method
System.out.println("\nTesting equality:");
System.out.println("rect2.equals(rect3): " + rect2.equals(rect3));
System.out.println("rect1.equals(rect2): " + rect1.equals(rect2));
// Calculate areas for comparison
System.out.println("\n=== Area Calculations ===");
Rectangle[] rectangles = {rect1, rect2, rect3, rect4};
double totalArea = 0;
for (int i = 0; i < rectangles.length; i++) {
double area = rectangles[i].calculateArea();
System.out.printf("Rectangle %d area: %.2f\n", i + 1, area);
totalArea += area;
}
System.out.printf("Total area of all rectangles: %.2f\n", totalArea);
}
}Q3. (GTU Summer 2020) Explain constructor overloading in Java with a practical example. Also explain the use of 'this' keyword.
Solution:
Constructor Overloading:
Constructor overloading is the ability to define multiple constructors in a class with different parameter lists. Java determines which constructor to call based on the number and types of arguments passed.
Benefits:
- Provides multiple ways to initialize objects
- Increases flexibility and usability
- Allows default values for some parameters
- Makes the class more user-friendly
Practical Example - Book Class:
public class Book {
private String title;
private String author;
private String isbn;
private double price;
private int pages;
private String category;
// Constructor 1: Default constructor
public Book() {
this.title = "Unknown";
this.author = "Unknown";
this.isbn = "000-0000000000";
this.price = 0.0;
this.pages = 0;
this.category = "General";
System.out.println("Default constructor called");
}
// Constructor 2: Title and author only
public Book(String title, String author) {
this.title = title;
this.author = author;
this.isbn = "000-0000000000"; // Default ISBN
this.price = 19.99; // Default price
this.pages = 200; // Default pages
this.category = "General"; // Default category
System.out.println("Constructor with title and author called");
}
// Constructor 3: Title, author, and price
public Book(String title, String author, double price) {
this(title, author); // Call constructor 2 using 'this'
this.price = price; // Override default price
System.out.println("Constructor with title, author, and price called");
}
// Constructor 4: Complete information
public Book(String title, String author, String isbn,
double price, int pages, String category) {
this.title = title;
this.author = author;
this.isbn = isbn;
this.price = price;
this.pages = pages;
this.category = category;
System.out.println("Full constructor called");
}
// Constructor 5: Copy constructor
public Book(Book other) {
this.title = other.title;
this.author = other.author;
this.isbn = other.isbn;
this.price = other.price;
this.pages = other.pages;
this.category = other.category;
System.out.println("Copy constructor called");
}
// 'this' keyword uses:
// 1. To distinguish between instance variables and parameters
public void setTitle(String title) {
this.title = title; // this.title refers to instance variable
}
// 2. To call other methods in the same class
public void displayInfo() {
this.printHeader(); // 'this' is optional here
System.out.println("Title: " + this.title);
System.out.println("Author: " + this.author);
System.out.println("ISBN: " + this.isbn);
System.out.println("Price: $" + this.price);
System.out.println("Pages: " + this.pages);
System.out.println("Category: " + this.category);
this.printFooter();
}
private void printHeader() {
System.out.println("=== Book Information ===");
}
private void printFooter() {
System.out.println("========================");
}
// 3. To return current object (for method chaining)
public Book setPrice(double price) {
this.price = price;
return this; // Return current object
}
public Book setPages(int pages) {
this.pages = pages;
return this; // Return current object
}
public Book setCategory(String category) {
this.category = category;
return this; // Return current object
}
// Getters
public String getTitle() { return title; }
public String getAuthor() { return author; }
public double getPrice() { return price; }
// Demo program
public static void main(String[] args) {
System.out.println("=== Constructor Overloading Demo ===\n");
// Using different constructors
Book book1 = new Book();
System.out.println("Book 1 created\n");
Book book2 = new Book("Java Programming", "John Doe");
System.out.println("Book 2 created\n");
Book book3 = new Book("Advanced Java", "Jane Smith", 45.99);
System.out.println("Book 3 created\n");
Book book4 = new Book("Complete Java", "Bob Johnson",
"978-1234567890", 59.99, 800, "Programming");
System.out.println("Book 4 created\n");
Book book5 = new Book(book4); // Copy constructor
System.out.println("Book 5 created (copy of Book 4)\n");
// Display information
book1.displayInfo();
book2.displayInfo();
book3.displayInfo();
// Demonstrate method chaining with 'this'
System.out.println("=== Method Chaining Demo ===");
Book book6 = new Book("Learning Java", "Alice Brown")
.setPrice(35.99)
.setPages(450)
.setCategory("Education");
book6.displayInfo();
System.out.println("\n=== 'this' Keyword Summary ===");
System.out.println("1. this.variableName - refers to instance variable");
System.out.println("2. this(parameters) - calls another constructor");
System.out.println("3. this.methodName() - calls instance method");
System.out.println("4. return this - returns current object for chaining");
}
}Hands-on Lab Exercises
Exercise 1: Student Management System
- Create a comprehensive Student class with:
- Private attributes: name, studentId, courses[], grades[]
- Multiple constructors for different initialization scenarios
- Methods: addCourse(), setGrade(), calculateGPA(), displayTranscript()
- Proper encapsulation with getters and setters
- Implement input validation and error handling
- Create a test program with multiple student objects
Exercise 2: Banking Application
- Design and implement a BankAccount class:
- Account number, holder name, balance, account type
- Methods: deposit(), withdraw(), transfer(), displayStatement()
- Transaction history tracking
- Interest calculation for savings accounts
- Include security features and transaction limits
- Create an interactive banking menu system
Exercise 3: Library Management System
- Create Book and Library classes:
- Book: title, author, ISBN, availability status
- Library: book collection, member management
- Operations: addBook(), issueBook(), returnBook(), searchBooks()
- Member class with borrowing history
- Implement advanced search and sorting features
Lecture Summary
Key Concepts Covered:
- OOP paradigm and its advantages
- Classes as blueprints and objects as instances
- Encapsulation and access modifiers
- Constructors and constructor overloading
- Methods and object behavior
- 'this' keyword and its multiple uses
- Getter and setter methods for data access
Learning Outcomes Achieved:
- ✅ Understand OOP principles and benefits
- ✅ Create and use classes and objects
- ✅ Implement proper encapsulation techniques
- ✅ Design multiple constructors effectively
- ✅ Use 'this' keyword appropriately
- ✅ Apply OOP concepts to real-world problems
- ✅ Debug object-oriented programming errors
Next Lecture: Inheritance and Method Overriding
Topics: Inheritance hierarchy, super keyword, method overriding, polymorphism basics
Thank You!
Questions & Discussion
Next: Lecture 10 - Inheritance and Method Overriding
Course: 4343203 Java Programming
Unit 2: Object-Oriented Programming
GTU Semester 4

