-
-
Notifications
You must be signed in to change notification settings - Fork 2
Java Intermediate Guide
- Introduction to OOP
- Classes and Objects
- Constructors
- Encapsulation
- Inheritance
- Polymorphism
- Abstract Classes
- Interfaces
- Packages and Imports
- Exception Handling Basics
- Practice Exercises
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)
| 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 |
A class is a blueprint - it defines what an object will look like. An object is an actual thing created from that blueprint.
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);
}
}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 | Object |
|---|---|
| Blueprint | Actual thing |
| Defines properties and methods | Has actual values |
| One class, many objects | Created from a class |
A constructor is a special method that runs when you create an object. It's used to set up the object with initial values.
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
}
}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
}
}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 means protecting data by controlling how it's accessed. You hide the internal details and only expose what's necessary.
// 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 encapsulationpublic 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!");
}
}
}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 allows a class to inherit properties and methods from another class. The child class gets everything from the parent!
// 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)
}
}Use super to call parent class methods and constructors:
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 means "many forms". A single method can behave differently based on the object type.
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
}
}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();
}
}
}An abstract class is a class that cannot be instantiated. It's a blueprint for other classes.
- Provide common functionality to child classes
- Force child classes to implement certain methods
- Create a common interface
// 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!
}
}An interface is a contract that defines what methods a class must have. A class can implement multiple interfaces!
// 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 | 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 |
interface Drawable {
void draw();
// Default method - has a body!
default void print() {
System.out.println("Printing...");
}
}Packages organize your code into folders. Imports bring in code from other packages.
// 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();
}
}// 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);
}
}| 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 |
Exceptions are errors that occur during program execution. Handling them prevents crashes!
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...");
}
}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());
}try {
System.out.println("Trying something...");
} catch (Exception e) {
System.out.println("Error: " + e.getMessage());
} finally {
System.out.println("This ALWAYS runs!");
}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);
}Create a Rectangle class with length and width. Add a method to calculate area.
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
}
}Create an Employee class and a Manager subclass.
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
}
}Create an interface Playable and implement it in a Game class.
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!
}
}Handle division by zero.
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());
}
}
}Create shapes with overridden methods.
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());
}
}
}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 to learn about collections, streams, lambdas, and more!
You're becoming a Java pro! Keep going! 💪