// Abstract class
abstract class Vehicle {
// Abstract method (does not have a body)
abstract void start();
// Regular method
void stop() {
System.out.println("The vehicle is stopping.");
}
}
// Subclass (inherits from Vehicle)
class Car extends Vehicle {
// Provide implementation for the abstract method
@Override
void start() {
System.out.println("The car is starting with a key.");
}
}
// Subclass (inherits from Vehicle)
class Motorcycle extends Vehicle {
// Provide implementation for the abstract method
@Override
void start() {
System.out.println("The motorcycle is starting with a button.");
}
}
// Main class to test the abstraction
public class Main {
public static void main(String[] args) {
Vehicle car = new Car(); // Upcasting
Vehicle motorcycle = new Motorcycle(); // Upcasting
car.start(); // Calls Car's start method
car.stop(); // Calls Vehicle's stop method
motorcycle.start(); // Calls Motorcycle's start method
motorcycle.stop(); // Calls Vehicle's stop method
}
}
OUTPUT:
The car is starting with a key.
The vehicle is stopping.
The motorcycle is starting with a button.
The vehicle is stopping.
EXPLANATION
1. Abstraction: The Vehicle class is abstract, which means it cannot be
instantiated directly. It defines the structure (with abstract and concrete
methods) that its subclasses must follow.
2. Abstract Method: The start method in the Vehicle class is abstract, so all
subclasses (Car and Motorcycle) must provide their implementation of this
method.
3. Polymorphism: The Vehicle reference type is used to hold objects of its
subclasses (Car and Motorcycle), demonstrating polymorphism.
This approach ensures that any class extending Vehicle must define its specific way
of starting, but they all inherit the stopping functionality.
// Class demonstrating encapsulation
class BankAccount {
// Private fields to restrict direct access
private String accountHolderName;
private double balance;
// Constructor to initialize account details
public BankAccount(String accountHolderName, double initialBalance) {
this.accountHolderName = accountHolderName;
if (initialBalance > 0) {
this.balance = initialBalance;
} else {
this.balance = 0.0;
System.out.println("Initial balance cannot be negative. Setting balance to
0.");
}
}
// Public getter for accountHolderName
public String getAccountHolderName() {
return accountHolderName;
}
// Public getter for balance
public double getBalance() {
return balance;
}
// Public setter for accountHolderName (optional, for updates)
public void setAccountHolderName(String accountHolderName) {
this.accountHolderName = accountHolderName;
}
// Method to deposit money
public void deposit(double amount) {
if (amount > 0) {
balance += amount;
System.out.println("Deposited: " + amount);
} else {
System.out.println("Deposit amount must be positive.");
}
}
// Method to withdraw money
public void withdraw(double amount) {
if (amount > 0 && amount <= balance) {
balance -= amount;
System.out.println("Withdrawn: " + amount);
} else if (amount > balance) {
System.out.println("Insufficient balance.");
} else {
System.out.println("Withdrawal amount must be positive.");
}
}
}
// Main class to test encapsulation
public class Main {
public static void main(String[] args) {
// Creating an instance of BankAccount
BankAccount account = new BankAccount("John Doe", 1000.0);
// Accessing and modifying the account using methods
System.out.println("Account Holder: " + account.getAccountHolderName());
System.out.println("Current Balance: " + account.getBalance());
// Performing transactions
account.deposit(500.0);
System.out.println("Balance after deposit: " + account.getBalance());
account.withdraw(300.0);
System.out.println("Balance after withdrawal: " + account.getBalance());
// Attempting invalid operations
account.deposit(-100.0);
account.withdraw(2000.0);
// Updating account holder's name
account.setAccountHolderName("Jane Doe");
System.out.println("Updated Account Holder: " +
account.getAccountHolderName());
}
}
OUTPUT
Account Holder: John Doe
Current Balance: 1000.0
Deposited: 500.0
Balance after deposit: 1500.0
Withdrawn: 300.0
Balance after withdrawal: 1200.0
Deposit amount must be positive.
Insufficient balance.
Updated Account Holder: Jane Doe
Key Features of Encapsulation in the Example:
1. Private Fields: The fields accountHolderName and balance are private,
ensuring they cannot be accessed directly.
2. Public Methods: Methods like getAccountHolderName(), getBalance(),
deposit(), and withdraw() provide controlled access to the fields.
3. Validation: Logic within methods ensures only valid data can be set or
modified (e.g., deposit and withdrawal checks).
4. Flexibility: The implementation details are hidden, and the interface for
interacting with the object is clean and straightforward.
This is a classic use of encapsulation to protect and control access to sensitive data.
// Parent class
class Animal {
// Method common to all animals
void eat() {
System.out.println("This animal eats food.");
}
}
// Subclass (inherits from Animal)
class Dog extends Animal {
// Method specific to Dog
void bark() {
System.out.println("The dog barks.");
}
}
// Subclass (inherits from Animal)
class Cat extends Animal {
// Method specific to Cat
void meow() {
System.out.println("The cat meows.");
}
}
// Main class to test inheritance
public class Main {
public static void main(String[] args) {
// Creating an instance of Dog
Dog dog = new Dog();
dog.eat(); // Inherited from Animal
dog.bark(); // Specific to Dog
// Creating an instance of Cat
Cat cat = new Cat();
cat.eat(); // Inherited from Animal
cat.meow(); // Specific to Cat
}
}
OUTPUT
This animal eats food.
The dog barks.
This animal eats food.
The cat meows.
Explanation:
1. Inheritance: The Dog and Cat classes inherit from the Animal class. This
means they have access to the eat() method defined in the Animal class.
2. Specialization: The Dog and Cat classes add their specific behavior (bark()
and meow() methods) while still inheriting common behavior from the Animal
class.
3. Reusability: The common eat() method is written once in the Animal class
but can be used by all its subclasses.
This approach demonstrates how inheritance promotes code reuse and allows
extending the behavior of a parent class in child classes.
// Abstract superclass
abstract class Shape {
// Abstract method to calculate area
abstract double calculateArea();
// Method to display area
void displayArea() {
System.out.println("Area: " + calculateArea());
}
}
// Subclass for Circle
class Circle extends Shape {
private double radius;
// Constructor
public Circle(double radius) {
this.radius = radius;
}
// Implementing calculateArea
@Override
double calculateArea() {
return Math.PI * radius * radius;
}
}
// Subclass for Rectangle
class Rectangle extends Shape {
private double length;
private double width;
// Constructor
public Rectangle(double length, double width) {
this.length = length;
this.width = width;
}
// Implementing calculateArea
@Override
double calculateArea() {
return length * width;
}
}
// Subclass for Triangle
class Triangle extends Shape {
private double base;
private double height;
// Constructor
public Triangle(double base, double height) {
this.base = base;
this.height = height;
}
// Implementing calculateArea
@Override
double calculateArea() {
return 0.5 * base * height;
}
}
// Main class to demonstrate polymorphism
public class Main {
public static void main(String[] args) {
// Polymorphism: Using Shape reference to hold objects of different types
Shape shape1 = new Circle(5); // Circle with radius 5
Shape shape2 = new Rectangle(4, 6); // Rectangle with length 4 and width 6
Shape shape3 = new Triangle(3, 8); // Triangle with base 3 and height 8
// Calling methods on the Shape reference
System.out.println("Circle:");
shape1.displayArea();
System.out.println("\nRectangle:");
shape2.displayArea();
System.out.println("\nTriangle:");
shape3.displayArea();
}
}
Circle:
Area: 78.53981633974483
Rectangle:
Area: 24.0
Triangle:
Area: 12.0
Explanation:
1. Abstract Class (Shape):
o Shape defines an abstract method calculateArea() that is overridden by
all subclasses.
o It also includes a concrete method displayArea() that uses the
calculateArea() method to print the area of the shape.
2. Subclasses (Circle, Rectangle, Triangle):
o Each subclass provides its specific implementation of the
calculateArea() method based on the shape's formula.
3. Polymorphism:
o A Shape reference (shape1, shape2, shape3) is used to hold objects of
its subclasses (Circle, Rectangle, Triangle).
o The method displayArea() is called on the Shape reference, and the
correct calculateArea() method is invoked dynamically at runtime
based on the actual object type.