NAME.
RISHAV SHARMA
ROLL NO. 20252651042
DATE. 09/APR/2026
JAVA MODULE-1 & MODULE 2
ASSIGNMENT.
Question. 1 Design a BankAccount class that demonstrates all three access
modifiers (private, protected, public). Show why making the
balance private is essential by writing asubclass
SavingsAccount that tries to access it directly ; observe the
compile error and then fix it properly. What does this reveal
about encapsulation?
Code. import [Link].*;
// main class where execution starts
public class Main {
// class representing a bank account
static class BankAccount {
// private variable so it cannot be accessed directly
outside this class
private double balance;
// protected variable accessible inside subclass
protected String accountType;
// public variable accessible everywhere
public String owner;
// constructor to initialize account details
public BankAccount(String owner, double balance,
String accountType) {
[Link] = owner;
[Link] = balance;
[Link] = accountType;
}
// getter method to safely access balance
public double getBalance() {
return balance;
}
// method to deposit money into account
public void deposit(double amount) {
balance += amount;
}
}
// subclass of BankAccount
static class SavingsAccount extends BankAccount {
// constructor calls parent constructor
public SavingsAccount(String owner, double balance) {
super(owner, balance, "Savings");
}
public void showBalance() {
// this line will give compile-time error because
balance is private in parent class
// [Link](balance);
// correct way to access balance using getter method
[Link]("Balance: " + getBalance());
}
}
public static void main(String[] args) {
// creating object of subclass
SavingsAccount acc = new SavingsAccount("Rishav",
1000);
// calling method to display balance
[Link]();
}
}
Output.
The balance is declared as private in the BankAccount class,
so it cannot be accessed directly by the subclass
SavingsAccount. When we try to access it directly, it gives a
compile-time error. This forces us to use a getter method to
access the value safely.
This shows encapsulation, where data is hidden and can only
be accessed through controlled methods. It protects the data
from unintended changes and makes the program more secure
and organized.
Question.2 Create a Student class with four constructors: a no-arg
constructor setting defaults, a parameterized constructor, an
overloaded constructor accepting only name (with a default
GPA), and a copy constructor. In main, demonstrate that
modifying a copy does not affect the original.
Code. import [Link].*;
// main class where execution starts
public class Main {
// class representing a student
static class Student {
String name;
double gpa;
// no-argument constructor setting default values
Student() {
name = "Unknown";
gpa = 0.0;
}
// parameterized constructor to initialize name and gpa
Student(String name, double gpa) {
[Link] = name;
[Link] = gpa;
}
// overloaded constructor that takes only name and
assigns default gpa
Student(String name) {
[Link] = name;
[Link] = 5.0;
}
// copy constructor that creates a new object from another
object
Student(Student s) {
[Link] = [Link];
[Link] = [Link];
}
// method to display student details
void display() {
[Link]("Name: " + name + ", GPA: " +
gpa);
}
}
public static void main(String[] args) {
// creating original student object using parameterized
constructor
Student s1 = new Student("Rishav", 9.5);
// creating copy of s1 using copy constructor
Student s2 = new Student(s1);
// modifying copied object
[Link] = "Changed";
[Link] = 7.0;
// displaying both objects
[Link]("Original Student:");
[Link]();
[Link]("Copied Student:");
[Link]();
}
}
Output.
Question.3 Design a Matrix class that is immutable where all fields are
private final and set only in the constructor. Provide a method
add(Matrix other) that returns a new Matrix instead of
modifying this. Compare this design to a mutable version.
When and why does immutability make a class safer to use,
especially in the context of the copy constructor discussion?
Code. import [Link].*;
// main class where execution starts
public class Main {
// immutable Matrix class
static class Matrix {
// private final data so it cannot be changed after
initialization
private final int[][] data;
// constructor initializes matrix and makes a deep copy
public Matrix(int[][] input) {
int rows = [Link];
int cols = input[0].length;
data = new int[rows][cols];
// copying values to prevent external modification
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
data[i][j] = input[i][j];
}
}
}
// method to add two matrices and return a new matrix
public Matrix add(Matrix other) {
int rows = [Link];
int cols = data[0].length;
int[][] result = new int[rows][cols];
// performing element-wise addition
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
result[i][j] = [Link][i][j] + [Link][i][j];
}
}
// returning new object instead of modifying existing
one
return new Matrix(result);
}
// method to display matrix
public void display() {
for (int[] row : data) {
for (int val : row) {
[Link](val + " ");
}
[Link]();
}
}
}
public static void main(String[] args) {
int[][] a = {
{1, 2},
{3, 4}
};
int[][] b = {
{5, 6},
{7, 8}
};
// creating two matrix objects
Matrix m1 = new Matrix(a);
Matrix m2 = new Matrix(b);
// adding matrices
Matrix result = [Link](m2);
// displaying result
[Link]("Result Matrix:");
[Link]();
}
}
Output.
The Matrix class is designed to be immutable by declaring its
data field as private and final. This ensures that once a Matrix
object is created, its internal data cannot be modified.
The constructor makes a deep copy of the input array so that
changes outside the class do not affect the internal state. The
add method does not modify the current object. Instead, it
creates and returns a new Matrix object containing the result.
Question:4 Implement a Temperature class where the internal state is
stored in Celsius (private
double celsius). Provide getters/setters that validate range
(absolute zero check). Then
create a static utility method convert(double f) that converts
Fahrenheit to Celsius.
Explain: why should convert be static while getTemperature
should not be?
Code: import [Link].*;
// main class where execution starts
public class Main {
// class representing temperature
static class Temperature {
// private variable storing temperature in celsius
private double celsius;
// constructor initializes value using setter for validation
public Temperature(double celsius) {
setCelsius(celsius);
}
// getter method to return temperature
public double getCelsius() {
return celsius;
}
// setter method with validation
public void setCelsius(double celsius) {
// temperature cannot go below absolute zero
if (celsius < -273.15) {
throw new IllegalArgumentException("temperature
below absolute zero");
}
[Link] = celsius;
}
// static method to convert fahrenheit to celsius
public static double convert(double f) {
return (f - 32) * 5 / 9;
}
}
public static void main(String[] args) {
// creating temperature object
Temperature t = new Temperature(25);
// displaying temperature
[Link]("Celsius: " + [Link]());
// converting fahrenheit to celsius using static method
double result = [Link](98.6);
[Link]("Converted: " + result);
}
}
Output:
The Temperature class stores the temperature internally in
Celsius using a private variable. The setter method ensures
that the value does not go below absolute zero, which makes
the class safe and valid.
The convert method is declared static because it performs a
general conversion and does not depend on any specific
object’s data. It can be used without creating an object of the
class.
The getCelsius method is not static because it depends on the
instance variable celsius. It returns the value of a specific
object, so it must be called using an object.
Thus, static methods are used for general utility functions,
while non-static methods are used when working with object-
specific data.
MODULE 2
QUESTION 1 1. Write a method swap(int a, int b) that attempts to swap two
integers. Show that it [Link] write swapArray(int[] arr, int
i, int j) that succeeds. Explain the fundamentaldifference in
terms of Java's pass-by-value semantics. Then design a
Wrapper class
whose instances can be swapped, why does this work even
though Java is always pass-
by-value?
CODE import [Link].*;
// main class where execution starts
public class Main {
// method that tries to swap two integers
static void swap(int a, int b) {
// swapping values locally
int temp = a;
a = b;
b = temp;
// printing inside method
[Link]("inside swap: " + a + " " + b);
}
// method that swaps elements in an array
static void swapArray(int[] arr, int i, int j) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
// wrapper class to hold integer value
static class Wrapper {
int value;
Wrapper(int value) {
[Link] = value;
}
}
// method to swap values inside wrapper objects
static void swapWrapper(Wrapper a, Wrapper b) {
int temp = [Link];
[Link] = [Link];
[Link] = temp;
}
public static void main(String[] args) {
// testing swap with primitive values
int x = 10, y = 20;
swap(x, y);
// values remain unchanged outside
[Link]("after swap: " + x + " " + y);
// testing swap with array
int[] arr = {10, 20};
swapArray(arr, 0, 1);
// values get swapped successfully
[Link]("after swapArray: " + arr[0] + " " +
arr[1]);
// testing swap with wrapper objects
Wrapper w1 = new Wrapper(10);
Wrapper w2 = new Wrapper(20);
swapWrapper(w1, w2);
// values inside objects are swapped
[Link]("after swapWrapper: " + [Link] + "
" + [Link]);
}
}
OUTPUT
EXPLAINATIO In Java, all arguments are passed by value. When the swap(int
N a, int b) method is called, copies of the values are passed. Any
changes made inside the method affect only the copies, not
the original variables. Therefore, the swap fails.
In the swapArray method, the reference to the array is passed
by value, but it still points to the same memory location.
When elements of the array are modified, the changes are
reflected outside the method. Hence, swapping works.
In the Wrapper class, objects are also passed by value, but the
value passed is the reference to the object. Both parameters
refer to the same objects in memory. When we change the
internal state of the object (value field), the changes are
visible outside the method.
QUESTIO Create a MathUtils class with four overloaded versions of area():
N2 for a circle (radius),
rectangle (length, width), triangle (base, height), and square
(side). All return double.
Now add a fifth overload that takes a String shapeName and a
double[] of dimensions.
Does Java resolve this at compile time or runtime?
CODE import [Link].*;
// main class where execution starts
public class Main {
// utility class containing overloaded area methods
static class MathUtils {
// area of circle using radius
static double area(double radius) {
return [Link] * radius * radius;
}
// area of rectangle using length and width
static double area(double length, double width) {
return length * width;
}
// area of triangle using base and height
static double area(double base, double height, boolean
isTriangle) {
return 0.5 * base * height;
}
// area of square using side
static double area(int side) {
return side * side;
}
// general method using shape name and dimensions
static double area(String shapeName, double[] d) {
if ([Link]("circle")) {
return area(d[0]);
}
if ([Link]("rectangle")) {
return area(d[0], d[1]);
}
if ([Link]("triangle")) {
return 0.5 * d[0] * d[1];
}
if ([Link]("square")) {
return d[0] * d[0];
}
return 0;
}
}
public static void main(String[] args) {
// calling different overloaded methods
[Link]("Circle: " + [Link](5.0));
[Link]("Rectangle: " + [Link](4.0, 6.0));
[Link]("Triangle: " + [Link](4.0, 5.0,
true));
[Link]("Square: " + [Link](4));
// calling general method
double[] dims = {5};
[Link]("Circle (general): " +
[Link]("circle", dims));
}
}
OUTPUT
Explainati The MathUtils class demonstrates method overloading by
on defining multiple area methods with the same name but different
parameter lists. Each method calculates the area of a different
shape such as circle, rectangle, triangle, and square.
The fifth method takes a String and an array of dimensions.
Based on the shape name, it decides which calculation to
perform.
Java resolves method overloading at compile time. The compiler
determines which method to call based on the number and type of
arguments. However, inside the method that uses the shape name,
the decision is made at runtime using conditions.
QUESTIO Build an Employee array of 5 objects. Write a method
N3 findHighestPaid(Employee[]
employees) that returns the Employee reference with the maximum
salary. Modify the
returned object's name inside main, does the original array reflect
the change?
CODE import [Link].*;
// main class where execution starts
public class Main {
// class representing an employee
static class Employee {
String name;
double salary;
// constructor to initialize employee details
Employee(String name, double salary) {
[Link] = name;
[Link] = salary;
}
// method to display employee details
void display() {
[Link]("Name: " + name + ", Salary: " +
salary);
}
}
// method to find employee with highest salary
static Employee findHighestPaid(Employee[] employees) {
// assume first employee has highest salary initially
Employee max = employees[0];
// iterate through array to find highest salary
for (int i = 1; i < [Link]; i++) {
if (employees[i].salary > [Link]) {
max = employees[i];
}
}
// returning reference of employee with highest salary
return max;
}
public static void main(String[] args) {
// creating array of 5 employee objects
Employee[] employees = {
new Employee("A", 1000),
new Employee("B", 2500),
new Employee("C", 1800),
new Employee("D", 3000),
new Employee("E", 2000)
};
// finding highest paid employee
Employee highest = findHighestPaid(employees);
// modifying the name of returned object
[Link] = "Changed";
// displaying all employees
for (Employee e : employees) {
[Link]();
}
}
}
OUTPUT
explainatio The method findHighestPaid returns a reference to the employee
n object with the highest salary. When we modify the name of this
returned object in the main method, the change is reflected in the
original array.
This happens because objects in Java are accessed using references.
The method returns the same object reference, not a copy.
Therefore, any modification made through that reference affects the
original object stored in the array.
QUESTIO Model a Currency class. Implement toUSD() and fromUSD()
N4 methods to convert
between types, simulating data conversion. Discuss: what problems
arise when
converting floating-point currency values. Show a concrete
example where double
gives a wrong answer.
CODE import [Link].*;
import [Link];
// main class where execution starts
public class Main {
// class representing currency
static class Currency {
double amount;
// constructor to initialize amount
Currency(double amount) {
[Link] = amount;
}
// method to convert current currency to USD using exchange
rate
double toUSD(double rate) {
return amount * rate;
}
// method to convert from USD to another currency
double fromUSD(double rate) {
return amount / rate;
}
}
public static void main(String[] args) {
// creating currency object
Currency c = new Currency(100);
// converting to USD
double usd = [Link](0.012);
[Link]("Converted to USD: " + usd);
// converting back from USD
double local = [Link](0.012);
[Link]("Converted from USD: " + local);
// demonstrating floating point problem
double value = 0.1 + 0.2;
// expected 0.3 but gives incorrect result
[Link]("Using double: " + value);
// correct way using BigDecimal
BigDecimal a = new BigDecimal("0.1");
BigDecimal b = new BigDecimal("0.2");
[Link]("Using BigDecimal: " + [Link](b));
}
}
OUTPUT
explainatio The Currency class is used to simulate currency conversion using
n methods toUSD and fromUSD. These methods perform
multiplication and division based on exchange rates.
A major issue arises when using floating-point data types like
double for currency calculations. Floating-point numbers cannot
represent some decimal values exactly, which leads to precision
errors.
For example, when we add 0.1 and 0.2 using double, the result is
not exactly 0.3 but a slightly incorrect value. This happens due to
how numbers are stored in binary format.
To solve this problem, BigDecimal is used. It provides precise
decimal arithmetic and avoids rounding errors, making it suitable
for financial calculations.