Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
0% found this document useful (0 votes)
2 views

Object Oreinted Programming

The document discusses the design of a real-time messaging application using Object-Oriented Programming (OOP) and a modular approach, highlighting the benefits of encapsulation, inheritance, and polymorphism. It also addresses issues in initial designs, proposing a redesign that incorporates interfaces, simplified inheritance, and design patterns like Factory and Strategy for better maintainability and extensibility. Additionally, it includes code examples for various classes such as BankAccount, Rectangle, and Student, demonstrating fundamental OOP principles.

Uploaded by

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

Object Oreinted Programming

The document discusses the design of a real-time messaging application using Object-Oriented Programming (OOP) and a modular approach, highlighting the benefits of encapsulation, inheritance, and polymorphism. It also addresses issues in initial designs, proposing a redesign that incorporates interfaces, simplified inheritance, and design patterns like Factory and Strategy for better maintainability and extensibility. Additionally, it includes code examples for various classes such as BankAccount, Rectangle, and Student, demonstrating fundamental OOP principles.

Uploaded by

Khurram Shehzad
Copyright
© © All Rights Reserved
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 48

Question 1:

DESIGNING A REAL TIME MESSAGING APPLICATION.


1. BENEFITS OF OOP APPROACH:
- Encapsulation: User, Message, and Notification classes can encapsulate
relevant data and behaviors, which improves modularity and reusability. Each class
would handle its own data and methods, such as User.createProfile() or
Message.send().
- Inheritance: Common elements across different message types (text, image,
video) can share a base class, like `Message`, with subclasses for TextMessage,
ImageMessage, etc. This setup allows new features to be added easily by extending
base classes.
- Polymorphism: For handling different message types in a uniform way,
polymorphism would be key. The system can treat all messages as `Message`
objects, making it easier to manage different media types and add future message
types.

2. BENEFITS OF MODULAR/STRUCTURAL APPROACH:


- Functional Modules: Using modules for specific functions, such as
`NotificationModule`, `MessageHandler`, or `UserManagement`, would help keep
the codebase organized and reduce complexity. Each module can focus on a single
functionality, which makes the code more maintainable.
- Scalability: Functional modules make it easier to horizontally scale parts of the
application independently. For example, the messaging module could be scaled
separately to handle a surge in message traffic, while user management and
notification modules remain stable.
- Simplicity and Efficiency: This approach promotes simplicity by keeping
functions focused and modular, which can lead to better performance and easier
debugging.

WHICH APPROACH TO FOLLOW:


For designing an application like this a hybrid approach would be best fit, which
have combined characteristics of both approaches.

3. HYBRID APPROACH:
- Core Components: Use OOP to design the main classes for data modeling,
encapsulation, and easy addition of new features.
- Modules for Functional Organization: Divide the application into modules by
functionality. For instance:
- `UserModule` for handling user-related actions (signup, profile management).

Page | 1
- `MessageModule` for messaging logic, which could use polymorphism for
message types.
- `NotificationModule` for handling real-time notifications and updating users.
- Scalable Architecture: With modules, each component can be scaled
independently based on demand. This is essential for supporting millions of users.

WHY THIS APPROACH:


- Flexibility: The hybrid model combines the best of both worlds, making it easier
to add features like voice or video calls by extending the core classes while
maintaining a functional organization.
- Maintainability and Scalability: Encapsulated classes in OOP allow for future
extensions without affecting existing code, and modularity allows for independent
scaling and simplified maintenance.
- Performance: By separating concerns and utilizing efficient modules, the app can
achieve high performance and fast response times, critical for a real-time app.

Question 2:
ISSUES IN THE INITIAL DESIGN
1. Code Duplication: Common functions (e.g., borrowing and reserving) are
repeated in multiple subclasses.
2. Inflexibility: Adding new media types requires modifying existing classes,
making the codebase prone to errors.
3. Complexity: A deep inheritance hierarchy leads to a hard-to-maintain and
complex structure.

REDESIGN USING OBJECT-ORIENTED CONCEPTS


1. Introduce Interfaces for Common Behaviors:
- Define interfaces for common behaviors such as `Borrowable` and `Reservable`.

CODE:
interface Borrowable {
void borrow();
void returnItem();

Page | 2
double calculateLateFee(int daysLate);
}

interface Reservable {
void reserve();
void cancelReservation();
}

2. Simplify the Inheritance Structure with a Single Base Class:


- Instead of having complex subclass-specific logic, define a single, simple
`MediaItem` base class with attributes common to all media types (e.g., `title`,
`author`, `catalogNumber`).
- Specific attributes for each media type can be handled by additional fields in
subclasses but without duplicating functionality.

CODE:
abstract class MediaItem {
private String title;
private String author;
private String catalogNumber;

public MediaItem(String title, String author, String catalogNumber) {


this.title = title;
this.author = author;
this.catalogNumber = catalogNumber;
}

// Common methods like getTitle, getAuthor, etc.


}

3. Use Composition to Handle Media-Specific Behavior:

Page | 3
- Create separate classes for functionalities instead of coding them directly in the
media subclasses. For instance, create a `BorrowingService` to handle the
borrowing logic, late fees, and reservations.

CODE:
class BorrowingService {
public void borrowItem(MediaItem item) {
// Logic for borrowing an item
}

public double calculateLateFee(MediaItem item, int daysLate) {


// Calculate fee based on item type
}
}

4. Use the Factory Pattern for New Media Types:


- To make it easy to add new media types, use the **Factory Pattern** to create
`MediaItem` objects. This way, you can extend the catalog by adding new item
types (e.g., Blu-rays) without modifying existing classes.

CODE:
class MediaItemFactory {
public static MediaItem createMediaItem(String type, String title, String author)
{
switch (type) {
case "Book": return new Book(title, author);
case "EBook": return new EBook(title, author);
// Other cases for media types
default: throw new IllegalArgumentException("Invalid media type");
}
}
}

Page | 4
5. Apply the Open-Closed Principle for Future Expansion:
- By decoupling functionality (borrowing, reserving) from the `MediaItem`
subclasses, you can add new behaviors or media types without modifying existing
code. This follows the Open-Closed Principle, which ensures the system is open to
extension but closed to modification.

6. Strategy Pattern for Late Fee Calculation:


- Implement the Strategy Pattern to calculate late fees. Define different
strategies for calculating fees for each media type, which makes the system
adaptable to future media items with unique fee structures.

CODE:
interface LateFeeStrategy {
double calculateFee(int daysLate);
}

class BookLateFeeStrategy implements LateFeeStrategy {


public double calculateFee(int daysLate) {
return daysLate * 0.5;
}
}

class DVDFeeStrategy implements LateFeeStrategy {


public double calculateFee(int daysLate) {
return daysLate * 1.0;
}
}

BENEFITS OF REDESIGN:
1. Improved Reusability: Interfaces (`Borrowable`, `Reservable`) allow reusing
functionality across different media types without duplicating code.

Page | 5
2. Enhanced Maintainability: Separating logic into distinct services (e.g.,
`BorrowingService`) simplifies the codebase and isolates responsibilities, making
the code easier to understand and maintain.
3. Greater Extensibility: Using the Factory and Strategy patterns allows you to
introduce new media types or behaviors without modifying existing code, following
the Open-Closed Principle.

Question 3:
CODE:
class BankAccount {
// Fields
private String accountNumber;
private double balance;

// Constructor
public BankAccount(String accountNumber, double initialBalance) {
this.accountNumber = accountNumber;
this.balance = initialBalance;
}

// Method to deposit an amount to the balance


public void deposit(double amount) {
if (amount > 0) {
balance += amount;
System.out.println("Deposited: $" + amount);
} else {
System.out.println("Invalid deposit amount.");
}
}

// Method to withdraw an amount from the balance

Page | 6
public void withdraw(double amount) {
if (amount > 0 && amount <= balance) {
balance -= amount;
System.out.println("Withdrew: $" + amount);
} else {
System.out.println("Insufficient funds or invalid withdrawal amount.");
}
}

// Method to get the current balance


public double getBalance() {
return balance;
}
}

public class BankAccountTest {


public static void main(String[] args) {
// Create a BankAccount object with initial balance of $1000 and account
number "123456789"
BankAccount account = new BankAccount("123456789", 1000);

// Deposit $500
account.deposit(500);

// Withdraw $200
account.withdraw(200);

// Print the final balance


System.out.println("Final Balance: $" + account.getBalance());
}

Page | 7
}

Question 4:
CODE:
class Rectangle {
// Fields
private double length;
private double width;

// Constructor
public Rectangle(double length, double width) {
this.length = length;
this.width = width;
}

// Method to calculate the area of the rectangle


public double calculateArea() {
return length * width;
}

// Method to calculate the perimeter of the rectangle


public double calculatePerimeter() {
return 2 * (length + width);
}
}

public class RectangleTest {


public static void main(String[] args) {
// Create a Rectangle object with length of 5 units and width of 3 units

Page | 8
Rectangle rectangle = new Rectangle(5, 3);

// Calculate and print the area


System.out.println("Area of the rectangle: " + rectangle.calculateArea());

// Calculate and print the perimeter


System.out.println("Perimeter of the rectangle: " +
rectangle.calculatePerimeter());
}
}

Question 5:
CODE:
import java.util.ArrayList;

class Student {
// Fields
private String name;
private String studentID;
private ArrayList<Double> grades;

// Constructor
public Student(String name, String studentID) {
this.name = name;
this.studentID = studentID;
this.grades = new ArrayList<>();
}

// Method to add a grade to the grades list


public void addGrade(double grade) {

Page | 9
grades.add(grade);
}

// Method to calculate the average grade


public double calculateAverage() {
if (grades.isEmpty()) {
return 0.0;
}

double sum = 0.0;


for (double grade : grades) {
sum += grade;
}
return sum / grades.size();
}

// Method to get the list of grades


public ArrayList<Double> getGrades() {
return grades;
}
}

public class StudentTest {


public static void main(String[] args) {
// Create a Student object for "Alice" with ID "S1001"
Student alice = new Student("Alice", "S1001");

// Add grades to Alice's grades list


alice.addGrade(85.5);
alice.addGrade(90.0);

Page | 10
alice.addGrade(78.0);

// Calculate and print Alice's average grade


System.out.println("Grades: " + alice.getGrades());
System.out.println("Average Grade: " + alice.calculateAverage());
}
}

Question 6:
CODE:
class Car {
// Fields
private String make;
private String model;
private double fuelLevel;
private double fuelConsumption; // in liters per kilometer

// Constructor
public Car(String make, String model, double fuelLevel, double fuelConsumption)
{
this.make = make;
this.model = model;
this.fuelLevel = fuelLevel;
this.fuelConsumption = fuelConsumption;
}

// Method to simulate driving the car for a given distance


public void drive(double distance) {
double fuelNeeded = distance * fuelConsumption;

Page | 11
if (fuelNeeded <= fuelLevel) {
fuelLevel -= fuelNeeded;
System.out.println("Drove " + distance + " km. Fuel used: " + fuelNeeded +
" liters.");
} else {
System.out.println("Not enough fuel to drive " + distance + " km.");
}
}

// Method to refuel the car by a specified amount


public void refuel(double amount) {
if (amount > 0) {
fuelLevel += amount;
System.out.println("Refueled " + amount + " liters.");
} else {
System.out.println("Invalid refuel amount.");
}
}

// Method to get the current fuel level


public double getFuelLevel() {
return fuelLevel;
}
}

public class CarTest {


public static void main(String[] args) {
// Create a Car object representing a "Toyota Corolla" with a fuel level of 50
liters
// and a fuel consumption rate of 0.05 liters/km

Page | 12
Car car = new Car("Toyota", "Corolla", 50, 0.05);

// Drive the car for 200 kilometers


car.drive(200);

// Refuel the car with 20 liters


car.refuel(20);

// Print the final fuel level


System.out.println("Final Fuel Level: " + car.getFuelLevel() + " liters.");
}
}

Question 7:
CODE:
class LibraryBook {
// Fields
private String title;
private String author;
private boolean isCheckedOut;

// Constructor
public LibraryBook(String title, String author) {
this.title = title;
this.author = author;
this.isCheckedOut = false; // Book is available by default
}

// Method to check out the book

Page | 13
public void checkOut() {
isCheckedOut = true;
System.out.println(title + " has been checked out.");
}

// Method to return the book


public void returnBook() {
isCheckedOut = false;
System.out.println(title + " has been returned.");
}

// Method to get the status of the book


public String getStatus() {
return isCheckedOut ? "Checked out" : "Available";
}
}

public class LibraryBookTest {


public static void main(String[] args) {
// Create a LibraryBook object for "1984" by "George Orwell"
LibraryBook book = new LibraryBook("1984", "George Orwell");

// Check out the book


book.checkOut();

// Print the book's status


System.out.println("Status: " + book.getStatus());

// Return the book


book.returnBook();

Page | 14
// Print the book's status again
System.out.println("Status: " + book.getStatus());
}
}

Question 8:
CODE:
class Person {
// Fields
private String name;
private int age;
private String address;

// Default constructor
public Person() {
this.name = "Unknown";
this.age = 0;
this.address = "Not specified";
}

// Overloaded constructor (name and age)


public Person(String name, int age) {
this.name = name;
this.age = age;
this.address = "Not specified";
}

// Overloaded constructor (name, age, and address)

Page | 15
public Person(String name, int age, String address) {
this.name = name;
this.age = age;
this.address = address;
}

// Method to display the person's information


public void displayInfo() {
System.out.println("Name: " + name);
System.out.println("Age: " + age);
System.out.println("Address: " + address);
}
}

public class Main {


public static void main(String[] args) {
// Create an instance using the default constructor
Person person1 = new Person();
person1.displayInfo();

System.out.println(); // For separation

// Create an instance using the constructor that accepts name and age
Person person2 = new Person("Alice", 30);
person2.displayInfo();

System.out.println(); // For separation

// Create an instance using the constructor that accepts name, age, and
address

Page | 16
Person person3 = new Person("Bob", 25, "123 Main St");
person3.displayInfo();
}
}

Question 9:
CODE:
class Book {
// Fields
private String title;
private String author;
private int yearPublished;
private String ISBN;

// Constructor that accepts only title and author


public Book(String title, String author) {
this.title = title;
this.author = author;
this.yearPublished = -1; // Default value for yearPublished
this.ISBN = "Unknown"; // Default value for ISBN
}

// Overloaded constructor that accepts title, author, and yearPublished


public Book(String title, String author, int yearPublished) {
this.title = title;
this.author = author;
this.yearPublished = yearPublished;
this.ISBN = "Unknown"; // Default value for ISBN
}

Page | 17
// Overloaded constructor that accepts all fields
public Book(String title, String author, int yearPublished, String ISBN) {
this.title = title;
this.author = author;
this.yearPublished = yearPublished;
this.ISBN = ISBN;
}

// Method to display the book's details


public void displayDetails() {
System.out.println("Title: " + title);
System.out.println("Author: " + author);
System.out.println("Year Published: " + (yearPublished == -1 ? "Not
Available" : yearPublished));
System.out.println("ISBN: " + ISBN);
}
}

public class Main {


public static void main(String[] args) {
// Create an instance using the constructor that accepts only title and author
Book book1 = new Book("The Great Gatsby", "F. Scott Fitzgerald");
book1.displayDetails();

System.out.println(); // For separation

// Create an instance using the constructor that accepts title, author, and
yearPublished
Book book2 = new Book("1984", "George Orwell", 1949);

Page | 18
book2.displayDetails();

System.out.println(); // For separation

// Create an instance using the constructor that accepts all fields


Book book3 = new Book("To Kill a Mockingbird", "Harper Lee", 1960, "978-0-
06-112008-4");
book3.displayDetails();
}
}

Question 10:
CODE:
class Product {
// Fields
private String productID;
private String name;
private double price;

// Constructor
public Product(String productID, String name, double price) {
this.productID = productID;
this.name = name;
this.price = price;
}

// Method to display the product's details


public void displayProductInfo() {
System.out.println("Product ID: " + productID);
System.out.println("Name: " + name);

Page | 19
System.out.println("Price: $" + price);
}

// Setter for price to modify it


public void setPrice(double price) {
this.price = price;
}
}

public class Main {


public static void main(String[] args) {
// Creating Product objects
Product productA = new Product("P001", "Laptop", 1000);
Product productB = new Product("P002", "Smartphone", 500);

// Assigning productC the reference of productA


Product productC = productA;

// Printing memory addresses (references)


System.out.println("Reference of productA: " +
System.identityHashCode(productA));
System.out.println("Reference of productB: " +
System.identityHashCode(productB));
System.out.println("Reference of productC: " +
System.identityHashCode(productC));

// Modifying the price of productC


productC.setPrice(900);

// Display details of productA and productC


System.out.println("\nDetails of productA:");

Page | 20
productA.displayProductInfo();

System.out.println("\nDetails of productC:");
productC.displayProductInfo();
}
}

Question 11:
CODE:
class DataProcessor {
// Fields
private int processorID;
private int[] data;

// Constructor
public DataProcessor(int processorID, int[] data) {
this.processorID = processorID;
this.data = data;
System.out.println("DataProcessor with ID " + processorID + " created.");
}

// Method to perform a simple computation on data array


public void processData() {
int sum = 0;
for (int num : data) {
sum += num;
}
System.out.println("Data processed by Processor " + processorID + ": Sum = "
+ sum);
}

Page | 21
// Override finalize method to display message on garbage collection
@Override
protected void finalize() {
System.out.println("DataProcessor with ID " + processorID + " is being garbage
collected.");
}
}

public class Main {


public static void main(String[] args) {
// Loop to create DataProcessor objects
for (int i = 1; i <= 5; i++) {
DataProcessor processor = new DataProcessor(i, new int[]{1, 2, 3, 4, 5});
processor.processData();
// Setting reference to null to make it eligible for garbage collection
processor = null;
}

// Suggesting garbage collection


System.gc();
}
}

Question 12:
Step 1: First of all, define the `BankAccount` Class with
Encapsulation and Access Control

Page | 22
1. Encapsulation with Private Fields:
- Make the fields `accountNumber`, `balance`, and `accountHolderName` private.
This prevents direct access to these fields from outside the class, enforcing
encapsulation.

2. Public Getter Methods:


- Provide public getter methods (`getBalance()`, `getAccountNumber()`, and
`getAccountHolderName()`) to allow controlled access to the account details.
- No setter methods are provided, ensuring that once the account is created,
`accountNumber` and `accountHolderName` cannot be modified. The `balance`
can only be modified using `deposit()` and `withdraw()`.

3. Control Access within Package:


- Since the account number might need to be accessed by other classes within the
`banking` package (but not from outside), we can make `getAccountNumber()`
package-private by omitting the `public` modifier.

Step 2: Implement the `BankAccount` Class

CODE:
package banking;

public class BankAccount {


// Private fields
private String accountNumber;
private double balance;
private String accountHolderName;

// Constructor
public BankAccount(String accountNumber, double initialBalance, String
accountHolderName) {
this.accountNumber = accountNumber;
this.balance = initialBalance;

Page | 23
this.accountHolderName = accountHolderName;
}

// Getter for balance


public double getBalance() {
return balance;
}

// Getter for account holder's name


public String getAccountHolderName() {
return accountHolderName;
}

// Package-private getter for account number


String getAccountNumber() {
return accountNumber;
}

// Deposit method
public void deposit(double amount) {
if (amount > 0) {
balance += amount;
System.out.println("Deposited: " + amount);
} else {
System.out.println("Invalid deposit amount.");
}
}

// Withdraw method
public void withdraw(double amount) {

Page | 24
if (amount > 0 && amount <= balance) {
balance -= amount;
System.out.println("Withdrew: " + amount);
} else {
System.out.println("Insufficient funds or invalid amount.");
}
}
}

Step 3: Accessing the `BankAccount` Class within the Same Package

CODE:
package banking;

public class BankEmployee {


public void printAccountDetails(BankAccount account) {
// Accessing package-private method getAccountNumber() - allowed
System.out.println("Account Number: " + account.getAccountNumber());

// Accessing public method getBalance()


System.out.println("Balance: " + account.getBalance());

// Accessing public method getAccountHolderName()


System.out.println("Account Holder: " + account.getAccountHolderName());
}
}

Step 4: Attempting to Access `BankAccount` from Outside the


Package

CODE:

Page | 25
package external;

import banking.BankAccount;

public class ExternalSystem {


public void accessAccount(BankAccount account) {
// This line will cause a compilation error as getAccountNumber() is package-
private
// System.out.println("Account Number: " + account.getAccountNumber());

// Accessing the public method getBalance() is allowed


System.out.println("Balance: " + account.getBalance());
}
}

The `ExternalSystem` class cannot access `getAccountNumber()` because it’s


package-private. Only `getBalance()` and `getAccountHolderName()`, which are
public, can be accessed.

Question 13:
Code Implementation
`Character` Class:
CODE:
// Character.java in package rpg
package rpg;

public abstract class Character {


private String name;
protected int health;
protected int level;

Page | 26
// Constructor
public Character(String name, int health, int level) {
this.name = name;
this.health = health;
this.level = level;
}

// Abstract attack method


public abstract void attack();

// Display character status


public void displayStatus() {
System.out.println("Name: " + name);
System.out.println("Health: " + health);
System.out.println("Level: " + level);
}
}

`Warrior` Class:
CODE:
// Warrior.java in package rpg
package rpg;

public class Warrior extends Character {


// Constructor
public Warrior(String name, int health, int level) {
super(name, health, level);
}

Page | 27
// Implement abstract attack method
public void attack() {
System.out.println("Warrior attacks with a sword!");
}

// Take damage method


public void takeDamage(int damage) {
health -= damage; // Accessing protected health field
if (health < 0) health = 0;
System.out.println("Warrior took " + damage + " damage. Remaining health: "
+ health);
}
}

`Mage` Class:
CODE:
// Mage.java in package rpg
package rpg;

public class Mage extends Character {


// Constructor
public Mage(String name, int health, int level) {
super(name, health, level);
}

// Implement abstract attack method


public void attack() {
System.out.println("Mage casts a spell!");
}

Page | 28
// Cast spell method
public void castSpell() {
level += 1; // Accessing protected level field
System.out.println("Mage casts a spell and increases level to " + level);
}
}

Main Class to Test


CODE:
// Main.java in package rpg
package rpg;

public class Main {


public static void main(String[] args) {
// Create a Warrior
Warrior warrior = new Warrior("Thor", 100, 1);
warrior.displayStatus();
warrior.attack();
warrior.takeDamage(20);
warrior.displayStatus();

// Create a Mage
Mage mage = new Mage("Merlin", 80, 1);
mage.displayStatus();
mage.attack();
mage.castSpell();
mage.displayStatus();
}

Page | 29
}

Question 14:
Code Implementation
// File: mathlib/basic/Calculator.java
package mathlib.basic;

public class Calculator {


// Adds two numbers
public double add(double a, double b) {
return a + b;
}

// Subtracts one number from another


public double subtract(double a, double b) {
return a - b;
}

// Multiplies two numbers


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

// Divides one number by another


public double divide(double a, double b) {
if (b == 0) {
throw new ArithmeticException("Division by zero is not allowed");
}
return a / b;

Page | 30
}
}

// File: mathlib/advanced/Statistics.java
package mathlib.advanced;

import java.util.Arrays;
// Public Statistics Class…..
public class Statistics {
// Calculates the mean of a data set
public double mean(double[] data) {
double sum = 0;
for (double num : data) {
sum += num;
}
return sum / data.length;
}

// Calculates the median of a data set


public double median(double[] data) {
Arrays.sort(data);
int middle = data.length / 2;
if (data.length % 2 == 0) {
return (data[middle - 1] + data[middle]) / 2.0;
} else {
return data[middle];
}
}

// Calculates the standard deviation of a data set

Page | 31
public double standardDeviation(double[] data) {
double mean = mean(data);
double sum = 0;
for (double num : data) {
sum += (num - mean) * (num - mean);
}
return Helper.sqrt(sum / data.length); // Using package-private Helper method
}
}

// File: mathlib/advanced/Helper.java
package mathlib.advanced;

// Package-private Helper class


class Helper {
// Package-private square root method
static double sqrt(double value) {
return Math.sqrt(value);
}
}

// Main Class for Testing (Outside `mathlib` Package)


// File: Main.java
import mathlib.basic.Calculator;
import mathlib.advanced.Statistics;

public class Main {


public static void main(String[] args) {
// Access Calculator from mathlib.basic
Calculator calc = new Calculator();

Page | 32
System.out.println("Addition: " + calc.add(5, 3));
System.out.println("Division: " + calc.divide(10, 2));

// Access Statistics from mathlib.advanced


Statistics stats = new Statistics();
double[] data = {10, 20, 30, 40, 50};
System.out.println("Mean: " + stats.mean(data));
System.out.println("Median: " + stats.median(data));
System.out.println("Standard Deviation: " + stats.standardDeviation(data));

// Trying to access Helper from outside mathlib.advanced will fail


// Helper helper = new Helper(); // Error: Helper has package-private access
}
}

Question 15:
COMPLEX NUMBER CLASS DEVELOPMENT
CODE:

package midlab;

class ComplexNumber {
double real;
double imaginary;

public ComplexNumber(double real, double imaginary) {


this.real = real;
this.imaginary = imaginary;
}

public ComplexNumber add(ComplexNumber other) {


double newReal = this.real + other.real;
double newImaginary = this.imaginary + other.imaginary;
return new ComplexNumber(newReal, newImaginary);

Page | 33
}

public ComplexNumber subtract(ComplexNumber other) {


double newReal = this.real - other.real;
double newImaginary = this.imaginary - other.imaginary;
return new ComplexNumber(newReal, newImaginary);
}

public void display() {


System.out.println(this.real + " + " + this.imaginary + "i");
}
}

public class ComplexNumberTest {


public static void main(String[] args) {
ComplexNumber num1 = new ComplexNumber(3.0, 2.0);
ComplexNumber num2 = new ComplexNumber(1.5, 4.5);

ComplexNumber sum = num1.add(num2);


ComplexNumber difference = num1.subtract(num2);

System.out.print("num1: ");
num1.display();

System.out.print("num2: ");
num2.display();

System.out.print("sum: ");
sum.display();

System.out.print("difference: ");
difference.display();
}
}

Question 16:
STUDENT CLASS DEVELOPMENT
CODE:
import java.util.ArrayList;

class Student {

Page | 34
String name;
String studentID;
ArrayList<Double> grades;

public Student(String name, String studentID) {


this.name = name;
this.studentID = studentID;
this.grades = new ArrayList<>();
}

public Student(Student other) {


this.name = other.name;
this.studentID = other.studentID;
this.grades = new ArrayList<>(other.grades);
}

public void addGrade(double grade) {


grades.add(grade);
}

public ArrayList<Double> getGrades() {


return grades;
}

public void displayInfo() {


System.out.println("Name: " + name);
System.out.println("Student ID: " + studentID);
System.out.println("Grades: " + grades);
}
}

public class Main {


public static void main(String[] args) {
Student student1 = new Student("Alice", "S12345");
student1.addGrade(85.0);
student1.addGrade(90.0);

Student student2 = new Student(student1);


student2.addGrade(95.0);

System.out.print("student1 grades: ");


student1.displayInfo();
System.out.print("student2 grades: ");
student2.displayInfo();
}
}

Page | 35
Question 17:
COUNTER CLASS DEVELOPMENT:
CODE

class Counter {
private int id;
private static int count = 0;

public Counter() {
count++;
this.id = count;
}

public static int getCount() {


return count;
}

public int getId() {


return id;
}
}

public class Main {


public static void main(String[] args) {
Counter c1 = new Counter();
Counter c2 = new Counter();
Counter c3 = new Counter();

System.out.println("c1 id: " + c1.getId());


System.out.println("c2 id: " + c2.getId());
System.out.println("c3 id: " + c3.getId());
System.out.println("Total Counter objects created: " + Counter.getCount());
}
}

Question 18:
CODE:
class MathUtility {
public static int factorial(int n) {
if (n < 0) throw new IllegalArgumentException("n must be non-negative.");

Page | 36
int result = 1;
for (int i = 2; i <= n; i++) {
result *= i;
}
return result;
}

public static boolean isPrime(int n) {


if (n <= 1) return false;
for (int i = 2; i <= Math.sqrt(n); i++) {
if (n % i == 0) return false;
}
return true;
}

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


while (b != 0) {
int temp = b;
b = a % b;
a = temp;
}
return a;
}
}

public class Main {


public static void main(String[] args) {
int fact = MathUtility.factorial(5);
boolean isPrime13 = MathUtility.isPrime(13);
boolean isPrime15 = MathUtility.isPrime(15);

Page | 37
int gcdValue = MathUtility.gcd(48, 18);

System.out.println("Factorial of 5: " + fact);


System.out.println("Is 13 prime? " + isPrime13);
System.out.println("Is 15 prime? " + isPrime15);
System.out.println("GCD of 48 and 18: " + gcdValue);
}
}

Question 19:
CODE:
public class TestScores {
public static void main(String[] args) {
int[] scores = {85, 92, 76, 81, 95};
int sum = 0;
int highest = scores[0];
int lowest = scores[0];

for (int score : scores) {


sum += score;
if (score > highest) {
highest = score;
}
if (score < lowest) {
lowest = score;
}
}

double average = sum / (double) scores.length;

Page | 38
System.out.println("Average Score: " + average);
System.out.println("Highest Score: " + highest);
System.out.println("Lowest Score: " + lowest);
}
}

Question 20:
CODE:
public class TheaterSeating {
public static void main(String[] args) {
int[][] seats = new int[3][4]; // 0 for available, 1 for booked

// Mark certain seats as booked


seats[0][1] = 1; // row 1, column 2
seats[1][2] = 1; // row 2, column 3
seats[2][0] = 1; // row 3, column 1

// Print the seating chart


System.out.println("Seating Chart:");
for (int i = 0; i < seats.length; i++) {
for (int j = 0; j < seats[i].length; j++) {
if (seats[i][j] == 0) {
System.out.print("A "); // Available
} else {
System.out.print("B "); // Booked
}
}
System.out.println(); // New line for each row
}

Page | 39
}
}

Question 21:
CODE:
public class AverageCalculator {
public static void main(String[] args) {
double[] numbers = {10.5, 23.8, 5.7, 17.6, 9.0};
double average = calculateAverage(numbers);
System.out.println("Average: " + average);
}

public static double calculateAverage(double[] numbers) {


double sum = 0;
for (double number : numbers) {
sum += number;
}
return sum / numbers.length;
}
}

Question 22:
CODE:
import java.util.Arrays;

public class ArrayOperations {


public static void main(String[] args) {
int[] numbers = {42, 23, 16, 15, 8, 4};

Page | 40
// Sort the array
Arrays.sort(numbers);
System.out.println("Sorted array: " + Arrays.toString(numbers));

// Search for the value 15


int index = Arrays.binarySearch(numbers, 15);
System.out.println("Index of 15: " + index);

// Fill the array with 0


Arrays.fill(numbers, 0);
System.out.println("Array after filling with 0: " + Arrays.toString(numbers));
}
}

Question 23:
CODE:
import java.util.Arrays;

public class ArrayCopyExample {


public static void main(String[] args) {
int[] originalArray = {1, 2, 3, 4, 5};

// Create a copy using the clone() method


int[] clonedArray = originalArray.clone();

// Create a copy using Arrays.copyOf()


int[] copiedArray = Arrays.copyOf(originalArray, originalArray.length);

Page | 41
// Modify the first element of each copied array
clonedArray[0] = 99;
copiedArray[0] = 99;

// Print all arrays


System.out.println("Original array: " + Arrays.toString(originalArray));
System.out.println("Cloned array: " + Arrays.toString(clonedArray));
System.out.println("Copied array: " + Arrays.toString(copiedArray));
}
}

Question 24:
CODE:
public class StringImmutabilityExample {
public static void main(String[] args) {
String original = "Hello";
String modified = original + " World";

// Print both strings


System.out.println("Original string: " + original);
System.out.println("Modified string: " + modified);
}
}

Question 25:
CODE:
public class Point {
private final double x;
private final double y;

Page | 42
public Point(double x, double y) {
this.x = x;
this.y = y;
}

public double getX() {


return x;
}

public double getY() {


return y;
}

public Point translate(double dx, double dy) {


return new Point(this.x + dx, this.y + dy);
}
}

public class Main {


public static void main(String[] args) {
Point p1 = new Point(2.0, 3.0);
Point p2 = p1.translate(1.0, -1.0);

// Print coordinates of both points


System.out.println("Point p1: (" + p1.getX() + ", " + p1.getY() + ")");
System.out.println("Point p2: (" + p2.getX() + ", " + p2.getY() + ")");
}
}

Page | 43
QUESTION 26:
CODE:
// Mutable counter class
class CounterMutable {
private int count;

public void increment() {


count++;
}

public int getCount() {


return count;
}
}

// Immutable Counter class


class CounterImmutable {
private final int count;

public CounterImmutable(int count) {


this.count = count;
}

public CounterImmutable increment() {


return new CounterImmutable(this.count + 1);
}

public int getCount() {

Page | 44
return count;
}
}

// Main class to demonstrate both Counter implementations


public class Main {
public static void main(String[] args) {
// Demonstrating mutable Counter
CounterMutable mutableCounter = new CounterMutable();
mutableCounter.increment();
System.out.println("Mutable Counter count: " + mutableCounter.getCount()); //
Outputs: 1
mutableCounter.increment();
System.out.println("Mutable Counter count after another increment: " +
mutableCounter.getCount()); // Outputs: 2

// Demonstrating immutable Counter


CounterImmutable immutableCounter = new CounterImmutable(0);
System.out.println("Immutable Counter initial count: " +
immutableCounter.getCount()); // Outputs: 0
CounterImmutable newCounter = immutableCounter.increment();
System.out.println("Immutable Counter count after increment: " +
newCounter.getCount()); // Outputs: 1
System.out.println("Original Immutable Counter still count: " +
immutableCounter.getCount()); // Outputs: 0
}
}

Question 27:
CODE:
public class Main {

Page | 45
public static void main(String[] args) {
String s1 = "Java";
String s2 = "Java";
String s3 = new String("Java");

// Compare using == operator


System.out.println("s1 == s2: " + (s1 == s2)); // true, both point to the same
object in the String Pool
System.out.println("s1 == s3: " + (s1 == s3)); // false, s3 is a different object
in heap memory

// Compare using equals() method


System.out.println("s1.equals(s2): " + s1.equals(s2)); // true, content is the
same
System.out.println("s1.equals(s3): " + s1.equals(s3)); // true, content is the
same
}
}

Question 28:
CODE:
import java.util.Date;

public final class Employee {


private final String name;
private final Date dateOfJoining;

public Employee(String name, Date dateOfJoining) {


this.name = name;
this.dateOfJoining = new Date(dateOfJoining.getTime()); // Creating a new Date
object to ensure immutability

Page | 46
}

public String getName() {


return name;
}

public Date getDateOfJoining() {


return new Date(dateOfJoining.getTime()); // Returning a new Date object
}
}

public class Main {


public static void main(String[] args) {
Employee emp = new Employee("John Doe", new Date());

// Attempting to modify the date of joining


Date joiningDate = emp.getDateOfJoining();
joiningDate.setTime(joiningDate.getTime() + 100000); // This won't affect
emp's dateOfJoining

// Show that the internal state remains unchanged


System.out.println("Employee Name: " + emp.getName());
System.out.println("Date of Joining: " + emp.getDateOfJoining());
}
}

Question 29:
BENEFITS OF USING IMMUTABLE CLASSES
Thread Safety: Immutable classes cannot change, making them safe to use in
multi-threaded programs without synchronization issues.

Page | 47
Easier Debugging: Their unchanging nature simplifies understanding and tracking
down problems in the code.
Better Performance with Reuse: They can be reused safely, saving memory and
improving performance by avoiding unnecessary object creation.
Potential Drawbacks of Using Immutable Classes
More Memory Use: Creating new instances for every change can consume more
memory compared to modifying existing objects.
Slower Updates: The need to create new objects for updates can lead to slower
performance in data-intensive applications.
When to Use Immutable Classes
Safe Data Sharing: Use them when sharing data between parts of a program to
prevent accidental changes.
Simple Data Transfer: They are ideal for transferring data where you want to
ensure the original data remains unchanged.
When Not to Use Immutable Classes
Frequent Changes: If your application requires frequent data updates, mutable
objects might be more efficient.
Complex Structures: In cases with complex data structures that need constant
modification, mutable objects can be easier to manage.

Page | 48

You might also like