0% found this document useful (0 votes)
12 views

Chapter 4 Java

Uploaded by

dawit kassa
Copyright
© © All Rights Reserved
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
12 views

Chapter 4 Java

Uploaded by

dawit kassa
Copyright
© © All Rights Reserved
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 50

Chapter 4

Q1: What is code reusability in Java?


A: Code reusability refers to the practice of using existing code for
new functions or programs instead of writing new code from scratch.
This is achieved through mechanisms like classes, interfaces, and
inheritance in Java.
Q2: How does inheritance contribute to code reusability?
A: Inheritance allows a new class (subclass) to inherit properties and
methods from an existing class (superclass). This enables
developers to reuse existing code and extend functionality without
modifying the original code.

Example 1: Basic Inheritance

// Superclass
class Animal {
void eat() {
System.out.println("This animal eats food.");
}
}

// Subclass
class Dog extends Animal {
void bark() {
System.out.println("The dog barks.");
}
}

// Usage
public class Main {
public static void main(String[] args) {
Dog dog = new Dog();
dog.eat(); // Inherited method
dog.bark(); // Dog's own method
}
}
Example 2: Method Overriding

// Superclass
class Vehicle {
void start() {
System.out.println("Vehicle is starting.");
}
}

// Subclass
class Car extends Vehicle {
@Override
void start() {
System.out.println("Car is starting.");
}
}

// Usage
public class Main {
public static void main(String[] args) {
Vehicle myCar = new Car();
myCar.start(); // Calls the overridden method in Car
}
}

Example 3: Multiple Levels of Inheritance

// Superclass
class Shape {
void display() {
System.out.println("This is a shape.");
}
}

// Intermediate subclass
class Circle extends Shape {
void draw() {
System.out.println("Drawing a circle.");
}
}

// Leaf subclass
class ColoredCircle extends Circle {
void fillColor() {
System.out.println("Filling the circle with color.");
}
}

// Usage
public class Main {
public static void main(String[] args) {
ColoredCircle coloredCircle = new ColoredCircle();
coloredCircle.display(); // Inherited from Shape
coloredCircle.draw(); // From Circle
coloredCircle.fillColor(); // From ColoredCircle
}
}

Example 4: Using Constructors in Inheritance


// Superclass
class Person {
String name;

Person(String name) {
this.name = name;
}
}

// Subclass
class Student extends Person {
int studentId;

Student(String name, int studentId) {


super(name); // Call superclass constructor
this.studentId = studentId;
}

void display() {
System.out.println("Name: " + name + ", Student ID: " +
studentId);
}
}

// Usage
public class Main {
public static void main(String[] args) {
Student student = new Student("Alice", 101);
student.display(); // Output: Name: Alice, Student ID: 101
}
}

Example 5: Abstract Classes and Inheritance

// Abstract superclass
abstract class Animal {
abstract void sound(); // Abstract method
}

// Subclass
class Cat extends Animal {
@Override
void sound() {
System.out.println("The cat meows.");
}
}

// Usage
public class Main {
public static void main(String[] args) {
Animal myCat = new Cat();
myCat.sound(); // Output: The cat meows.
}
}

Example 6: Interface Implementation with Inheritance


// Interface
interface Playable {
void play();
}

// Superclass
class Game {
void start() {
System.out.println("Game is starting.");
}
}

// Subclass implementing the interface


class Soccer extends Game implements Playable {
@Override
public void play() {
System.out.println("Playing soccer.");
}
}

// Usage
public class Main {
public static void main(String[] args) {
Soccer soccer = new Soccer();
soccer.start(); // From Game
soccer.play(); // From Playable
}
}

Q3: What are interfaces, and how do they promote code


reusability?
A: Interfaces define a contract that classes can implement. They
allow different classes to be treated in the same way, promoting
code reusability by enabling polymorphism. This means you can use
the same method names across different classes.

Example 1: Basic Interface Implementation


// Define an interface
interface Animal {
void sound();
}

// Implement the interface in different classes


class Dog implements Animal {
@Override
public void sound() {
System.out.println("Dog barks.");
}
}
class Cat implements Animal {
@Override
public void sound() {
System.out.println("Cat meows.");
}
}

// Usage
public class Main {
public static void main(String[] args) {
Animal myDog = new Dog();
Animal myCat = new Cat();

myDog.sound(); // Output: Dog barks.


myCat.sound(); // Output: Cat meows.
}
}

Example 2: Polymorphism with Interfaces

// Define the interface


interface Shape {
double area();
}

// Implement the interface in different classes


class Rectangle implements Shape {
private double width;
private double height;

Rectangle(double width, double height) {


this.width = width;
this.height = height;
}

@Override
public double area() {
return width * height;
}
}
class Circle implements Shape {
private double radius;

Circle(double radius) {
this.radius = radius;
}

@Override
public double area() {
return Math.PI * radius * radius;
}
}

// Usage
public class Main {
public static void main(String[] args) {
Shape[] shapes = { new Rectangle(4, 5), new Circle(3) };

for (Shape shape : shapes) {


System.out.println("Area: " + shape.area());
}
// Output:
// Area: 20.0
// Area: 28.274333882308138
}
}

Example 3: Multiple Interfaces

// Define the first interface


interface Playable {
void play();
}

// Define the second interface


interface Eatable {
void eat();
}

// Implement both interfaces in a single class


class Dog implements Playable, Eatable {
@Override
public void play() {
System.out.println("Dog is playing.");
}

@Override
public void eat() {
System.out.println("Dog is eating.");
}
}

// Usage
public class Main {
public static void main(String[] args) {
Dog dog = new Dog();
dog.play(); // Output: Dog is playing.
dog.eat(); // Output: Dog is eating.
}
}

Example 4: Default Methods in Interfaces


// Define the interface with a default method
interface Vehicle {
void start();

default void honk() {


System.out.println("Vehicle is honking.");
}
}

// Implement the interface in a class


class Car implements Vehicle {
@Override
public void start() {
System.out.println("Car is starting.");
}
}

// Usage
public class Main {
public static void main(String[] args) {
Car car = new Car();
car.start(); // Output: Car is starting.
car.honk(); // Output: Vehicle is honking.
}
}

Example 5: Interface as a Parameter

// Define the interface


interface Greeting {
void greet(String name);
}

// Implement the interface in different classes


class EnglishGreeting implements Greeting {
@Override
public void greet(String name) {
System.out.println("Hello, " + name + "!");
}
}

class SpanishGreeting implements Greeting {


@Override
public void greet(String name) {
System.out.println("¡Hola, " + name + "!");
}
}

// Method that uses the interface


public class Main {
public static void displayGreeting(Greeting greeting, String name)
{
greeting.greet(name);
}

public static void main(String[] args) {


Greeting english = new EnglishGreeting();
Greeting spanish = new SpanishGreeting();

displayGreeting(english, "Alice"); // Output: Hello, Alice!


displayGreeting(spanish, "Carlos"); // Output: ¡Hola, Carlos!
}
}

Example 6: Marker Interface


// Define a marker interface
interface Serializable {}

// A class implementing the marker interface


class Data implements Serializable {
// Class implementation
}

// Usage of the marker interface


public class Main {
public static void main(String[] args) {
Data data = new Data();
if (data instanceof Serializable) {
System.out.println("Data is serializable.");
} else {
System.out.println("Data is not serializable.");
}
// Output: Data is serializable.
}
}

Q4: Can you explain the concept of composition and how it


supports code reusability?
A: Composition involves building classes using references to other
classes, rather than inheriting from them. This allows for greater
flexibility and reusability, as you can combine different components
to create new functionality without the constraints of a class
hierarchy.
Example 1: Basic Composition
// Class representing an Engine
class Engine {
void start() {
System.out.println("Engine starting...");
}
}
// Class representing a Car that uses composition
class Car {
private Engine engine; // Reference to Engine

Car() {
this.engine = new Engine(); // Composition
}

void startCar() {
engine.start(); // Delegating the start action to the engine
System.out.println("Car is ready to go!");
}
}

// Usage
public class Main {
public static void main(String[] args) {
Car car = new Car();
car.startCar();
// Output:
// Engine starting...
// Car is ready to go!
}
}

Example 2: Composition with Multiple Components


// Class representing a Wheel
class Wheel {
void roll() {
System.out.println("Wheel is rolling.");
}
}

// Class representing a Car that uses multiple components


class Car {
private Engine engine; // Engine component
private Wheel[] wheels; // Array of Wheel components

Car() {
this.engine = new Engine();
this.wheels = new Wheel[4]; // A car typically has 4 wheels
for (int i = 0; i < wheels.length; i++) {
wheels[i] = new Wheel();
}
}

void startCar() {
engine.start();
for (Wheel wheel : wheels) {
wheel.roll();
}
System.out.println("Car is ready to go!");
}
}

// Usage
public class Main {
public static void main(String[] args) {
Car car = new Car();
car.startCar();
// Output:
// Engine starting...
// Wheel is rolling.
// Wheel is rolling.
// Wheel is rolling.
// Wheel is rolling.
// Car is ready to go!
}
}

Example 3: Using Interfaces for Composition


// Interface for Flyable
interface Flyable {
void fly();
}

// Class representing a Bird


class Bird implements Flyable {
@Override
public void fly() {
System.out.println("Bird is flying.");
}
}

// Class representing a Plane


class Plane implements Flyable {
@Override
public void fly() {
System.out.println("Plane is flying.");
}
}

// Class that uses composition with Flyable components


class FlyingMachine {
private Flyable flyable; // Composition

FlyingMachine(Flyable flyable) {
this.flyable = flyable;
}

void performFlight() {
flyable.fly(); // Delegating the flight action
}
}

// Usage
public class Main {
public static void main(String[] args) {
FlyingMachine birdMachine = new FlyingMachine(new Bird());
FlyingMachine planeMachine = new FlyingMachine(new
Plane());

birdMachine.performFlight(); // Output: Bird is flying.


planeMachine.performFlight(); // Output: Plane is flying.
}
}

Example 4: Composition with Configuration


// Class representing a configuration
class Configuration {
private String setting;

Configuration(String setting) {
this.setting = setting;
}

String getSetting() {
return setting;
}
}

// Class that uses composition to apply a configuration


class Application {
private Configuration config; // Composition

Application(Configuration config) {
this.config = config;
}

void run() {
System.out.println("Application running with setting: " +
config.getSetting());
}
}

// Usage
public class Main {
public static void main(String[] args) {
Configuration config = new Configuration("High Performance");
Application app = new Application(config);
app.run(); // Output: Application running with setting: High
Performance
}
}

Example 5: Dynamic Composition

// Class representing a Printer


class Printer {
void print(String message) {
System.out.println("Printing: " + message);
}
}
// Class representing a Document that uses composition
class Document {
private Printer printer; // Composition

Document(Printer printer) {
this.printer = printer; // Dependency injection
}

void printDocument(String content) {


printer.print(content); // Delegating print action
}
}

// Usage
public class Main {
public static void main(String[] args) {
Printer printer = new Printer();
Document doc = new Document(printer);
doc.printDocument("Hello, World!"); // Output: Printing: Hello,
World!
}
}

Example 6: Composition Over Inheritance


// Class representing a Sound System
class SoundSystem {
void playMusic() {
System.out.println("Playing music...");
}
}

// Class representing a Home Theater that uses composition


class HomeTheater {
private SoundSystem soundSystem; // Composition

HomeTheater() {
this.soundSystem = new SoundSystem(); // Composition
}

void watchMovie() {
System.out.println("Setting up the home theater...");
soundSystem.playMusic(); // Using the composed object
System.out.println("Enjoy the movie!");
}
}

// Usage
public class Main {
public static void main(String[] args) {
HomeTheater homeTheater = new HomeTheater();
homeTheater.watchMovie();
// Output:
// Setting up the home theater...
// Playing music...
// Enjoy the movie!
}
}

Q5: What is the DRY principle, and how does it relate to code
reusability?
A: The DRY (Don't Repeat Yourself) principle emphasizes reducing
code duplication. By reusing code through methods, classes, or
libraries, developers can adhere to this principle, making their
codebase cleaner and easier to maintain.
Q6: How can libraries and frameworks aid in code
reusability?
A: Libraries and frameworks provide pre-written code for common
tasks, allowing developers to leverage existing solutions rather than
creating new ones. This accelerates development and ensures
consistency across applications.
Q7: What role do design patterns play in code reusability?
A: Design patterns are established solutions to common problems in
software design. By following these patterns, developers can create
reusable code structures that facilitate easier maintenance and
scalability.
Q8: How can generic programming enhance code reusability
in Java?
A: Generic programming allows developers to define classes,
interfaces, and methods with type parameters. This enables the
creation of flexible and reusable code that can work with any data
type, reducing redundancy.
Q9: What is the significance of modular programming in
terms of code reusability?
A: Modular programming involves breaking down a program into
smaller, manageable, and reusable modules. This makes it easier to
test, maintain, and reuse code across different projects.
Q10: Can you provide an example of how to achieve code
reusability with methods in Java?
A: Yes! Here’s a simple example:
java
Copy
public class MathUtils {
// Method to add two numbers
public static int add(int a, int b) {
return a + b;
}

// Method to multiply two numbers


public static int multiply(int a, int b) {
return a * b;
}
}

// Usage in another class


public class Main {
public static void main(String[] args) {
int sum = MathUtils.add(5, 10);
int product = MathUtils.multiply(5, 10);

System.out.println("Sum: " + sum); // Output: Sum: 15


System.out.println("Product: " + product); // Output: Product: 50
}
}
This example demonstrates how to create reusable methods in a
utility class, which can be called from other parts of the program.

Q11: What are static methods, and how do they promote


code reusability?
A: Static methods belong to the class rather than any instance of
the class. They can be called without creating an object, making
them ideal for utility or helper methods that can be reused
throughout the application.
Example 1: Basic Static Method
class MathUtils {
// Static method to add two numbers
static int add(int a, int b) {
return a + b;
}
}

// Usage
public class Main {
public static void main(String[] args) {
int sum = MathUtils.add(5, 10);
System.out.println("Sum: " + sum); // Output: Sum: 15
}
}

Example 2: Static Methods for Utility Functions


class StringUtils {
// Static method to reverse a string
static String reverse(String str) {
return new StringBuilder(str).reverse().toString();
}
}

// Usage
public class Main {
public static void main(String[] args) {
String original = "Hello";
String reversed = StringUtils.reverse(original);
System.out.println("Reversed: " + reversed); // Output:
Reversed: olleH
}
}

Example 3: Static Methods with Parameters


class Converter {
// Static method to convert Celsius to Fahrenheit
static double celsiusToFahrenheit(double celsius) {
return (celsius * 9/5) + 32;
}
}
// Usage
public class Main {
public static void main(String[] args) {
double celsius = 25;
double fahrenheit = Converter.celsiusToFahrenheit(celsius);
System.out.println(celsius + " °C = " + fahrenheit + " °F"); //
Output: 25.0 °C = 77.0 °F
}
}

Example 4: Static Block Initialization


class Config {
static String CONFIG;

// Static block to initialize static variables


static {
CONFIG = "Application Configuration Loaded";
}

// Static method to display configuration


static void displayConfig() {
System.out.println(CONFIG);
}
}

// Usage
public class Main {
public static void main(String[] args) {
Config.displayConfig(); // Output: Application Configuration
Loaded
}
}

Example 5: Static Methods in a Singleton Patter


class Singleton {
private static Singleton instance;

// Private constructor to prevent instantiation


private Singleton() {}
// Static method to provide access to the instance
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}

void showMessage() {
System.out.println("Hello from Singleton!");
}
}

// Usage
public class Main {
public static void main(String[] args) {
Singleton singleton = Singleton.getInstance();
singleton.showMessage(); // Output: Hello from Singleton!
}
}

Example 6: Static Methods with Overloading


class Display {
// Static method to display an integer
static void show(int number) {
System.out.println("Integer: " + number);
}

// Overloaded static method to display a string


static void show(String message) {
System.out.println("Message: " + message);
}
}

// Usage
public class Main {
public static void main(String[] args) {
Display.show(100); // Output: Integer: 100
Display.show("Hello!"); // Output: Message: Hello!
}
}
Example 7: Static Methods in a Math Library
class MathLibrary {
// Static method to compute the factorial of a number
static long factorial(int n) {
if (n == 0) return 1;
long result = 1;
for (int i = 1; i <= n; i++) {
result *= i;
}
return result;
}
}

// Usage
public class Main {
public static void main(String[] args) {
int number = 5;
long fact = MathLibrary.factorial(number);
System.out.println("Factorial of " + number + " is " + fact); //
Output: Factorial of 5 is 120
}
}

Q12: How does the use of packages enhance code reusability


in Java?
A: Packages group related classes and interfaces, making it easier
to organize code. By using packages, developers can import and
reuse classes across different projects, promoting modular design
and reducing redundancy.

Example 1: Creating and Using a Package


MathUtils Class in Package

src/
└── com/
└── example/
└── utils/
└── MathUtils.java

// File: src/com/example/utils/MathUtils.java
package com.example.utils;

public class MathUtils {


public static int add(int a, int b) {
return a + b;
}

public static int subtract(int a, int b) {


return a - b;
}
}

Using the Package in Another Class

Create another class to use the MathUtils class:

// File: src/Main.java

import com.example.utils.MathUtils;

public class Main {

public static void main(String[] args) {

int sum = MathUtils.add(10, 5);

int difference = MathUtils.subtract(10, 5);

System.out.println("Sum: " + sum); // Output: Sum: 15

System.out.println("Difference: " + difference); // Output:


Difference: 5

}
}

Example 2: Creating a Package with Multiple Classes


src/

└── com/

└── example/

└── shapes/

├── Circle.java

└── Rectangle.java

Circle Class

// File: src/com/example/shapes/Circle.java

package com.example.shapes;

public class Circle {

private double radius;

public Circle(double radius) {

this.radius = radius;

public double area() {

return Math.PI * radius * radius;


}

Rectangle Class

// File: src/com/example/shapes/Rectangle.java

package com.example.shapes;

public class Rectangle {

private double width;

private double height;

public Rectangle(double width, double height) {

this.width = width;

this.height = height;

public double area() {

return width * height;

Using the Package

// File: src/Main.java
import com.example.shapes.Circle;

import com.example.shapes.Rectangle;

public class Main {

public static void main(String[] args) {

Circle circle = new Circle(5);

Rectangle rectangle = new Rectangle(4, 6);

System.out.println("Circle Area: " + circle.area()); // Output:


Circle Area: 78.53981633974483

System.out.println("Rectangle Area: " + rectangle.area()); //


Output: Rectangle Area: 24.0

Example 3: Using import Statements


1. Creating a New Package

src/

└── com/

└── example/

└── animals/

├── Dog.java

└── Cat.java
Dog Class

// File: src/com/example/animals/Dog.java

package com.example.animals;

public class Dog {

public void bark() {

System.out.println("Dog barks!");

Cat Class

// File: src/com/example/animals/Cat.java

package com.example.animals;

public class Cat {

public void meow() {

System.out.println("Cat meows!");

Using Import Statements

// File: src/Main.java

import com.example.animals.Dog;

import com.example.animals.Cat;
public class Main {

public static void main(String[] args) {

Dog dog = new Dog();

Cat cat = new Cat();

dog.bark(); // Output: Dog barks!

cat.meow(); // Output: Cat meows!

Example 4: Subpackages
1. Creating a Subpackage

src/

└── com/

└── example/

├── animals/

│ ├── Dog.java

│ └── Cat.java

└── services/

└── AnimalService.java

AnimalService Class
// File: src/com/example/services/AnimalService.java

package com.example.services;

import com.example.animals.Dog;

import com.example.animals.Cat;

public class AnimalService {

public void makeSound() {

Dog dog = new Dog();

Cat cat = new Cat();

dog.bark();

cat.meow();

Using the Subpackage

// File: src/Main.java

import com.example.services.AnimalService;

public class Main {

public static void main(String[] args) {

AnimalService animalService = new AnimalService();

animalService.makeSound();
// Output:

// Dog barks!

// Cat meows!

Example 5: Package Access Modifiers


1. Creating a Class with Default Access Modifier

// File: src/com/example/animals/Cat.java

package com.example.animals;

class Cat { // Default access modifier

public void meow() {

System.out.println("Cat meows!");

Accessing the Class from the Same Package

// File: src/com/example/animals/Dog.java

package com.example.animals;

public class Dog {

public void bark() {

Cat cat = new Cat(); // Accessible because it's in the same


package
cat.meow();

System.out.println("Dog barks!");

Using the Classes

// File: src/Main.java
import com.example.animals.Dog;

public class Main {


public static void main(String[] args) {
Dog dog = new Dog();
dog.bark();
// Output:
// Cat meows!
// Dog barks!
}
}

Q13: What is the importance of Java libraries in promoting


code reusability?
A: Java libraries, such as the Java Standard Library, provide pre-
written code for various functionalities (e.g., data structures,
networking). Developers can reuse these libraries to save time and
effort, ensuring reliability and efficiency.

Example 1: Using the Java Collections Framework


The Java Collections Framework provides classes for storing and
manipulating groups of data.

import java.util.ArrayList;
import java.util.Collections;

public class Main {


public static void main(String[] args) {
// Create a list using ArrayList
ArrayList<String> names = new ArrayList<>();
names.add("Alice");
names.add("Bob");
names.add("Charlie");

// Sort the list


Collections.sort(names);

// Print the sorted list


System.out.println("Sorted names: " + names);
// Output: Sorted names: [Alice, Bob, Charlie]
}
}

Example 2: Using the Java Stream API


The Stream API allows for functional-style operations on streams of
elements.

import java.util.Arrays;
import java.util.List;

public class Main {


public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);

// Use Stream API to filter and sum


int sum = numbers.stream()
.filter(n -> n % 2 == 0) // Only even numbers
.mapToInt(Integer::intValue)
.sum();

System.out.println("Sum of even numbers: " + sum); // Output:


Sum of even numbers: 6
}
}
Example 3: Using the java.time Package for Date and Time
The java.time package provides a modern date and time API.

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;

public class Main {


public static void main(String[] args) {
// Get the current date
LocalDate today = LocalDate.now();
System.out.println("Today's date: " + today);

// Format the date


DateTimeFormatter formatter =
DateTimeFormatter.ofPattern("dd-MM-yyyy");
String formattedDate = today.format(formatter);
System.out.println("Formatted date: " + formattedDate);
// Output: Today's date: 2024-09-24 (example output)
// Output: Formatted date: 24-09-2024
}
}

Q14: How does the concept of "loose coupling" relate to


code reusability?
A: Loose coupling refers to designing components that are
independent of each other. This allows for easier code reuse, as
changes to one component do not affect others. It simplifies
maintenance and enhances flexibility in code design.
Q15: Can you explain how annotations can be used to
support code reusability?
A: Annotations provide metadata about code elements, allowing
frameworks to process them in reusable ways. For example, Java's
Spring framework uses annotations for dependency injection,
enabling reusable and configurable components.
Q16: What is the role of abstract classes in code reusability?
A: Abstract classes provide a base for other classes, allowing shared
code implementation while enforcing a contract for subclasses. This
promotes code reusability by allowing subclasses to inherit common
behaviors while defining specific implementations.

Example 1: Basic Abstract Class

// Abstract class
abstract class Animal {
// Abstract method (does not have a body)
abstract void sound();

// Concrete method
void sleep() {
System.out.println("Sleeping...");
}
}

// Subclass that extends the abstract class


class Dog extends Animal {
@Override
void sound() {
System.out.println("Dog barks!");
}
}

// Usage
public class Main {
public static void main(String[] args) {
Animal myDog = new Dog();
myDog.sound(); // Output: Dog barks!
myDog.sleep(); // Output: Sleeping...
}
}

Example 2: Abstract Class with Constructor


// Abstract class
abstract class Vehicle {
private String brand;

// Constructor
Vehicle(String brand) {
this.brand = brand;
}

// Abstract method
abstract void start();

// Concrete method
String getBrand() {
return brand;
}
}

// Subclass that extends the abstract class


class Car extends Vehicle {
Car(String brand) {
super(brand); // Call the constructor of Vehicle
}

@Override
void start() {
System.out.println(getBrand() + " car is starting.");
}
}

// Usage
public class Main {
public static void main(String[] args) {
Vehicle myCar = new Car("Toyota");
myCar.start(); // Output: Toyota car is starting.
}
}

Example 3: Multiple Subclasses

// Abstract class
abstract class Shape {
abstract double area(); // Abstract method
}

// Subclass for Circle


class Circle extends Shape {
private double radius;

Circle(double radius) {
this.radius = radius;
}

@Override
double area() {
return Math.PI * radius * radius;
}
}

// Subclass for Rectangle


class Rectangle extends Shape {
private double width;
private double height;

Rectangle(double width, double height) {


this.width = width;
this.height = height;
}

@Override
double area() {
return width * height;
}
}

// Usage
public class Main {
public static void main(String[] args) {
Shape circle = new Circle(5);
Shape rectangle = new Rectangle(4, 6);

System.out.println("Circle Area: " + circle.area()); // Output:


Circle Area: 78.53981633974483
System.out.println("Rectangle Area: " + rectangle.area()); //
Output: Rectangle Area: 24.0
}
}

Example 4: Abstract Class with Method Implementation

// Abstract class
abstract class Employee {
String name;

Employee(String name) {
this.name = name;
}
// Abstract method
abstract double calculateSalary();

// Concrete method
void display() {
System.out.println("Employee Name: " + name);
}
}

// Subclass for FullTimeEmployee


class FullTimeEmployee extends Employee {
private double monthlySalary;

FullTimeEmployee(String name, double monthlySalary) {


super(name);
this.monthlySalary = monthlySalary;
}

@Override
double calculateSalary() {
return monthlySalary * 12; // Annual salary
}
}

// Subclass for PartTimeEmployee


class PartTimeEmployee extends Employee {
private double hourlyWage;
private int hoursWorked;

PartTimeEmployee(String name, double hourlyWage, int


hoursWorked) {
super(name);
this.hourlyWage = hourlyWage;
this.hoursWorked = hoursWorked;
}

@Override
double calculateSalary() {
return hourlyWage * hoursWorked; // Total earnings
}
}

// Usage
public class Main {
public static void main(String[] args) {
Employee fullTime = new FullTimeEmployee("Alice", 3000);
Employee partTime = new PartTimeEmployee("Bob", 20, 80);

fullTime.display();
System.out.println("Annual Salary: " +
fullTime.calculateSalary()); // Output: Annual Salary: 36000.0

partTime.display();
System.out.println("Total Earnings: " +
partTime.calculateSalary()); // Output: Total Earnings: 1600.0
}
}

Example 5: Abstract Class with Final Method

// Abstract class
abstract class Animal {
abstract void sound(); // Abstract method

// Final method
final void info() {
System.out.println("Animals are living beings.");
}
}

// Subclass
class Cat extends Animal {
@Override
void sound() {
System.out.println("Cat meows!");
}
}

// Usage
public class Main {
public static void main(String[] args) {
Animal myCat = new Cat();
myCat.sound(); // Output: Cat meows!
myCat.info(); // Output: Animals are living beings.
}
}

Q17: How can exception handling contribute to code


reusability?
A: By defining custom exceptions, developers can create reusable
error-handling mechanisms across applications. This encapsulates
error logic and allows consistent handling of specific scenarios,
making code more maintainable.
Q18: What are lambda expressions, and how do they
enhance code reusability?
A: Lambda expressions allow for the creation of anonymous
functions. They enable developers to pass behavior as parameters,
leading to more reusable and concise code, especially in functional
programming paradigms.
Q19: How can unit testing frameworks promote code
reusability?
A: Unit testing frameworks like JUnit allow developers to write
reusable test cases for their code. Once written, these tests can be
run against different versions of the code, ensuring functionality
remains consistent across changes.
Q20: What is the significance of version control in
maintaining reusable code?
A: Version control systems (e.g., Git) help track changes in code
over time. This allows developers to reuse stable versions of code,
collaborate effectively, and maintain a history of changes,
facilitating better management of reusable components.
Q21: How do functional interfaces support code reusability?
A: Functional interfaces (interfaces with a single abstract method)
allow for the use of lambda expressions and method references.
This encourages reusable code patterns, especially in APIs that
require callbacks or event handling.
Q22: Can you provide an example of using interfaces for
code reusability?
A: Here’s an example illustrating the use of interfaces:
Java

// Define a reusable interface


interface Shape {
double area();
}

// Implement the interface in different classes


class Circle implements Shape {
private double radius;

public Circle(double radius) {


this.radius = radius;
}

@Override
public double area() {
return Math.PI * radius * radius;
}
}

class Rectangle implements Shape {


private double width;
private double height;

public Rectangle(double width, double height) {


this.width = width;
this.height = height;
}

@Override
public double area() {
return width * height;
}
}

// Usage in another class


public class Main {
public static void main(String[] args) {
Shape circle = new Circle(5);
Shape rectangle = new Rectangle(4, 6);

System.out.println("Circle Area: " + circle.area()); //


Output: Circle Area: 78.53981633974483
System.out.println("Rectangle Area: " + rectangle.area()); //
Output: Rectangle Area: 24.0
}
}
This example shows how different shapes can implement a common
interface, promoting code reusability and flexibility in handling
different shape types through a unified method.
What is the output of the following code?

class Parent {

void display() {

System.out.println("Parent");

class Child extends Parent {

void display() {

System.out.println("Child");

public class Main {

public static void main(String[] args) {

Parent obj = new Child();

obj.display();

A) Parent
B) Child
C) Compilation Error
D) Runtime Error
Answer: B) Child
Which of the following is an example of polymorphism in
Java?
A) Method Overloading
B) Method Overriding
C) Both A and B
D) None of the above
Answer: C) Both A and B

Question 6: Composition vs Aggregation


Which of the following best describes composition?
A) A relationship where one class can contain references to another
class.
B) A relationship where one class can exist independently of the
other.
C) A "has-a" relationship that implies ownership.
D) Both A and C.
Answer: D) Both A and C.

Question 7: Method Overloading


What will be the output of the following code?

class Test {

void display(int a) {

System.out.println("Integer: " + a);

void display(double b) {

System.out.println("Double: " + b);

public class Main {

public static void main(String[] args) {


Test test = new Test();

test.display(10); // Line A

test.display(10.5); // Line B

A) Integer: 10
Double: 10.5
B) Compilation Error
C) Integer: 10
Double: 10
D) Integer: 10
Double: 10.0
Answer: A) Integer: 10
Double: 10.5

Question 8: Interface Implementation


What is the output of the following code?

interface Animal {

void sound();

class Dog implements Animal {

public void sound() {

System.out.println("Dog barks!");

public class Main {

public static void main(String[] args) {


Animal myDog = new Dog();

myDog.sound();

A) Dog barks!
B) Compilation Error
C) Runtime Error
D) No output
Answer: A) Dog barks!

Question 9: Abstract Method


What happens if a class extends an abstract class but does
not implement its abstract methods?
A) The class can be instantiated.
B) A compilation error occurs.
C) The class is automatically made abstract.
D) Both B and C.
Answer: D) Both B and C.

Question 10: Aggregation


Which of the following statements about aggregation is
correct?
A) The lifetime of the contained object is managed by the container
object.
B) It represents a "part-of" relationship.
C) The contained object can exist independently of the container
object.
D) Both B and C.
Answer: D) Both B and C.

Question 11: Method Overriding


What is the result of the following code?

class Base {

void show() {

System.out.println("Base class");
}

class Derived extends Base {

void show() {

System.out.println("Derived class");

public class Main {

public static void main(String[] args) {

Base obj = new Derived();

obj.show();

A) Base class
B) Derived class
C) Compilation Error
D) Runtime Error
Answer: B) Derived class

Question 12: Final Keyword


What happens if you declare a class as final in Java?
A) The class can be inherited.
B) The class cannot be inherited.
C) The class cannot have any methods.
D) The class cannot be instantiated.
Answer: B) The class cannot be inherited.

Question 13: Abstract Class vs Interface


Which of the following statements is true regarding abstract
classes and interfaces?
A) An abstract class can implement multiple interfaces, but an
interface cannot extend classes.
B) An interface can have constructors, but an abstract class cannot.
C) An abstract class can have instance variables, but an interface
cannot.
D) Both A and C.
Answer: D) Both A and C.

Question 14: Composition Example


Which of the following best describes the relationship shown
in the code below?

class Engine {

// Engine properties and methods

class Car {

private Engine engine; // Composition relationship

Car(Engine engine) {

this.engine = engine;

A) Aggregation
B) Composition
C) Inheritance
D) Polymorphism

Answer: B) Composition

Question 15: Polymorphism with Interfaces


What will be the output of the following code?

interface Shape {

void draw();

class Circle implements Shape {

public void draw() {

System.out.println("Drawing Circle");

class Square implements Shape {

public void draw() {

System.out.println("Drawing Square");

public class Main {

public static void main(String[] args) {

Shape shape1 = new Circle();

Shape shape2 = new Square();

shape1.draw();

shape2.draw();

A) Drawing Circle
Drawing Square
B) Compilation Error
C) Drawing Circle
Circle
D) Drawing Square
Square
Answer: A) Drawing Circle
Drawing Square

Question 16: Abstract Class Instantiation


Can you instantiate an abstract class in Java?
A) Yes, it can be instantiated.
B) No, it cannot be instantiated.
C) Only if it has concrete methods.
D) Only if it has a constructor.
Answer: B) No, it cannot be instantiated.

Question 17: Inheritance Hierarchy


Given the following class hierarchy, what will be the output
of the code?

class Animal {

void eat() {

System.out.println("Animal eats");

class Dog extends Animal {

void bark() {

System.out.println("Dog barks");

public class Main {

public static void main(String[] args) {

Animal obj = new Dog();


obj.eat();

// obj.bark(); // Uncommenting this line will cause an error

A) Animal eats
B) Dog barks
C) Compilation Error
D) Runtime Error
Answer: A) Animal eats

Question 18: Interface Inheritance


Which of the following is true about an interface inheriting
another interface?
A) An interface cannot extend another interface.
B) An interface can extend multiple interfaces.
C) An interface can have constructors.
D) An interface can implement other interfaces.
Answer: B) An interface can extend multiple interfaces.

Question 19: Method Overloading


What is method overloading?
A) Defining multiple methods with the same name in different
classes.
B) Defining multiple methods with the same name but different
parameters in the same class.
C) Overriding a method in a subclass.
D) Changing the return type of a method.
Answer: B) Defining multiple methods with the same name but
different parameters in the same class.

Question 20: Access Modifiers


Which access modifier allows a class to be accessible only
within its own package?
A) public
B) private
C) protected
D) Default (no modifier)
Answer: D) Default (no modifier)
Question 21: Interface Implementation
If a class implements an interface, what must it do?
A) Provide implementations for all methods declared in the
interface.
B) Only implement some methods from the interface.
C) It can leave the methods unimplemented.
D) It can inherit from another class.
Answer: A) Provide implementations for all methods declared in the
interface.

Question 22: Abstract Class with Final Method


What will happen if you declare a method in an abstract
class as final?
A) The method can be overridden in subclasses.
B) The method cannot be overridden in subclasses.
C) The method cannot be defined in the abstract class.
D) The method must be abstract.
Answer: B) The method cannot be overridden in subclasses.

Question 23: Composition vs Inheritance


Which statement best describes the difference between
composition and inheritance?
A) Composition is a "is-a" relationship; inheritance is a "has-a"
relationship.
B) Inheritance is a "is-a" relationship; composition is a "has-a"
relationship.
C) Both represent the same relationship.
D) Neither supports code reusability.
Answer: B) Inheritance is a "is-a" relationship; composition is a
"has-a" relationship.
Question 24: Polymorphism at Runtime
What is runtime polymorphism in Java?
A) It occurs when a method is overloaded.
B) It is achieved through method overriding.
C) It is determined at compile-time.
D) It cannot be achieved in Java.
Answer: B) It is achieved through method overriding.
Question 25: Abstract Classes and Interfaces
Which of the following statements is false?
A) An abstract class can have both abstract and concrete methods.
B) An interface can have only abstract methods.
C) A class can implement multiple interfaces.
D) An abstract class can implement multiple interfaces.
Answer: B) An interface can have only abstract methods. (As of
Java 8, interfaces can also have default and static methods.)

You might also like