# Java Intermediate Guide - Object-Oriented Programming ## Table of Contents - [Introduction to OOP](#introduction-to-oop) - [Classes and Objects](#classes-and-objects) - [Constructors](#constructors) - [Encapsulation](#encapsulation) - [Inheritance](#inheritance) - [Polymorphism](#polymorphism) - [Abstract Classes](#abstract-classes) - [Interfaces](#interfaces) - [Packages and Imports](#packages-and-imports) - [Exception Handling Basics](#exception-handling-basics) - [Practice Exercises](#practice-exercises) --- ## Introduction to OOP Object-Oriented Programming (OOP) is a way of organizing code that treats data and functions as objects. Think of objects as real-world things: - **Car** - has properties (color, speed) and actions (drive, brake) - **BankAccount** - has properties (balance, owner) and actions (deposit, withdraw) - **Player** - has properties (name, score) and actions (jump, shoot) ### The Four Pillars of OOP | Pillar | Meaning | Example | |--------|---------|---------| | **Encapsulation** | Bundling data and methods together | A Car object contains its speed and drive() method | | **Inheritance** | Child classes inherit from parents | ElectricCar extends Car | | **Polymorphism** | Same action, different behavior | All shapes have area(), but each calculates differently | | **Abstraction** | Hiding complexity | You drive a car without knowing how the engine works | --- ## Classes and Objects A **class** is a blueprint - it defines what an object will look like. An **object** is an actual thing created from that blueprint. ### Creating a Class ```java public class Car { // Properties (also called fields or attributes) String color; String make; String model; int speed; // Methods (actions the car can do) public void drive() { System.out.println("The car is driving!"); } public void brake() { speed = 0; System.out.println("Car stopped!"); } public void displayInfo() { System.out.println(color + " " + make + " " + model); } } ``` ### Creating Objects ```java public class Main { public static void main(String[] args) { // Create an object from the Car class Car myCar = new Car(); // Set properties myCar.color = "Red"; myCar.make = "Toyota"; myCar.model = "Camry"; myCar.speed = 0; // Call methods myCar.displayInfo(); // Red Toyota Camry myCar.drive(); // The car is driving! myCar.brake(); // Car stopped! } } ``` ### Class vs Object | Class | Object | |-------|--------| | Blueprint | Actual thing | | Defines properties and methods | Has actual values | | One class, many objects | Created from a class | --- ## Constructors A **constructor** is a special method that runs when you create an object. It's used to set up the object with initial values. ### Default Constructor ```java public class Person { String name; int age; // Default constructor (no parameters) public Person() { name = "Unknown"; age = 0; } public static void main(String[] args) { Person p = new Person(); // Calls constructor System.out.println(p.name); // Unknown } } ``` ### Parameterized Constructor ```java public class Person { String name; int age; // Constructor with parameters public Person(String name, int age) { this.name = name; // "this" refers to the current object this.age = age; } public static void main(String[] args) { Person alice = new Person("Alice", 25); System.out.println(alice.name); // Alice System.out.println(alice.age); // 25 } } ``` ### Multiple Constructors (Overloading) ```java public class Person { String name; int age; // No-arg constructor public Person() { this.name = "Unknown"; this.age = 0; } // Constructor with name only public Person(String name) { this.name = name; this.age = 0; } // Constructor with all parameters public Person(String name, int age) { this.name = name; this.age = age; } } ``` --- ## Encapsulation **Encapsulation** means protecting data by controlling how it's accessed. You hide the internal details and only expose what's necessary. ### The Problem Without Encapsulation ```java // BAD - anyone can change these values directly! public class BankAccount { public double balance; // Public - anyone can change it! } // In main: BankAccount account = new BankAccount(); account.balance = -1000000; // Invalid! But possible without encapsulation ``` ### The Solution: Private Fields + Getters/Setters ```java public class BankAccount { // Private - can't access directly from outside private double balance; private String accountNumber; // Constructor public BankAccount(String accountNumber, double initialBalance) { this.accountNumber = accountNumber; // Validate initial balance if (initialBalance >= 0) { this.balance = initialBalance; } else { this.balance = 0; } } // Getter - read-only access public double getBalance() { return balance; } // Setter - controlled modification public void deposit(double amount) { if (amount > 0) { balance += amount; System.out.println("Deposited: " + amount); } else { System.out.println("Invalid deposit amount!"); } } public void withdraw(double amount) { if (amount > 0 && amount <= balance) { balance -= amount; System.out.println("Withdrawn: " + amount); } else { System.out.println("Invalid withdrawal!"); } } } ``` ### Using Encapsulation ```java public class Main { public static void main(String[] args) { BankAccount account = new BankAccount("12345", 1000); // Can't do this anymore: // account.balance = -1000000; // ERROR! // Must use methods: account.deposit(500); // Deposited: 500.0 account.withdraw(200); // Withdrawn: 200.0 System.out.println(account.getBalance()); // 1300.0 } } ``` --- ## Inheritance **Inheritance** allows a class to inherit properties and methods from another class. The child class gets everything from the parent! ### Basic Inheritance ```java // Parent class (Superclass) public class Animal { String name; int age; public void eat() { System.out.println(name + " is eating"); } public void sleep() { System.out.println(name + " is sleeping"); } } // Child class (Subclass) public class Dog extends Animal { String breed; // Dog inherits eat() and sleep() automatically! // Add Dog-specific method public void bark() { System.out.println("Woof woof!"); } } public class Main { public static void main(String[] args) { Dog myDog = new Dog(); myDog.name = "Buddy"; myDog.breed = "Golden Retriever"; myDog.eat(); // Buddy is eating (inherited) myDog.sleep(); // Buddy is sleeping (inherited) myDog.bark(); // Woof woof! (Dog-specific) } } ``` ### The `super` Keyword Use `super` to call parent class methods and constructors: ```java public class Animal { String name; public Animal(String name) { this.name = name; } public void makeSound() { System.out.println("Some sound"); } } public class Cat extends Animal { public Cat(String name) { super(name); // Call parent constructor } @Override // Annotation - marks override public void makeSound() { System.out.println("Meow!"); } } ``` --- ## Polymorphism **Polymorphism** means "many forms". A single method can behave differently based on the object type. ### Method Overriding ```java public class Shape { public void draw() { System.out.println("Drawing a shape"); } } public class Circle extends Shape { @Override public void draw() { System.out.println("Drawing a circle"); } } public class Square extends Shape { @Override public void draw() { System.out.println("Drawing a square"); } } public class Main { public static void main(String[] args) { Shape shape1 = new Circle(); Shape shape2 = new Square(); shape1.draw(); // Drawing a circle shape2.draw(); // Drawing a square } } ``` ### Using Polymorphism with Arrays ```java public class Main { public static void main(String[] args) { // Store different shapes in one array Shape[] shapes = new Shape[3]; shapes[0] = new Circle(); shapes[1] = new Square(); shapes[2] = new Triangle(); // Each draw() behaves differently! for (Shape shape : shapes) { shape.draw(); } } } ``` --- ## Abstract Classes An **abstract class** is a class that cannot be instantiated. It's a blueprint for other classes. ### Why Use Abstract Classes? - Provide common functionality to child classes - Force child classes to implement certain methods - Create a common interface ### Creating Abstract Classes ```java // Abstract class - can't create instances of this abstract class Animal { String name; // Abstract method - must be implemented by children public abstract void makeSound(); // Regular method - inherited by children public void eat() { System.out.println(name + " is eating"); } } class Dog extends Animal { @Override public void makeSound() { System.out.println("Woof!"); } } class Cat extends Animal { @Override public void makeSound() { System.out.println("Meow!"); } } public class Main { public static void main(String[] args) { Animal myDog = new Dog(); myDog.name = "Buddy"; myDog.eat(); // Buddy is eating myDog.makeSound(); // Woof! Animal myCat = new Cat(); myCat.name = "Whiskers"; myCat.makeSound(); // Meow! } } ``` --- ## Interfaces An **interface** is a contract that defines what methods a class must have. A class can implement multiple interfaces! ### Creating Interfaces ```java // Interface - defines what to do, not how interface Drawable { void draw(); // Abstract method - no body } interface Movable { void move(); } // Class implements both interfaces class Car implements Drawable, Movable { @Override public void draw() { System.out.println("Drawing a car"); } @Override public void move() { System.out.println("Car is moving"); } } ``` ### Interface vs Abstract Class | Interface | Abstract Class | |-----------|----------------| | Can implement multiple | Can extend only one | | Only abstract methods (Java 7) | Can have regular methods | | No constructor | Can have constructor | | All fields are constants | Can have regular fields | ### Default Methods (Java 8+) ```java interface Drawable { void draw(); // Default method - has a body! default void print() { System.out.println("Printing..."); } } ``` --- ## Packages and Imports **Packages** organize your code into folders. **Imports** bring in code from other packages. ### Creating Packages ```java // Save as: com/mycompany/util/StringHelper.java package com.mycompany.util; public class StringHelper { public static String reverse(String str) { return new StringBuilder(str).reverse().toString(); } } ``` ### Importing Packages ```java // Import a single class import java.util.Scanner; // Import all classes from a package import java.util.*; // Import static members import static java.lang.System.out; public class Main { public static void main(String[] args) { out.println("Hello!"); // Using static import Scanner scanner = new Scanner(System.in); } } ``` ### Common Packages | Package | Purpose | |---------|---------| | `java.lang` | Basic classes (String, Math, System) | | `java.util` | Collections, utilities | | `java.io` | Input/Output | | `java.time` | Date and time | | `java.net` | Networking | --- ## Exception Handling Basics **Exceptions** are errors that occur during program execution. Handling them prevents crashes! ### The Try-Catch Block ```java public class ExceptionDemo { public static void main(String[] args) { int[] numbers = {1, 2, 3}; try { System.out.println(numbers[5]); // This will cause an error! } catch (ArrayIndexOutOfBoundsException e) { System.out.println("Error: Index doesn't exist!"); System.out.println("Exception: " + e.getMessage()); } System.out.println("Program continues..."); } } ``` ### Multiple Catch Blocks ```java try { int result = 10 / 0; // ArithmeticException String s = null; s.length(); // NullPointerException } catch (ArithmeticException e) { System.out.println("Math error: " + e.getMessage()); } catch (NullPointerException e) { System.out.println("Null reference: " + e.getMessage()); } catch (Exception e) { System.out.println("Any other error: " + e.getMessage()); } ``` ### The Finally Block ```java try { System.out.println("Trying something..."); } catch (Exception e) { System.out.println("Error: " + e.getMessage()); } finally { System.out.println("This ALWAYS runs!"); } ``` ### Throwing Exceptions ```java public static void divide(int a, int b) throws ArithmeticException { if (b == 0) { throw new ArithmeticException("Cannot divide by zero!"); } System.out.println(a / b); } ``` --- ## Practice Exercises ### Exercise 1: Create a Class Create a `Rectangle` class with length and width. Add a method to calculate area. ```java public class Rectangle { private double length; private double width; public Rectangle(double length, double width) { this.length = length; this.width = width; } public double getArea() { return length * width; } public static void main(String[] args) { Rectangle rect = new Rectangle(5, 3); System.out.println("Area: " + rect.getArea()); // 15 } } ``` ### Exercise 2: Inheritance Create an `Employee` class and a `Manager` subclass. ```java class Employee { String name; double salary; public void work() { System.out.println(name + " is working"); } } class Manager extends Employee { int teamSize; public void lead() { System.out.println(name + " is leading " + teamSize + " people"); } } public class Exercise2 { public static void main(String[] args) { Manager mgr = new Manager(); mgr.name = "Alice"; mgr.salary = 80000; mgr.teamSize = 5; mgr.work(); // From Employee mgr.lead(); // Manager-specific } } ``` ### Exercise 3: Interface Create an interface `Playable` and implement it in a `Game` class. ```java interface Playable { void play(); } class Game implements Playable { private String name; public Game(String name) { this.name = name; } @Override public void play() { System.out.println("Playing " + name + "!"); } } public class Exercise3 { public static void main(String[] args) { Game game = new Game("Minecraft"); game.play(); // Playing Minecraft! } } ``` ### Exercise 4: Exception Handling Handle division by zero. ```java public class Exercise4 { public static int divide(int a, int b) { if (b == 0) { throw new ArithmeticException("Cannot divide by zero!"); } return a / b; } public static void main(String[] args) { try { System.out.println(divide(10, 0)); } catch (ArithmeticException e) { System.out.println("Error: " + e.getMessage()); } } } ``` ### Exercise 5: Polymorphism Create shapes with overridden methods. ```java abstract class Shape { abstract double getArea(); } class Circle extends Shape { double radius; Circle(double radius) { this.radius = radius; } @Override double getArea() { return Math.PI * radius * radius; } } class Rectangle extends Shape { double width, height; Rectangle(double width, double height) { this.width = width; this.height = height; } @Override double getArea() { return width * height; } } public class Exercise5 { public static void main(String[] args) { Shape[] shapes = {new Circle(5), new Rectangle(4, 6)}; for (Shape s : shapes) { System.out.println("Area: " + s.getArea()); } } } ``` --- ## Summary In this guide, you learned: - ✅ What OOP is and the four pillars - ✅ How to create classes and objects - ✅ How to use constructors - ✅ What encapsulation is and why it matters - ✅ How inheritance works - ✅ What polymorphism is - ✅ How to create abstract classes - ✅ How to use interfaces - ✅ How to organize code with packages - ✅ How to handle exceptions **Next Steps:** Move on to [Java Advanced Guide](./Java-Advanced-Guide.md) to learn about collections, streams, lambdas, and more! --- *You're becoming a Java pro! Keep going! 💪*