OOP with JAVA — Complete Exam Solutions
[Link] IV Sem | R D Engineering College | Pre-University Exam 2023-24
SECTION A — Short Answer Questions (2 Marks Each)
Q1(a). Difference between JDK, JVM, and JRE in Java
JDK (Java Development Kit): It is the complete software development environment used for developing
Java applications. It includes the JRE, compiler (javac), debugger, and other development tools. Every
developer must install JDK to write and compile Java programs.
JRE (Java Runtime Environment): It provides the runtime environment in which Java bytecode can be
executed. It includes the JVM plus core libraries and other files. End-users who only want to run Java
programs need JRE.
JVM (Java Virtual Machine): It is an abstract computing machine that enables a computer to run Java
programs. It converts bytecode into machine-specific code at runtime. JVM is responsible for Java's
platform independence (WORA – Write Once Run Anywhere).
Relation: JDK ⊃ JRE ⊃ JVM. JDK contains JRE, and JRE contains JVM.
Q1(b). Import and Static Import — Naming Convention for Packages
import statement: Used to bring a class or entire package into the current program so it can be used
without its fully-qualified name.
Example: import [Link]; or import [Link].*;
static import: Introduced in Java 5, it allows static members (fields and methods) of a class to be used
directly without class qualification.
Example: import static [Link]; — after this, you can write PI instead of [Link].
Package Naming Convention: Packages are always written in lowercase to avoid conflict with class
names. Typically use reverse domain name: e.g., [Link].
Q1(c). Difference between Overloading and Overriding
Method Overloading (Compile-time / Static Polymorphism): Defining multiple methods in the same
class with the same name but different parameter lists (different type, number, or order of parameters).
Return type alone cannot differentiate overloaded methods.
Method Overriding (Runtime / Dynamic Polymorphism): Redefining a method in a subclass that
already exists in the parent class with the same name, same return type, and same parameters. Used to
achieve runtime polymorphism.
Key Differences: Overloading occurs in the same class; Overriding occurs between parent and child
class. Overloading is resolved at compile time; Overriding is resolved at runtime. Overriding requires
@Override annotation (recommended).
Q1(d). Hierarchy of Exceptions in Java
In Java, Throwable is the root class of the exception hierarchy. It has two direct subclasses:
1. Error: Represents serious problems that a reasonable application should not try to catch. Example:
OutOfMemoryError, StackOverflowError. These are unchecked and usually unrecoverable.
2. Exception: Represents conditions that a program might want to catch. Divided into:
a) Checked Exceptions (Compile-time): Must be declared or handled. E.g., IOException,
SQLException, ClassNotFoundException.
b) Unchecked Exceptions (Runtime): Subclasses of RuntimeException. Not required to be declared.
E.g., NullPointerException, ArrayIndexOutOfBoundsException, ArithmeticException.
Hierarchy: Object → Throwable → {Error, Exception} → RuntimeException → (various specific
exceptions)
Q1(e). Use of yield Keyword in Java
The yield keyword was introduced in Java 13 as part of Switch Expressions (a preview feature, made
standard in Java 14). It is used to return a value from a switch expression block.
Example:
int numLetters = switch (day) {
case MONDAY, FRIDAY, SUNDAY -> 6;
case TUESDAY -> 7;
default -> {
int len = [Link]().length();
yield len; // returns value from block
}
};
yield is used inside a switch block (with curly braces) to produce a result value. It is NOT the same as
return — it only applies to switch expressions.
Q1(f). Advantages of the Collections Framework in Java
The Java Collections Framework (JCF) provides a unified architecture for storing and manipulating groups
of objects. Its advantages are:
1. Reduces programming effort — ready-made data structures (List, Set, Map, Queue) are available.
2. Increases performance — high-performance implementations of data structures.
3. Provides interoperability — collections can be passed between APIs seamlessly.
4. Reduces effort in learning APIs — uniform set of interfaces.
5. Reusability — generic algorithms work on any collection.
6. Type Safety — Generics prevent runtime ClassCastException.
Q1(g). Request Parameter in Spring Boot
In Spring Boot (and Spring MVC), @RequestParam annotation is used to extract query parameters from
the HTTP request URL and bind them to method parameters in a controller.
Example:
@GetMapping("/greet")
public String greet(@RequestParam String name) {
return "Hello, " + name;
}
// URL: /greet?name=John → Output: Hello, John
Optional parameters can be handled using: @RequestParam(required=false,
defaultValue="Guest").
SECTION B — Attempt any THREE (7 Marks Each)
Q2(a). Abstract Class vs Interface — With Example
Abstract Class: A class declared with the abstract keyword. It can have both abstract methods (without
body) and concrete methods (with body). It can have constructors, instance variables, and access
modifiers.
Interface: A pure abstraction blueprint. Before Java 8, all methods were abstract. From Java 8+,
interfaces can have default and static methods. Variables in interface are implicitly public static
final.
Key Differences:
1. A class can extend only one abstract class, but can implement multiple interfaces.
2. Abstract class can have constructors; interfaces cannot (prior to Java 9).
3. Abstract class supports all access modifiers; interface members are public by default.
4. Use abstract class when classes share common code; use interface for capability contracts.
Example:
// Abstract Class
abstract class Animal {
String name;
Animal(String name) { [Link] = name; }
abstract void sound(); // abstract method
void breathe() { [Link]("Breathing"); } // concrete
}
// Interface
interface Swimmable {
void swim();
}
class Duck extends Animal implements Swimmable {
Duck() { super("Duck"); }
public void sound() { [Link]("Quack"); }
public void swim() { [Link]("Duck swims"); }
}
Q2(b). Difference between throw and throws — With Example
throw: A Java keyword used inside a method body to explicitly throw an exception. It is followed by an
exception object. Only a single exception can be thrown at a time using throw.
throws: A Java keyword used in a method signature/declaration to indicate that the method might throw
one or more exceptions. It delegates the responsibility of exception handling to the caller.
Key Differences:
1. throw is used inside method body; throws is used in method declaration.
2. throw throws one exception at a time; throws can declare multiple exceptions.
3. throw is followed by an instance; throws is followed by exception class name(s).
Example:
// throws in method signature
public void readFile(String file) throws IOException, FileNotFoundException {
if (file == null) {
throw new IllegalArgumentException("File cannot be null"); // throw
}
FileReader fr = new FileReader(file); // may throw FileNotFoundException
}
// Caller must handle or declare the exception
public static void main(String[] args) {
try {
new Demo().readFile(null);
} catch (IOException e) {
[Link]("Caught: " + [Link]());
}
}
Q2(c). Functional Interface vs Normal Interface — With Example
Functional Interface: An interface that contains exactly one abstract method. It can have multiple
default or static methods. Annotated with @FunctionalInterface (optional but recommended). They
are the foundation for Lambda Expressions in Java 8+.
Normal Interface: Can have any number of abstract methods. Cannot be used directly with lambda
expressions.
Built-in Functional Interfaces: Runnable, Callable, Comparator, Predicate, Function, Consumer,
Supplier.
Example:
@FunctionalInterface
interface MathOperation {
int operate(int a, int b); // Single abstract method
}
public class Main {
public static void main(String[] args) {
// Using Lambda Expression
MathOperation add = (a, b) -> a + b;
MathOperation multiply = (a, b) -> a * b;
[Link]("Add: " + [Link](5, 3)); // 8
[Link]("Multiply: " + [Link](5, 3)); // 15
}
}
Lambda expressions provide a concise way to implement functional interfaces without creating
anonymous inner classes.
Q2(d). Difference between ArrayList and LinkedList in Java Collections
ArrayList: Implemented using a dynamic array. Provides fast random access O(1) for get/set operations.
Insertion and deletion in the middle is slow O(n) because elements must be shifted.
LinkedList: Implemented using a doubly linked list. Provides fast insertion/deletion O(1) at both ends.
Random access is slow O(n) because traversal from head is needed.
Detailed Comparison:
1. Memory: ArrayList uses less memory; LinkedList has extra memory for node pointers.
2. Access: ArrayList is better for frequent read operations; LinkedList for frequent add/remove.
3. Iteration: ArrayList is faster for iteration due to contiguous memory.
4. Implements: ArrayList implements List; LinkedList implements both List and Deque.
Example:
import [Link].*;
ArrayList<String> al = new ArrayList<>();
[Link]("Apple"); [Link]("Banana"); [Link](0); // O(1) access
LinkedList<String> ll = new LinkedList<>();
[Link]("Apple"); [Link]("Mango"); [Link](); // O(1) at ends
Q2(e). Spring Boot vs Traditional Spring Applications
Spring Boot is built on top of the Spring Framework and is designed to simplify the bootstrapping and
development of new Spring applications. It follows the 'convention over configuration' principle.
Key Differences:
1. Configuration: Traditional Spring requires extensive XML or Java configuration; Spring Boot uses
auto-configuration.
2. Server: Spring Boot embeds Tomcat/Jetty/Undertow — no external server needed; Traditional Spring
requires external server deployment.
3. Dependency: Spring Boot uses starter dependencies (e.g., spring-boot-starter-web); Traditional Spring
requires manual dependency management.
4. Deployment: Spring Boot creates standalone JAR with all dependencies; Traditional Spring creates
WAR files.
5. Boilerplate: Spring Boot drastically reduces boilerplate code; Traditional Spring has more setup code.
Spring Boot Core Features: Auto-configuration, Embedded server, Spring Boot CLI, Actuator for
monitoring, Spring Initializr for project setup.
SECTION C — Attempt any ONE per question (7 Marks Each)
Q3(a). Role of Constructors — Sub-class calls Super-class Constructor
A constructor is a special method in Java that is called when an object is created. It has the same name
as the class and no return type. Its primary role is to initialize the object's state.
Types of Constructors:
1. Default Constructor: No parameters. Automatically provided if no constructor is defined.
2. Parameterized Constructor: Takes arguments to initialize fields with specific values.
3. Copy Constructor: Takes an object of the same class and copies its values.
super() in Constructor Chaining: When a subclass object is created, Java implicitly calls the superclass
constructor first using super(). If the parent class doesn't have a default constructor, the child class
MUST explicitly call super(args) as the first statement.
Example:
class Vehicle {
String brand;
int year;
Vehicle(String brand, int year) {
[Link] = brand;
[Link] = year;
[Link]("Vehicle constructor called");
}
}
class Car extends Vehicle {
int doors;
Car(String brand, int year, int doors) {
super(brand, year); // MUST be first line
[Link] = doors;
[Link]("Car constructor called");
}
}
public class Main {
public static void main(String[] args) {
Car c = new Car("Toyota", 2023, 4);
// Output: Vehicle constructor called
// Car constructor called
}
}
Q3(b). Multiple Inheritance in Java — Using Interfaces
Java does NOT support multiple inheritance with classes to avoid the Diamond Problem (ambiguity
when two parent classes have the same method). However, Java supports multiple inheritance through
interfaces.
A class can implement multiple interfaces, thereby inheriting behavior from multiple sources.
Example:
interface Flyable {
default void fly() {
[Link]("Flying in the sky");
}
}
interface Swimmable {
default void swim() {
[Link]("Swimming in water");
}
}
interface Runnable {
void run(); // abstract
}
// Duck inherits from multiple interfaces = Multiple Inheritance
class Duck implements Flyable, Swimmable, Runnable {
public void run() {
[Link]("Running on land");
}
}
public class Main {
public static void main(String[] args) {
Duck d = new Duck();
[Link](); // Flying in the sky
[Link](); // Swimming in water
[Link](); // Running on land
}
}
An interface can also extend multiple interfaces: interface C extends A, B {} — This is another
form of multiple inheritance in Java.
Q4(a). Java Program for Multithreading Execution
A thread is the smallest unit of execution in Java. Multithreading allows concurrent execution of two or
more threads to maximize CPU utilization. Java provides the Thread class and Runnable interface to
create threads.
Ways to create threads: 1) Extend Thread class, 2) Implement Runnable interface (preferred).
Example (using both approaches):
// Method 1: Extending Thread class
class MyThread extends Thread {
String name;
MyThread(String name) { [Link] = name; }
public void run() {
for (int i = 1; i <= 3; i++) {
[Link](name + " - Count: " + i);
try { [Link](500); } catch (InterruptedException e) {}
}
}
}
// Method 2: Implementing Runnable
class Task implements Runnable {
public void run() {
[Link]("Runnable Task running in: " + [Link]().getName());
}
}
public class MultiThreadDemo {
public static void main(String[] args) {
MyThread t1 = new MyThread("Thread-A");
MyThread t2 = new MyThread("Thread-B");
[Link](); // starts thread, calls run()
[Link]();
Thread t3 = new Thread(new Task());
[Link]();
}
}
Q4(b)(i). sleep() vs wait() | (ii). notify() vs notifyAll()
(i) sleep() vs wait():
sleep(): Defined in Thread class. It pauses the current thread for a specified number of milliseconds. It
does NOT release any lock/monitor held by the thread. It is a static method.
wait(): Defined in Object class. It causes the current thread to wait until another thread calls notify()
or notifyAll() on the same object. It RELEASES the lock/monitor. Must be called inside a
synchronized block.
Key: sleep() is for time-based pausing; wait() is for inter-thread communication and releases the monitor.
(ii) notify() vs notifyAll():
notify(): Wakes up a single thread that is waiting on the object's monitor. If multiple threads are waiting,
one is chosen arbitrarily. The awakened thread cannot proceed until it reacquires the lock.
notifyAll(): Wakes up all threads waiting on the object's monitor. All awakened threads compete for the
lock; only one will proceed at a time.
Key: Use notify() when only one thread needs to be woken up; use notifyAll() when all waiting threads
need to re-check their condition (safer but less efficient).
Example of wait/notify pattern:
synchronized(obj) {
while (!condition) {
[Link](); // releases lock and waits
}
// do work
}
// In another thread:
synchronized(obj) {
condition = true;
[Link](); // wakes all waiting threads
}
SECTION C (Continued) — Questions 5, 6, 7
Q5(a). Sealed Classes in Java — How They Differ from final
Sealed Class (introduced in Java 17, preview in Java 15/16): A class that restricts which other classes
or interfaces can extend or implement it. Declared using the sealed keyword with a permits clause
listing allowed subclasses.
final class: A class that cannot be extended at all by any class. It is the most restrictive — no
subclassing allowed.
Key Differences:
1. Extensibility: final = no extension; sealed = controlled/limited extension to permitted classes only.
2. Purpose: final prevents subclassing entirely; sealed allows only approved subclasses.
3. Pattern Matching: Sealed classes work well with switch pattern matching — compiler knows all
subtypes.
4. Permitted subclasses must be in the same package/module and must be declared as final, sealed, or
non-sealed.
Example:
// Sealed class — only Circle, Rectangle, Triangle are permitted
public sealed class Shape permits Circle, Rectangle, Triangle {
abstract double area();
}
final class Circle extends Shape {
double radius;
Circle(double r) { [Link] = r; }
double area() { return [Link] * radius * radius; }
}
final class Rectangle extends Shape {
double w, h;
Rectangle(double w, double h) { this.w = w; this.h = h; }
double area() { return w * h; }
}
non-sealed class Triangle extends Shape {
double base, height;
Triangle(double b, double h) { [Link] = b; [Link] = h; }
double area() { return 0.5 * base * height; }
}
// final class — CANNOT be extended
final class Constant {
static final double PI = 3.14159;
}
Q5(b)(i). Lambda Expressions | (ii). try-with-resources
(i) Lambda Expressions:
Introduced in Java 8, lambda expressions provide a concise way to implement functional interfaces
(interfaces with a single abstract method). They enable functional programming in Java.
Syntax: (parameters) -> expression or (parameters) -> { statements; }
Examples:
// No parameter
Runnable r = () -> [Link]("Running!");
// Single parameter
Consumer<String> printer = name -> [Link]("Hello " + name);
// Multiple parameters
Comparator<Integer> comp = (a, b) -> a - b;
// With block body
MathOp square = (x) -> {
int result = x * x;
return result;
};
// Used with Collections
List<String> list = [Link]("Banana","Apple","Mango");
[Link]((s1, s2) -> [Link](s2));
[Link](s -> [Link](s));
Benefits: Reduces boilerplate, enables functional-style operations, works with Streams API, enables
parallel processing.
(ii) try-with-resources:
Introduced in Java 7. It automatically closes resources (files, streams, connections, etc.) at the end of the
try block, without needing an explicit finally block. The resource must implement the AutoCloseable or
Closeable interface.
Syntax: try (ResourceType res = new ResourceType()) { ... }
Example:
// Without try-with-resources (old way)
BufferedReader br = null;
try {
br = new BufferedReader(new FileReader("[Link]"));
[Link]([Link]());
} catch (IOException e) {
[Link]();
} finally {
if (br != null) [Link](); // manual close
}
// With try-with-resources (Java 7+)
try (BufferedReader br2 = new BufferedReader(new FileReader("[Link]"))) {
[Link]([Link]());
} catch (IOException e) {
[Link]();
}
// br2 is automatically closed after try block exits
Multiple resources can be declared: try (Res1 r1 = ...; Res2 r2 = ...) {}. They are closed in
reverse order of declaration.
Q6(a). Iterator vs Comparator Interface
Iterator Interface ([Link]): Used to traverse elements of a collection one by one. It provides a
way to access elements sequentially without exposing the underlying structure.
Methods of Iterator: hasNext() — returns true if more elements exist; next() — returns the next
element; remove() — removes the last returned element.
Iterator Example:
List<String> fruits = new ArrayList<>([Link]("Apple","Mango","Banana"));
Iterator<String> it = [Link]();
while ([Link]()) {
String fruit = [Link]();
[Link](fruit);
if ([Link]("Mango")) [Link](); // safe removal during iteration
}
Comparator Interface ([Link]): Used to define a custom ordering/sorting logic for
objects. It is a functional interface with the method compare(T o1, T o2) which returns negative, zero,
or positive integer.
Comparator Example:
List<String> names = [Link]("Charlie","Alice","Bob");
// Sort alphabetically (natural order)
[Link](names, (a, b) -> [Link](b));
// Sort by length
[Link]([Link](String::length));
// Custom Object Sorting
class Student { String name; int marks; }
List<Student> students = ...;
[Link]((s1, s2) -> [Link] - [Link]); // descending marks
Key Difference: Iterator is for traversal; Comparator is for ordering. Iterator works on a collection
instance; Comparator works on two objects to compare them.
Q6(b). Set vs List in Collections Framework — With Programming Example
List ([Link]): An ordered collection that allows duplicate elements. Elements are accessed by their
index. Maintains insertion order. Common implementations: ArrayList, LinkedList, Vector.
Set ([Link]): An unordered collection that does NOT allow duplicate elements. Does not provide
index-based access. Common implementations: HashSet (unordered), LinkedHashSet (insertion order),
TreeSet (sorted order).
Key Differences:
1. Duplicates: List allows; Set rejects duplicates (add() returns false).
2. Order: List maintains insertion order; HashSet has no order; TreeSet sorts.
3. Access: List supports get(index); Set has no index-based access.
4. Null: List allows multiple nulls; HashSet allows one null; TreeSet allows no null.
Programming Example:
import [Link].*;
public class SetVsList {
public static void main(String[] args) {
// LIST — allows duplicates, maintains order
List<String> list = new ArrayList<>();
[Link]("Java"); [Link]("Python"); [Link]("Java");
[Link]("List: " + list);
// Output: [Java, Python, Java] — duplicate kept
// SET — no duplicates
Set<String> set = new HashSet<>();
[Link]("Java"); [Link]("Python"); [Link]("Java");
[Link]("HashSet: " + set);
// Output: [Java, Python] — duplicate removed
// TreeSet — sorted
Set<String> treeSet = new TreeSet<>(set);
[Link]("TreeSet: " + treeSet);
// Output: [Java, Python] — alphabetical order
// Index access in List
[Link]("Element at 0: " + [Link](0)); // Java
}
}
Q7(a). Spring MVC — What It Is and How It Works
Spring MVC (Model-View-Controller) is a web framework built on the Spring Framework that implements
the MVC design pattern. It provides a structured way to build web applications by separating concerns into
three components:
1. Model: Represents the data/business logic. Contains the application state. Plain Java objects (POJOs)
or data from database.
2. View: Responsible for rendering the UI. Typically JSP, Thymeleaf, or JSON response for REST APIs.
3. Controller: Handles incoming HTTP requests, processes them (using service/model), and returns the
appropriate view or response.
How Spring MVC Works (Request Flow):
1. Client sends an HTTP request.
2. DispatcherServlet (Front Controller) intercepts the request.
3. It consults HandlerMapping to find the right controller method.
4. Controller processes the request, interacts with Service/Model.
5. Controller returns a ModelAndView object (view name + data).
6. ViewResolver resolves the view name to an actual view (JSP/Thymeleaf).
7. View renders the response and sends it back to the client.
Example Controller:
@Controller
public class HelloController {
@GetMapping("/hello")
public String hello(Model model) {
[Link]("message", "Welcome to Spring MVC!");
return "hello"; // resolves to [Link] or [Link]
}
@PostMapping("/submit")
public String submit(@RequestParam String name, Model model) {
[Link]("name", name);
return "result";
}
}
Q7(b). Spring Framework — What It Is and Core Features
Spring Framework is an open-source, lightweight, and comprehensive framework for enterprise Java
development. It was created by Rod Johnson in 2003. It aims to simplify Java EE development and
promotes loose coupling through Dependency Injection (DI) and Inversion of Control (IoC).
Core Features of Spring Framework:
1. Inversion of Control (IoC): The framework manages the creation and lifecycle of objects (beans).
Objects don't create their dependencies — Spring injects them.
2. Dependency Injection (DI): Dependencies are injected through constructor injection, setter injection, or
field injection using @Autowired annotation. Promotes loose coupling.
3. Aspect-Oriented Programming (AOP): Enables separation of cross-cutting concerns like logging,
security, and transaction management from business logic.
4. Spring MVC: Web framework for building web applications and RESTful services.
5. Spring Data: Simplifies database access. Provides repositories for JPA, MongoDB, etc.
6. Spring Security: Comprehensive authentication and authorization framework.
7. Spring Transaction Management: Declarative transaction management using @Transactional.
8. Spring Boot: Extension of Spring that provides auto-configuration, embedded servers, and opinionated
defaults.
Example of DI with Spring:
@Component
class Engine {
public void start() { [Link]("Engine started"); }
}
@Component
class Car {
@Autowired // Spring injects Engine automatically
private Engine engine;
public void drive() {
[Link]();
[Link]("Car is driving");
}
}
All the Best for Your Exam! Revise these answers thoroughly. Focus on code examples as they
fetch full marks.