Oops Assignment 2 Final
Oops Assignment 2 Final
OUTPUT:-
OUTPUT:-
Question 3:
// StackTest.java - Implementation
public class StackTest implements Stack {
private static final int DEFAULT_CAPACITY = 10;
private int[] array;
private int size;
public StackTest() {
array = new int[DEFAULT_CAPACITY];
size = 0;
}
@Override
public void push(int element) {
if (size == array.length) {
resizeArray();
}
array[size++] = element;
}
@Override
public int pop() {
if (isEmpty()) {
throw new IllegalStateException("Stack is empty");
}
return array[--size];
}
@Override
public boolean isEmpty() {
return size == 0;
}
private void resizeArray() {
int newCapacity = array.length * 2;
int[] newArray = new int[newCapacity];
System.arraycopy(array, 0, newArray, 0, size);
array = newArray;
}
public static void main(String[] args) {
StackTest stack = new StackTest();
System.out.println("Is stack empty? " + stack.isEmpty());
for (int i = 1; i <= 15; i++) {
stack.push(i);
System.out.println("Pushed: " + i);
}
System.out.println("Is stack empty? " + stack.isEmpty());
while (!stack.isEmpty()) {
System.out.println("Popped: " + stack.pop());
}
System.out.println("Is stack empty? " + stack.isEmpty());
}
}
Question 4:
// QueueTest.java - Implementation
public class QueueTest implements Queue {
private static final int DEFAULT_CAPACITY = 10;
private int[] array;
private int front;
private int rear;
public QueueTest() {
array = new int[DEFAULT_CAPACITY];
front = -1;
rear = -1;
}
@Override
public void enqueue(int element) {
if (isEmpty()) {
front = 0;
rear = 0;
} else if ((rear + 1) % array.length == front) {
resizeArray();
} else {
rear = (rear + 1) % array.length;
}
array[rear] = element;
}
@Override
public int dequeue() {
if (isEmpty()) {
throw new IllegalStateException("Queue is empty");
}
int removedElement = array[front];
if (front == rear) {
front = -1;
rear = -1;
} else {
front = (front + 1) % array.length;
}
return removedElement;
}
@Override
public boolean isEmpty() {
return front == -1 && rear == -1;
}
private void resizeArray() {
int newCapacity = array.length * 2;
int[] newArray = new int[newCapacity];
int size = 0;
for (int i = front; i <= rear; i++) {
newArray[size++] = array[i % array.length];
}
front = 0;
rear = size - 1;
array = newArray;
}
public static void main(String[] args) {
QueueTest queue = new QueueTest();
System.out.println("Is queue empty? " + queue.isEmpty());
for (int i = 1; i <= 15; i++) {
queue.enqueue(i);
System.out.println("Enqueued: " + i);
}
System.out.println("Is queue empty? " + queue.isEmpty());
while (!queue.isEmpty()) {
System.out.println("Dequeued: " + queue.dequeue());
}
System.out.println("Is queue empty? " + queue.isEmpty());
}
}
Question 5:
public class Submarine {
int depth;
int loc_x;
int loc_y;
public class ControlPanel {
// (a) Define setter and getter methods for location and depth
public void setLocation(int x, int y) {
loc_x = x;
loc_y = y;
}
public void setDepth(int d) {
depth = d;
}
public int getLocationX() {
return loc_x;
}
public int getLocationY() {
return loc_y;
}
public int getDepth() {
return depth;
}
}
public class FireControl {
int artilleryAmount;
// (b) Define a constructor to initialize artillery amount
public FireControl(int artilleryAmount) {
this.artilleryAmount = artilleryAmount;
}
// (c) This method will return true if artillery is present, otherwise return false
public boolean isArtilleryAvailable() {
return artilleryAmount > 0;
}
// (d) This method will search whether an enemy target is available at x, y
// If yes, it will set the status inactive
public void fireOnTarget(int x, int y) {
for (int i = 0; i < enemyTarget.target.length; i++) {
if (enemyTarget.target[i][0] == x && enemyTarget.target[i][1] == y && enemyTarget.target[i][2] == 1) {
enemyTarget.target[i][2] = 0; // Set status inactive
System.out.println("Target destroyed at (" + x + ", " + y + ")");
return;
}
}
System.out.println("No enemy target found at (" + x + ", " + y + ")");
}
}
public static class EnemyTarget {
static int target[][] = {
{10, 20, 1}, {15, 23, 1}, {22, 78, 1}, {8, 67, 1}, {56, 11, 1},
{34, 77, 1}, {33, 80, 1}, {32, 32, 1}, {56, 45, 1}, {54, 90, 1}
};
}
public static class Driver {
public static void main(String[] args) {
Submarine.ControlPanel controlPanel = new Submarine().new ControlPanel();
Submarine.FireControl fireControl = new Submarine().new FireControl(10);
// (e) Create an object of ControlPanel class and FireControl
// (f) Using FireControl object, call fireOnTarget until all enemy targets are destroyed.
for (int[] target : EnemyTarget.target) {
int x = target[0];
int y = target[1];
if (fireControl.isArtilleryAvailable()) {
fireControl.fireOnTarget(x, y);
// Assume random numbers between 0-100 are passed as parameters
int randomX = (int) (Math.random() * 100);
int randomY = (int) (Math.random() * 100);
controlPanel.setLocation(randomX, randomY);
controlPanel.setDepth((int) (Math.random() * 100));
} else {
System.out.println("No artillery available.");
System.out.println(“john doe");
System.out.println("123456789");
break;
}
}
}
}
}
OUTPUT:-
No artillery available
John Doe
123456789
Question 6:
import java.util.ArrayList;
import java.util.Iterator;
class Edge {
private String start;
private String end;
private int cost;
Edge(String s, String e, int w) {
start = s;
end = e;
cost = w;
}
public String getStart() {
return start;
}
public String getEnd() {
return end;
}
public int getCost() {
return cost;
}
}
class Graph {
private ArrayList<Edge> list_edges;
Graph(ArrayList<Edge> n) {
list_edges = n;
}
public void removeLoop() {
Iterator<Edge> iterator = list_edges.iterator();
while (iterator.hasNext()) {
Edge edge = iterator.next();
if (edge.getStart().equals(edge.getEnd())) {
iterator.remove();
}
}
}
public Edge findParallelEdge(Edge n) {
for (Edge edge : list_edges) {
if ((edge.getStart().equals(n.getStart()) && edge.getEnd().equals(n.getEnd()))
|| (edge.getStart().equals(n.getEnd()) && edge.getEnd().equals(n.getStart()))) {
return edge;
}
}
return null;
}
public void removeParallel() {
Iterator<Edge> iterator = list_edges.iterator();
while (iterator.hasNext()) {
Edge edge = iterator.next();
Edge parallelEdge = findParallelEdge(edge);
if (parallelEdge != null && edge.getCost() > parallelEdge.getCost()) {
iterator.remove();
}
}
}
public void print() {
for (Edge edge : list_edges) {
System.out.println("Start: " + edge.getStart() + ", End: " + edge.getEnd() + ", Cost: " + edge.getCost());
}
}
}
public class Main {
public static void main(String[] args) {
ArrayList<Edge> edges = new ArrayList<>();
edges.add(new Edge("A", "B", 5));
edges.add(new Edge("B", "C", 7));
edges.add(new Edge("C", "A", 10));
edges.add(new Edge("D", "A", 2));
Graph graph = new Graph(edges);
// Removing loops
graph.removeLoop();
System.out.println("Edges after removing loops:");
graph.print();
// Removing parallel edges
graph.removeParallel();
System.out.println("\nEdges after removing parallel edges:");
graph.print();
System.out.println(“John Doe”);
System.out.println(“123456789”);
}
}
OUTPUT:-
John Doe
123456789
Question 7:
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
public class FileReadWriteExample {
public static void main(String[] args) {
String inputFile = "input.txt";
String outputFile = "output.txt";
// Perform reading operation using FileReader
try (FileReader reader = new FileReader(inputFile)) {
int character;
while ((character = reader.read()) != -1) {
System.out.print((char) character); // Print content to console
}
} catch (IOException e) {
System.err.println("Error reading from file: " + e.getMessage());
}
// Perform writing operation using FileWriter
try (FileWriter writer = new FileWriter(outputFile)) {
String contentToWrite = "This is a sample content that will be written to the file.";
writer.write(contentToWrite);
System.out.println("\n\nContent written to the file successfully.");
} catch (IOException e) {
System.err.println("Error writing to file: " + e.getMessage());
System.out.println(“John Doe”);
System.out.println(“123456789”);
}
}
}
OUTPUT:-
This is a sample content from the input.txt file.
Question 8:
In Java, both the Comparator and Comparable interfaces are used for defining the comparison logic between
objects, but they are used in different contexts.
Comparable Interface:
Context:
Used when you want the natural ordering of objects.
Implemented by the class of objects being compared.
Interface Signature:
public interface Comparable<T> {
int compareTo(T o);
}
Comparison Logic:
The compareTo method is implemented in the class of objects being compared.
Returns a negative integer, zero, or a positive integer as the calling object is less than, equal to, or greater than
the specified object.
Example:
public class Person implements Comparable<Person> {
private String name;
private int age;
// Constructors, getters, setters
@Override
public int compareTo(Person otherPerson) {
return this.name.compareTo(otherPerson.name);
}
}
public class ComparableExample {
public static void main(String[] args) {
List<Person> persons = new ArrayList<>();
persons.add(new Person("John", 25));
persons.add(new Person("Alice", 30));
persons.add(new Person("Bob", 22));
Collections.sort(persons); // Uses compareTo for natural ordering
for (Person person : persons) {
System.out.println(person.getName());
}
}
}
Comparator Interface:
Context:
Used when you want to define multiple ways of sorting or when you don't have control over the class being
compared.
Implemented by a separate class (or lambda expression).
Interface Signature:
public interface Comparator<T> {
int compare(T o1, T o2);
}
Comparison Logic:
The compare method is implemented in a separate class or a lambda expression.
Returns a negative integer, zero, or a positive integer as the first argument is less than, equal to, or greater than
the second.
Example:
public class AgeComparator implements Comparator<Person> {
@Override
public int compare(Person person1, Person person2) {
return Integer.compare(person1.getAge(), person2.getAge());
}
}
public class ComparatorExample {
public static void main(String[] args) {
List<Person> persons = new ArrayList<>();
persons.add(new Person("John", 25));
persons.add(new Person("Alice", 30));
persons.add(new Person("Bob", 22));
AgeComparator ageComparator = new AgeComparator();
Collections.sort(persons, ageComparator); // Uses compare from AgeComparator
for (Person person : persons) {
System.out.println(person.getName());
}
}
}
Question 9:
In Java, a package is a mechanism to organize classes and interfaces into a namespace. It helps in avoiding
naming conflicts, and it provides a way to group related classes and interfaces. A package is a collection of
related classes and interfaces grouped together under a common name.
Creating Packages:
There are two main ways to create packages in Java:
Using the package keyword:
You can explicitly specify the package name at the beginning of your Java source file. This is done by using the
package keyword followed by the package name. All the classes and interfaces defined in that file will belong to
the specified package.
// File: MyPackageClass.java
package com.example.mypackage;
public class MyPackageClass {
// class implementation
}
Here, the class MyPackageClass is part of the package com.example.mypackage.
Using the directory structure:
Organize your source code into directories that reflect the package structure. The directory structure must match
the package structure. For example:
src
└── com
└── example
└── mypackage
└── MyPackageClass.java
The content of MyPackageClass.java remains the same:
// File: MyPackageClass.java
package com.example.mypackage;
public class MyPackageClass {
// class implementation
}
Then, compile the source file using:
javac -d . MyPackageClass.java
The -d option specifies the destination directory for the compiled class files. The . means the current directory.
After compilation, the directory structure will be:
src
└── com
└── example
└── mypackage
└── MyPackageClass.class
Accessing Classes from a Package:
To use a class from another package, you need to either import the class explicitly or use the fully qualified
name. Examples:
Importing the class:
// File: AnotherClass.java
import com.example.mypackage.MyPackageClass;
public class AnotherClass {
public static void main(String[] args) {
MyPackageClass myObject = new MyPackageClass();
// Use the MyPackageClass object
}
}
Using the fully qualified name:
// File: AnotherClass.java
public class AnotherClass {
public static void main(String[] args) {
com.example.mypackage.MyPackageClass myObject = new com.example.mypackage.MyPackageClass();
// Use the MyPackageClass object
}
}
Both methods have their use cases, and the choice depends on the specific requirements of your project.
Question 10:
In Java, an exception is an abnormal event that occurs during the execution of a program and disrupts its normal
flow. When an exceptional situation arises, an object representing that situation is created, and the normal flow of
the program is interrupted. This object is an instance of a class derived from the Throwable class.
Java has two types of exceptions: Checked exceptions and Unchecked exceptions.
Checked Exceptions:
Checked exceptions are exceptions that the Java compiler forces you to handle explicitly in your code. They
occur at compile-time.
These exceptions are subclasses of Exception (excluding RuntimeException and its subclasses).
Examples of checked exceptions include IOException, ClassNotFoundException, and SQLException.
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
public class CheckedExceptionExample {
public static void main(String[] args) {
try {
File file = new File("example.txt");
FileReader reader = new FileReader(file);
// Perform operations that may throw IOException
} catch (IOException e) {
// Handle the IOException
e.printStackTrace();
}
}
}
Unchecked Exceptions (Runtime Exceptions):
Unchecked exceptions are exceptions that the compiler does not force you to handle explicitly. They occur at
runtime.
These exceptions are subclasses of RuntimeException and its subclasses.
Examples of unchecked exceptions include NullPointerException, ArrayIndexOutOfBoundsException, and
ArithmeticException.
public class UncheckedExceptionExample {
public static void main(String[] args) {
int[] array = {1, 2, 3};
try {
// Perform operations that may throw ArrayIndexOutOfBoundsException
int value = array[5];
} catch (ArrayIndexOutOfBoundsException e) {
// Handle the ArrayIndexOutOfBoundsException
e.printStackTrace();
}
}
}
In summary, checked exceptions are exceptions that are checked at compile-time, and the compiler forces you to
handle them using try-catch blocks or specify them in the method signature using the throws keyword.
Unchecked exceptions, on the other hand, occur at runtime and are not enforced by the compiler, giving you the
flexibility to handle them if needed.
Question 11:
// Custom exception class
class CustomException extends Exception {
public CustomException(String message) {
super(message);
}
}
// Class that throws the custom exception
class ExceptionThrower {
public void processInput(int input) throws CustomException {
if (input < 0) {
throw new CustomException("Input should be a non-negative number.");
} else {
System.out.println("Input is valid: " + input);
}
}
}
// Main class to demonstrate the use of the custom exception
public class UserDefinedExceptionExample {
public static void main(String[] args) {
ExceptionThrower thrower = new ExceptionThrower();
int userInput = -5;
try {
thrower.processInput(userInput);
} catch (CustomException e) {
System.err.println("CustomException caught: " + e.getMessage());
}
}
}
Question 12:
try:
The try block is used to enclose a set of statements that might generate exceptions.
The code inside the try block is monitored for exceptions, and if any exception occurs, it is caught by the
corresponding catch block.
try {
// Code that might throw an exception
} catch (ExceptionType e) {
// Code to handle the exception
}
catch:
The catch block follows the try block and is used to catch and handle exceptions.
It specifies the type of exception it can catch (ExceptionType), and when an exception of that type occurs in the
try block, control transfers to the catch block for handling.
try {
// Code that might throw an exception
} catch (ExceptionType e) {
// Code to handle the exception
}
finally:
The finally block is used to execute a set of statements, whether an exception is thrown or not.
It is often used for cleanup operations, like closing files or releasing resources.
try {
// Code that might throw an exception
} catch (ExceptionType e) {
// Code to handle the exception
} finally {
// Code that always executes
}
throw:
The throw keyword is used to explicitly throw an exception in your code.
It is followed by an instance of Throwable (typically an object of a class that extends Exception).
throw new SomeException("This is an exception message");
throws:
The throws keyword is used in method declarations to indicate that the method might throw certain types of
exceptions.
It specifies the exception types the method might throw, allowing the calling code to handle those exceptions.
void someMethod() throws SomeException {
// Method code
}
These keywords work together to form the basis of Java's exception handling mechanism, allowing developers to
write code that gracefully handles unexpected situations.
Question 13:
In Java, the keywords try, catch, finally, throw, and throws are used in exception handling. Here's a brief
explanation of each:
Thread Life Cycle in Java:
The life cycle of a thread in Java consists of several states, and transitions between these states. The life cycle of
a thread can be represented by the following diagram:
New (born):
A thread is in this state when an instance of the Thread class is created, but before the start() method is called.
The thread is not alive in this state.
Runnable (ready to run):
A thread enters the runnable state when the start() method is called.
The thread is now eligible to run, but the actual execution depends on the thread scheduler.
It is important to note that a runnable thread might not be running immediately, as it depends on the scheduling
algorithm of the operating system.
Blocked (waiting for a monitor lock):
A thread transitions to the blocked state when it tries to access an object that another thread has locked.
It remains in this state until the lock becomes available.
Threads can also enter the blocked state by explicitly calling methods like Object.wait() or Thread.sleep().
Waiting (waiting indefinitely for another thread):
A thread enters the waiting state by calling methods like Object.wait(), Thread.join(), or LockSupport.park()
without a specified timeout.
The thread waits until another thread invokes the notify(), notifyAll(), or interrupt() method for the same object.
Timed Waiting (waiting for another thread with a timeout):
A thread enters the timed waiting state by calling methods like Thread.sleep() or Object.wait() with a specified
timeout.
The thread waits for the specified amount of time or until it is notified.
Terminated (dead):
A thread enters the terminated state when its run() method completes, or when the stop() method is called.
Options for Creating Threads in Java:
Extending the Thread class:
Create a class that extends the Thread class.
Override the run() method to define the code that constitutes the new thread.
class MyThread extends Thread {
public void run() {
// Code for the new thread
}
}
Implementing the Runnable interface:
Create a class that implements the Runnable interface.
Implement the run() method.
class MyRunnable implements Runnable {
public void run() {
// Code for the new thread
}
}
You can then create a thread by passing an instance of your class to the Thread constructor.
Thread myThread = new Thread(new MyRunnable());
Using Lambda Expressions:
With Java 8 and later versions, you can use lambda expressions to simplify the creation of threads.
Thread myThread = new Thread(() -> {
// Code for the new thread
});
This is particularly convenient when using the Runnable interface.
Implementing the Callable interface:
Similar to Runnable, but the Callable interface allows a thread to return a result.
It is associated with the Future and ExecutorService classes.
These options provide flexibility in creating threads based on different requirements and preferences.
Question 14:
class ReverseNumberThread extends Thread {
// Constructor to set the thread name
public ReverseNumberThread(String name) {
super(name);
}
// Run method, where the actual logic of the thread is implemented
public void run() {
for (int i = 10; i >= 1; i--) {
System.out.println(Thread.currentThread().getName() + ": " + i);
try {
// Adding a short delay for better visualization
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class ReverseNumberThreadExample {
public static void main(String[] args) {
// Create two threads with different names
ReverseNumberThread thread1 = new ReverseNumberThread("Thread 1");
ReverseNumberThread thread2 = new ReverseNumberThread("Thread 2");
// Start the threads
thread1.start();
thread2.start();
}
}
Question 15:
class EvenThread extends Thread {
public void run() {
for (int i = 2; i <= 10; i += 2) {
System.out.println("Even Thread: " + i);
try {
Thread.sleep(500); // To make it more readable in the output
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class OddThread extends Thread {
public void run() {
for (int i = 1; i <= 10; i += 2) {
System.out.println("Odd Thread: " + i);
try {
Thread.sleep(500); // To make it more readable in the output
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class Main {
public static void main(String[] args) {
EvenThread evenThread = new EvenThread();
OddThread oddThread = new OddThread();
evenThread.start();
oddThread.start();
}
}