Module-1: Fundamentals of OOP and Java Basics 1. Difference between Procedure-Oriented Programming (POP) and Object-Oriented Programming (OOP) POP (e.g., C, Pascal): Focuses on functions/procedures. Data is global and can be accessed by any function. Top-down approach. Less secure as data is exposed. Difficulty in handling real-world complexity. OOP (e.g., Java, C++): Focuses on objects (data + methods). Data is encapsulated within objects. Bottom-up approach. More secure due to data hiding. Models real-world entities effectively. 2. Difference between Java and C++ Language Feature Java C++ Platform Platform-independent (WORA: Write Once, Run Anywhere) Platform-dependent Pointers No explicit pointers (uses references internally) Supports pointers explicitly Memory Mgmt. Automatic garbage collection Manual memory management (new/delete) Multiple Inheritance Through Interfaces only Directly supported Operator Overloading Not supported Supported GoTo Statement Not supported Supported Virtual Keyword No virtual keyword (all methods are virtual by default unless final ) Uses virtual keyword for dynamic polymorphism 3. What is ADT (Abstract Data Type)? How to implement an ADT? An Abstract Data Type (ADT) is a mathematical model for data types, defined by its behavior from the point of view of a user of the data, specifically in terms of possible values, possible operations on data of this type, and the behavior of these operations. Implementation: An ADT is implemented using a concrete data structure. For example, a List ADT can be implemented using an array or a linked list. The user interacts with the ADT through its defined operations, without needing to know the underlying implementation details. 4. What is Stack ADT? Operations: push(), pop(), isEmpty(), isFull(), size(), peek() A Stack ADT is a linear data structure that follows the Last-In, First-Out (LIFO) principle. Think of a stack of plates. push(element) : Adds an element to the top of the stack. pop() : Removes and returns the element from the top of the stack. isEmpty() : Returns true if the stack contains no elements, false otherwise. isFull() : Returns true if the stack has reached its maximum capacity, false otherwise (relevant for array-based stacks). size() : Returns the number of elements in the stack. peek() : Returns the element at the top of the stack without removing it. 5. Write the function of List ADT: get(), insert(), remove(), removeAt(), replace(), size(), isEmpty(), isFull() A List ADT is an ordered collection of elements. Elements can be added, removed, and accessed by their position (index). get(index) : Returns the element at the specified index . insert(element, index) : Inserts an element at the specified index . remove(element) : Removes the first occurrence of the specified element from the list. removeAt(index) : Removes the element at the specified index . replace(element, index) : Replaces the element at the specified index with the new element . size() : Returns the number of elements in the list. isEmpty() : Returns true if the list contains no elements, false otherwise. isFull() : Returns true if the list has reached its maximum capacity, false otherwise (relevant for array-based lists). 6. What is Queue ADT? Write the function of Queue ADT: enqueue(), dequeue(), peek(), size(), isFull(), isEmpty() A Queue ADT is a linear data structure that follows the First-In, First-Out (FIFO) principle. Think of a line of people waiting. enqueue(element) : Adds an element to the rear (back) of the queue. dequeue() : Removes and returns the element from the front of the queue. peek() : Returns the element at the front of the queue without removing it. size() : Returns the number of elements in the queue. isFull() : Returns true if the queue has reached its maximum capacity, false otherwise. isEmpty() : Returns true if the queue contains no elements, false otherwise. 7. Short note: Concrete invariant, Concrete state space Concrete Invariant: A condition that holds true for all valid states of a data structure's concrete representation. It helps maintain the integrity and correctness of the data structure's internal state. For example, in a sorted array, the invariant might be that array[i] <= array[i+1] for all valid i . Concrete State Space: The set of all possible actual representations (how the data is physically stored) that a data structure can take. This is distinct from the abstract state space, which describes the logical values of an ADT. 8. What is Abstraction? Advantage of Abstraction. Abstract method. Abstraction: The process of hiding the complex implementation details and showing only the essential features of an object. It focuses on "what" an object does rather than "how" it does it. Advantages: Reduces complexity by hiding irrelevant details. Improves maintainability and reusability. Enhances security by protecting internal implementation. Allows for easier modification of underlying implementation without affecting client code. Abstract Method: A method declared without an implementation (without a body). It is declared in an abstract class, and its implementation must be provided by concrete subclasses. In Java, it is declared using the abstract keyword: public abstract void draw(); 9. What is Interface in Java? Multiple inheritance using interface. Interface: A blueprint of a class. It can have abstract methods and constants. It's a mechanism to achieve total abstraction. In Java, a class can implement multiple interfaces. Multiple Inheritance using Interface: Java does not support direct multiple inheritance of classes (a class cannot extend more than one class) to avoid the "Diamond Problem." However, it achieves multiple inheritance of type (behavior) through interfaces. A class can implement multiple interfaces, thereby inheriting the abstract methods from all of them and providing their implementations. This allows an object to have multiple behaviors. interface Walkable { void walk(); } interface Swimmable { void swim(); } class Human implements Walkable, Swimmable { public void walk() { System.out.println("Human walks"); } public void swim() { System.out.println("Human swims"); } } 10. Difference between Interface and Abstract Class Feature Abstract Class Interface Declaration abstract class A {} interface I {} Methods Can have abstract and non-abstract methods. Before Java 8, only abstract methods. From Java 8, can have default and static methods. From Java 9, private methods. Variables Can have instance, static, and final variables. Only public static final variables (constants). Constructors Can have constructors. Cannot have constructors. Inheritance Extended by subclasses using extends . Implemented by classes using implements . Multiple Inheritance A class can extend only one abstract class. A class can implement multiple interfaces. Access Modifiers Can have any access modifier (public, protected, default, private). Methods are implicitly public abstract (before Java 8). Variables are implicitly public static final . Module-2: OOP Concepts in Java 1. Difference between Association and Aggregation? Association: Represents a general binary relationship between two classes. It simply states that objects of one class are connected to objects of another class. It's a "has-a" relationship but without strong ownership. Example: A Student is associated with a Professor. Aggregation: A specific type of association that represents a "has-a" or "part-of" relationship where the child can exist independently of the parent. It's a weak form of ownership. Example: A Department has Professors. If the Department is deleted, Professors might still exist. 2. Explain access modifiers (public, protected, private, default). Differentiate between them. Access modifiers in Java control the visibility and accessibility of classes, fields, methods, and constructors. public : Accessible from anywhere. protected : Accessible within the same package and by subclasses (even in different packages). default (no keyword): Accessible only within the same package. private : Accessible only within the same class. Modifier Same Class Same Package (Subclass) Same Package (Non-subclass) Different Package (Subclass) Different Package (Non-subclass) private $\checkmark$ $\times$ $\times$ $\times$ $\times$ default $\checkmark$ $\checkmark$ $\checkmark$ $\times$ $\times$ protected $\checkmark$ $\checkmark$ $\checkmark$ $\checkmark$ $\times$ public $\checkmark$ $\checkmark$ $\checkmark$ $\checkmark$ $\checkmark$ 3. Difference between static and final keyword. static : Belongs to the class, not to any specific instance. static variables: Shared among all instances of the class. static methods: Can be called directly on the class name, without creating an object. Cannot access non-static members directly. static block: Initializes static members. Executed once when the class is loaded. final : Makes an entity unchangeable. final variable: A constant. Its value can be assigned only once. final method: Cannot be overridden by subclasses. final class: Cannot be extended (inherited) by other classes. 4. Difference between Static Binding and Dynamic Binding (Early Binding & Late Binding) Static Binding (Early Binding): Occurs at compile time. Method calls are resolved based on the type of the reference variable. Happens for static , private , and final methods, and variables. Faster execution. Dynamic Binding (Late Binding): Occurs at runtime. Method calls are resolved based on the actual object type (the object pointed to by the reference variable). Happens for overridden methods (polymorphism). Allows for more flexible and extensible code. 5. Characteristics of OOP (Object Oriented Programming). Describe Everything. (4 pillars of OOP: Inheritance, Polymorphism, Encapsulation & Abstraction). Explain Everything with code. Encapsulation: Binding data (variables) and methods acting on that data together into a single unit (class). It also involves restricting direct access to some of an object's components, which is a form of data hiding. Achieved using access modifiers. class Account { private double balance; // Encapsulated data public void deposit(double amount) { // Public method to access/modify data if (amount > 0) { balance += amount; } } public double getBalance() { // Public getter return balance; } } Abstraction: Showing only essential features of an object and hiding the complex implementation details. (See previous Module 1, Q8). Achieved using abstract classes and interfaces. abstract class Shape { abstract double area(); // Abstract method public void display() { System.out.println("This is a shape."); } } class Circle extends Shape { double radius; public Circle(double radius) { this.radius = radius; } @Override double area() { return Math.PI * radius * radius; } } Inheritance: A mechanism where one object acquires all the properties and behaviors of a parent object. It promotes code reusability and establishes an "is-a" relationship. class Animal { // Parent class void eat() { System.out.println("Animal eats"); } } class Dog extends Animal { // Child class inherits from Animal void bark() { System.out.println("Dog barks"); } } // Usage: Dog myDog = new Dog(); myDog.eat(); myDog.bark(); Polymorphism: The ability of an object to take on many forms. It allows objects of different classes to be treated as objects of a common type. Achieved through method overloading (compile-time) and method overriding (runtime). Method Overloading (Compile-time / Static Polymorphism): Multiple methods with the same name but different parameters (number, type, or order) within the same class. class Calculator { int add(int a, int b) { return a + b; } double add(double a, double b) { return a + b; } } Method Overriding (Runtime / Dynamic Polymorphism): A subclass provides a specific implementation for a method that is already defined in its parent class. class Vehicle { void run() { System.out.println("Vehicle is running"); } } class Car extends Vehicle { @Override void run() { System.out.println("Car is running safely"); } } // Usage: Vehicle v = new Car(); v.run(); // Calls Car's run() method 6. Difference between Class and Object. Explain with code. Class: A blueprint or a template for creating objects. It defines the properties (attributes/fields) and behaviors (methods) that objects of that class will have. It doesn't consume memory. Object: An instance of a class. It's a real-world entity that has state (values of its properties) and behavior. Objects consume memory when created. // Class definition class Lamp { String type; // property boolean isOn; // property void turnOn() { // behavior isOn = true; System.out.println(type + " lamp is ON."); } void turnOff() { // behavior isOn = false; System.out.println(type + " lamp is OFF."); } } // Object creation and usage public class Main { public static void main(String[] args) { Lamp ledLamp = new Lamp(); // Object 1 ledLamp.type = "LED"; ledLamp.turnOn(); // Calls behavior Lamp halogenLamp = new Lamp(); // Object 2 halogenLamp.type = "Halogen"; halogenLamp.turnOff(); // Calls behavior } } 7. Why Java is called Object-Oriented Programming? Java is called an Object-Oriented Programming language because it strictly adheres to the principles of OOP: Encapsulation, Abstraction, Inheritance, and Polymorphism. Everything in Java (except primitive data types) is treated as an object, and programs are designed around objects interacting with each other. 8. Write a Java program to show use of Abstract class and inheritance. abstract class Employee { String name; int id; public Employee(String name, int id) { this.name = name; this.id = id; } // Abstract method: salary calculation differs for different employee types public abstract double calculateSalary(); // Non-abstract method public void displayInfo() { System.out.println("Name: " + name + ", ID: " + id); } } class FullTimeEmployee extends Employee { double monthlySalary; public FullTimeEmployee(String name, int id, double monthlySalary) { super(name, id); this.monthlySalary = monthlySalary; } @Override public double calculateSalary() { return monthlySalary; } } class ContractEmployee extends Employee { double hourlyRate; int hoursWorked; public ContractEmployee(String name, int id, double hourlyRate, int hoursWorked) { super(name, id); this.hourlyRate = hourlyRate; this.hoursWorked = hoursWorked; } @Override public double calculateSalary() { return hourlyRate * hoursWorked; } } public class AbstractInheritanceDemo { public static void main(String[] args) { Employee ftEmployee = new FullTimeEmployee("Alice", 101, 5000.0); Employee ctEmployee = new ContractEmployee("Bob", 102, 25.0, 160); System.out.println("Full-Time Employee Details:"); ftEmployee.displayInfo(); System.out.println("Salary: $" + ftEmployee.calculateSalary()); System.out.println("\nContract Employee Details:"); ctEmployee.displayInfo(); System.out.println("Salary: $" + ctEmployee.calculateSalary()); } } 9. What is qualified association ? Describe with example A qualified association is a type of association where an attribute (the qualifier) of one class reduces the multiplicity of the association from "many" to "one" or "zero to one". It's often used when an object in a collection can be uniquely identified by a specific attribute. Example: A Library has many Books . However, each Book can be uniquely identified within the Library by its ISBN . Here, ISBN acts as the qualifier. class Book { String isbn; String title; // ... } class Library { // A map could represent a qualified association: // Library has a collection of Books, uniquely identified by ISBN private Map<String, Book> booksByISBN; public Library() { this.booksByISBN = new HashMap<>(); } public void addBook(Book book) { booksByISBN.put(book.isbn, book); } public Book getBookByISBN(String isbn) { return booksByISBN.get(isbn); // Qualifier (ISBN) reduces multiplicity } } 10. Explain static keyword with java code The static keyword in Java is used for memory management mainly. It can be applied to variables, methods, blocks, and nested classes. It indicates that the member belongs to the class itself rather than to any specific instance of the class. Static Variable: A variable declared as static is shared among all instances of the class. There is only one copy of the static variable in memory. Static Method: A method declared as static belongs to the class rather than the object. It can be invoked without creating an instance of the class. Static methods can access static data members and can change their values. They cannot directly access non-static (instance) variables or call non-static methods. Static Block: Used to initialize the static data members. It is executed automatically when the class is loaded into memory, before any objects are created or any static methods are called. Static Nested Class: An inner class can be declared static. A static nested class can be accessed directly using the outer class name and does not require an instance of the outer class. class Counter { static int count = 0; // Static variable: shared by all instances Counter() { count++; // Incremented for every new object System.out.println("Object created. Count: " + count); } static void displayCount() { // Static method System.out.println("Total objects created: " + count); // Cannot access non-static 'this' or instance variables here } static { // Static block System.out.println("Static block executed: Class 'Counter' loaded."); // Initial setup for static members can go here } } public class StaticKeywordDemo { public static void main(String[] args) { System.out.println("Main method started."); Counter c1 = new Counter(); Counter c2 = new Counter(); Counter c3 = new Counter(); Counter.displayCount(); // Calling static method using class name } } /* Output: Static block executed: Class 'Counter' loaded. Main method started. Object created. Count: 1 Object created. Count: 2 Object created. Count: 3 Total objects created: 3 */ 11. What is Constructor? Types of Constructor (Default, parameterized and copy, private constructor) Explain with code A constructor in Java is a special type of method that is used to initialize objects. It is called when an instance of the class is created. The constructor has the same name as the class and does not have a return type. Default Constructor: If you don't define any constructor in your class, Java automatically provides a default (no-argument) constructor. It initializes instance variables with default values (0 for numbers, null for objects, false for booleans). Parameterized Constructor: A constructor that takes one or more parameters. It is used to initialize the instance variables of a new object with the provided values. Copy Constructor: (Not a built-in concept like C++ but can be implemented by convention) A constructor that takes an object of the same class as an argument. It is used to create a new object by copying the values from an existing object. Private Constructor: A constructor declared with the private access modifier. It prevents the class from being instantiated from outside the class. This is often used in singleton design patterns or for utility classes that only have static members. class Student { String name; int rollNo; // 1. Default Constructor (Synthesized by Java if no other constructor is defined) // If we define other constructors, we might need to explicitly define a no-arg constructor public Student() { this.name = "Unknown"; this.rollNo = 0; System.out.println("Default constructor called."); } // 2. Parameterized Constructor public Student(String name, int rollNo) { this.name = name; this.rollNo = rollNo; System.out.println("Parameterized constructor called for " + name); } // 3. Copy Constructor (by convention, not a distinct type in Java syntax) public Student(Student other) { this.name = other.name; this.rollNo = other.rollNo; System.out.println("Copy constructor called for " + this.name); } // Private constructor example (for Singleton pattern or utility classes) private Student(String secretName) { this.name = secretName; this.rollNo = -1; System.out.println("Private constructor called for internal use."); } public void display() { System.out.println("Name: " + name + ", Roll No: " + rollNo); } // Example of a static factory method to access a private constructor public static Student createSecretStudent(String secretName) { return new Student(secretName); } } public class ConstructorDemo { public static void main(String[] args) { Student s1 = new Student(); // Calls default constructor s1.display(); Student s2 = new Student("Alice", 101); // Calls parameterized constructor s2.display(); Student s3 = new Student(s2); // Calls copy constructor s3.display(); // Student s4 = new Student("Secret"); // Compile-time error: private constructor Student s4 = Student.createSecretStudent("Agent X"); // Access via static factory method s4.display(); } } 12. Describe Polymorphism. Explain Advantage and Disadvantage [ Explain with code] Polymorphism means "many forms". In OOP, it refers to the ability of an object to take on many forms. Specifically, it allows objects of different classes to be treated as objects of a common type. The most common use of polymorphism in Java occurs when a parent class reference is used to refer to a child class object. It is primarily achieved through: Method Overloading (Compile-time/Static Polymorphism): Defining multiple methods in the same class with the same name but different parameters. Method Overriding (Runtime/Dynamic Polymorphism): A subclass providing a specific implementation for a method that is already defined in its parent class. Advantages: Code Reusability: A single interface can be used for different data types. Flexibility and Extensibility: New classes can be added without modifying existing code, as long as they adhere to the common interface/parent class. Reduced Coupling: Code becomes less dependent on specific implementations. Easier Debugging: Issues related to behavior are often localized to the specific implementation. Disadvantages: Complexity: Can sometimes make code harder to understand initially, especially with deep inheritance hierarchies or extensive use of interfaces. Performance Overhead (Minor): Dynamic method dispatch (runtime polymorphism) has a slight performance overhead compared to static binding, though this is usually negligible in modern JVMs. // Example of Method Overloading (Compile-time Polymorphism) class Adder { int add(int a, int b) { return a + b; } int add(int a, int b, int c) { // Same method name, different parameters return a + b + c; } double add(double a, double b) { // Same method name, different parameter types return a + b; } } // Example of Method Overriding (Runtime Polymorphism) class Animal { void makeSound() { System.out.println("Animal makes a sound"); } } class Cat extends Animal { @Override void makeSound() { // Overriding parent method System.out.println("Cat meows"); } void scratch() { System.out.println("Cat scratches"); } } class Dog extends Animal { @Override void makeSound() { // Overriding parent method System.out.println("Dog barks"); } } public class PolymorphismDemo { public static void main(String[] args) { // Overloading Demo Adder adder = new Adder(); System.out.println("Sum of 2 ints: " + adder.add(5, 10)); System.out.println("Sum of 3 ints: " + adder.add(5, 10, 15)); System.out.println("Sum of 2 doubles: " + adder.add(5.5, 10.5)); // Overriding and Runtime Polymorphism Demo Animal myAnimal = new Animal(); myAnimal.makeSound(); // Output: Animal makes a sound Animal myCat = new Cat(); // Parent class reference, child class object myCat.makeSound(); // Output: Cat meows (Runtime polymorphism in action) // myCat.scratch(); // Compile-time error: 'Animal' reference doesn't know 'scratch' Animal myDog = new Dog(); // Parent class reference, child class object myDog.makeSound(); // Output: Dog barks // Array of Animal references, holding different animal objects Animal[] pets = new Animal[3]; pets[0] = new Animal(); pets[1] = new Cat(); pets[2] = new Dog(); System.out.println("\nSounds from pets array:"); for (Animal pet : pets) { pet.makeSound(); // Each call invokes the appropriate overridden method } } } 13. Difference between Aggregation and Generalization. Aggregation: (Part-whole relationship) A specialized form of association that represents a "has-a" or "part-of" relationship where the child object can exist independently of the parent. It's a weak form of ownership. Example: A Car has Wheels . If the car is destroyed, the wheels might still exist and be used on another car. Generalization (Inheritance): (Is-a relationship) A relationship between a general class (superclass/parent) and a more specific class (subclass/child). The subclass inherits properties and behaviors from the superclass. It represents an "is-a" kind of relationship. Example: A Cat is an Animal . A Dog is an Animal . If the Animal class defines basic animal behaviors, Cat and Dog inherit them. 14. What is Parameter passing? Define call by value and call by reference explain with code Parameter passing is the mechanism by which arguments are passed to a function or method. It defines how data is transferred between the caller and the called method. Call by Value: A copy of the actual argument's value is passed to the method. Any changes made to the parameter inside the method do not affect the original argument in the calling method. In Java, all primitive types ( int , char , boolean , float , double , etc.) are passed by value. Call by Reference: The memory address (reference) of the actual argument is passed to the method. Changes made to the parameter inside the method directly affect the original argument in the calling method, because both refer to the same memory location. Java does not support pure call by reference for objects in the same way C++ does. Instead, Java passes object references by value. This means a copy of the reference is passed. The copy still points to the same object in memory, so changes to the object's state (its instance variables) via the copy will affect the original object. However, if you reassign the parameter reference to a new object inside the method, the original reference in the caller remains unchanged. class Data { int value; Data(int val) { this.value = val; } } public class ParameterPassingDemo { // Call by Value for Primitive Type static void changePrimitive(int num) { System.out.println(" Inside changePrimitive: num before change = " + num); num = 20; // This changes only the copy of 'a' System.out.println(" Inside changePrimitive: num after change = " + num); } // Call by Value for Object Reference static void changeObjectValue(Data dataObj) { System.out.println(" Inside changeObjectValue: dataObj.value before change = " + dataObj.value); dataObj.value = 200; // This changes the state of the object that 'd1' also refers to System.out.println(" Inside changeObjectValue: dataObj.value after change = " + dataObj.value); } // Illustrating that reference itself is passed by value static void reassignReference(Data dataObj) { System.out.println(" Inside reassignReference: dataObj hashcode before reassign = " + dataObj.hashCode()); dataObj = new Data(300); // 'dataObj' parameter now points to a new object System.out.println(" Inside reassignReference: dataObj hashcode after reassign = " + dataObj.hashCode()); System.out.println(" Inside reassignReference: dataObj.value = " + dataObj.value); } public static void main(String[] args) { // Primitive Type (Call by Value) int a = 10; System.out.println("Before changePrimitive: a = " + a); changePrimitive(a); System.out.println("After changePrimitive: a = " + a); // 'a' is still 10 System.out.println("\n-----------------------------------\n"); // Object Reference (passed by value, but points to same object) Data d1 = new Data(100); System.out.println("Before changeObjectValue: d1.value = " + d1.value); changeObjectValue(d1); System.out.println("After changeObjectValue: d1.value = " + d1.value); // d1.value is now 200 System.out.println("\n-----------------------------------\n"); // Object Reference (reassigning reference inside method) Data d2 = new Data(1000); System.out.println("Before reassignReference: d2.value = " + d2.value); System.out.println("Before reassignReference: d2 hashcode = " + d2.hashCode()); reassignReference(d2); System.out.println("After reassignReference: d2.value = " + d2.value); // d2.value is still 1000 System.out.println("After reassignReference: d2 hashcode = " + d2.hashCode()); // Same hashcode as before call } } 15. Characteristics of Abstract keyword. explain abstract class with program The abstract keyword in Java is used to achieve abstraction. It can be applied to classes and methods. Abstract Class: A class declared with the abstract keyword. Cannot be instantiated directly (you cannot create objects of an abstract class). Can contain both abstract methods (without body) and concrete methods (with body). Can have constructors, but they are typically called by subclass constructors via super() . Must be extended by other classes, and if a concrete subclass extends an abstract class, it must provide implementations for all inherited abstract methods. If it doesn't, it must also be declared abstract. Abstract Method: A method declared with the abstract keyword and has no body (no implementation). Must be declared inside an abstract class. Subclasses are forced to provide an implementation for abstract methods, ensuring a common interface while allowing different behaviors. abstract class Vehicle { String brand; int year; public Vehicle(String brand, int year) { this.brand = brand; this.year = year; } // Abstract method: every vehicle moves, but how it moves differs public abstract void move(); // Concrete method: common behavior for all vehicles public void displayInfo() { System.out.println("Brand: " + brand + ", Year: " + year); } } class Car extends Vehicle { public Car(String brand, int year) { super(brand, year); } @Override public void move() { System.out.println("Car drives on roads."); } } class Boat extends Vehicle { public Boat(String brand, int year) { super(brand, year); } @Override public void move() { System.out.println("Boat sails on water."); } } public class AbstractClassDemo { public static void main(String[] args) { // Vehicle myVehicle = new Vehicle("Generic", 2020); // Compile-time error: Cannot instantiate abstract class Car myCar = new Car("Toyota", 2022); myCar.displayInfo(); myCar.move(); Boat myBoat = new Boat("Yamaha", 2021); myBoat.displayInfo(); myBoat.move(); // Polymorphic usage Vehicle anotherVehicle = new Car("Honda", 2023); anotherVehicle.displayInfo(); anotherVehicle.move(); // Calls Car's move() } } 16. Difference between throw & throws Feature throw throws Keyword purpose Used to explicitly throw an exception from a method or block. Used in the method signature to declare that a method might throw one or more specified exceptions. Usage Used within the method body. Used with the method signature. Argument Requires an instance of Throwable (e.g., throw new IOException("Error"); ). Requires a class name of the exception (e.g., void myMethod() throws IOException {} ). Count Used to throw a single exception. Can declare multiple exceptions, separated by commas. Checked exception Cannot throw a checked exception unless it's handled or declared in method signature. Mandatory for checked exceptions if not handled by try-catch . import java.io.IOException; public class ThrowThrowsDemo { // Using 'throws' to declare checked exception public static void readFile(String filePath) throws IOException { if (filePath == null || filePath.isEmpty()) { // Using 'throw' to create and throw an exception throw new IOException("File path cannot be null or empty."); } System.out.println("Attempting to read file: " + filePath); // Simulate file reading logic // In a real scenario, this might involve FileReader which throws IOException } public static void main(String[] args) { try { readFile("myFile.txt"); readFile(null); // This will throw an IOException } catch (IOException e) { System.err.println("Caught an IOException: " + e.getMessage()); } // Example of unchecked exception (RuntimeException) - no 'throws' needed try { int result = divide(10, 0); System.out.println("Result: " + result); } catch (ArithmeticException e) { System.err.println("Caught an ArithmeticException: " + e.getMessage()); } } public static int divide(int a, int b) { // No 'throws' needed for unchecked exceptions if (b == 0) { throw new ArithmeticException("Division by zero is not allowed."); } return a / b; } } 17. Difference between final and finally and finalize Feature final finally finalize() Keyword/Method Keyword Block in try-catch Method of Object class Purpose Makes entities unchangeable (variable, method, class). Ensures a block of code is executed regardless of whether an exception occurs or not. Used by garbage collector to perform cleanup operations on an object before it is garbage collected. When executed During compilation/initialization. Always executed after try block, or after catch block if an exception occurred. Called by Garbage Collector just before an object is destroyed. Not guaranteed to be called. Usage Context Variables, methods, classes. Exception handling ( try-catch-finally ). Object lifecycle management (deprecated since Java 9). public class FinalFinallyFinalizeDemo { public static void main(String[] args) { // final variable final int MAX_VALUE = 100; // MAX_VALUE = 200; // Compile-time error // final method (implicitly covered by no override in subclasses) // final class (implicitly covered by no extension) // finally block try { int result = 10 / 0; // ArithmeticException System.out.println("Result: " + result); } catch (ArithmeticException e) { System.err.println("Caught exception: " + e.getMessage()); } finally { System.out.println("Finally block executed."); // Always executes } System.out.println("\nCreating objects for finalize demo..."); new FinalizeExample(1); new FinalizeExample(2); // Requesting garbage collection, but no guarantee when/if finalize will be called System.gc(); System.out.println("GC requested. Program continues..."); // Keep main thread alive for a moment to allow GC to run (not guaranteed) try { Thread.sleep(1000); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } } class FinalizeExample { int id; FinalizeExample(int id) { this.id = id; System.out.println("FinalizeExample object " + id + " created."); } @Override protected void finalize() throws Throwable { try { System.out.println("Finalize method called for object " + id + " (cleanup operations here)."); } finally { super.finalize(); } } } 18. Create a package and write a java file with four methods for four basic Arithmetic operations such as addition, subtraction, multiplication and division. These methods should save the file in the package. Write one more program that imports the above file to use those four methods. Step 1: Create a directory structure for the package. Suppose your project root is myproject . Create: myproject/com/mymath/ Step 2: Create Calculator.java inside com/mymath/ . // File: myproject/com/mymath/Calculator.java package com.mymath; // Declares this class belongs to 'com.mymath' package public class Calculator { public static int add(int a, int b) { return a + b; } public static int subtract(int a, int b) { return a - b; } public static int multiply(int a, int b) { return a * b; } public static double divide(int a, int b) { if (b == 0) { throw new IllegalArgumentException("Division by zero is not allowed."); } return (double) a / b; } } Step 3: Create MathApp.java in the myproject root or another package. // File: myproject/MathApp.java import com.mymath.Calculator; // Imports the Calculator class from com.mymath package public class MathApp { public static void main(String[] args) { int num1 = 20; int num2 = 5; System.out.println("Addition: " + Calculator.add(num1, num2)); System.out.println("Subtraction: " + Calculator.subtract(num1, num2)); System.out.println("Multiplication: " + Calculator.multiply(num1, num2)); System.out.println("Division: " + Calculator.divide(num1, num2)); try { System.out.println("Division by zero: " + Calculator.divide(num1, 0)); } catch (IllegalArgumentException e) { System.err.println("Error: " + e.getMessage()); } } } Step 4: Compile and Run from myproject directory. # Compile Calculator.java javac com/mymath/Calculator.java # Compile MathApp.java (it will find Calculator.class) javac MathApp.java # Run MathApp java MathApp Module-3: Advanced OOP Concepts 19. What is exceptions ? Explain the user defined exception and system defined exceptions with suitable examples [ concept try & catch block] [concept Exception handling]. Exceptions: An exception is an event that disrupts the normal flow of a program's instructions. When an error occurs within a method, it creates an object and hands it off to the runtime system. This object, called an exception object, contains information about the error, including its type and the state of the program when the error occurred. Exception Handling: It is a mechanism to handle runtime errors so that the normal flow of the program can be maintained. Java's exception handling is managed via five keywords: try , catch , finally , throw , and throws . try block: Contains the code that might throw an exception. catch block: Catches and handles the exception thrown by the try block. Types of Exceptions: System Defined (Built-in) Exceptions: Checked Exceptions: Exceptions that are checked at compile time. The compiler forces the programmer to handle these exceptions (e.g., IOException , SQLException , ClassNotFoundException ). Unchecked Exceptions (Runtime Exceptions): Exceptions that are not checked at compile time. They occur due to programming errors (e.g., ArithmeticException , NullPointerException , ArrayIndexOutOfBoundsException ). User Defined Exceptions: Programmers can create their own custom exception classes by extending the Exception class (for checked exceptions) or RuntimeException class (for unchecked exceptions). import java.io.File; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; // User-defined checked exception class InvalidAgeException extends Exception { public InvalidAgeException(String message) { super(message); } } public class ExceptionHandlingDemo { public static void validateAge(int age) throws InvalidAgeException { if (age 20. Explain this keyword and Super keyword. Difference between "==" operator and "equals" methods in the context of string object this keyword: Refers to the current object. Can be used to refer to current class instance variables (e.g., this.variable = variable to resolve ambiguity between instance variable and parameter). Can be used to invoke current class methods (e.g., this.method() ). Can be used to invoke current class constructors (constructor chaining: this(args) ). Can be passed as an argument in the method call or constructor call. Can be used to return the current class instance from the method. super keyword: Refers to the immediate parent class object. Can be used to refer to immediate parent class instance variables (e.g., super.variable ). Can be used to invoke immediate parent class methods (e.g., super.method() ). Can be used to invoke immediate parent class constructors (e.g., super(args) ). Must be the first statement in the constructor. Difference between == operator and .equals() method for String objects: == operator: Compares object references. It checks if two references point to the exact same object in memory. For primitive types, it compares their actual values. For String objects, str1 == str2 is true only if str1 and str2 refer to the same String object (e.g., if they are the same literal or one is assigned from the other without creating a new object). .equals() method: Compares the content (value) of two objects. The String class overrides the equals() method (inherited from Object ) to compare the actual character sequences of the strings. For String objects, str1.equals(str2) is true if both strings have the same sequence of characters. class Parent { int value = 10; Parent() { System.out.println("Parent constructor."); } void display() { System.out.println("Parent value: " + value); } } class Child extends Parent { int value = 20; // Hides parent's value, doesn't override it Child() { // super(); // Implicitly called if no other super() or this() is present System.out.println("Child constructor."); } void showValues(int value) { // Parameter 'value' System.out.println("Local value: " + value); // refers to parameter System.out.println("Child's instance value: " + this.value); // refers to Child's instance variable System.out.println("Parent's instance value: " + super.value); // refers to Parent's instance variable } @Override void display() { super.display(); // Invokes parent's display method System.out.println("Child's display method."); } } public class KeywordComparison { public static void main(String[] args) { Child c = new Child(); c.showValues(30); c.display(); System.out.println("\n--- String Comparison ---"); String s1 = "hello"; String s2 = "hello"; // s1 and s2 refer to the same string literal in String Pool String s3 = new String("hello"); // s3 is a new object in heap, even if content is same String s4 = "world"; System.out.println("s1 == s2: " + (s1 == s2)); // true (same object in pool) System.out.println("s1 == s3: " + (s1 == s3)); // false (different objects) System.out.println("s1.equals(s2): " + s1.equals(s2)); // true (same content) System.out.println("s1.equals(s3): " + s1.equals(s3)); // true (same content) System.out.println("s1.equals(s4): " + s1.equals(s4)); // false (different content) } } 21. How Applet is different from frame and panel. Explain. How threads are made to communicate each other? Explain with example [2023] Applet vs. Frame vs. Panel (AWT/Swing Context): Applet: A small Java program that can be embedded in an HTML page and executed in a web browser. Extends java.applet.Applet (or javax.swing.JApplet for Swing). Has a lifecycle managed by the browser (init, start, paint, stop, destroy). Cannot run independently; requires a browser or applet viewer. Has security restrictions (sandbox model). Largely deprecated due to security concerns and rise of web technologies. Frame ( java.awt.Frame / javax.swing.JFrame ): A top-level window with a title bar, borders, and window controls (minimize, maximize, close). Can run as a standalone application. Acts as the main container for other GUI components (like panels, buttons, text fields). Does not need to be embedded in an HTML page. Panel ( java.awt.Panel / javax.swing.JPanel ): A generic lightweight container. Cannot exist on its own; must be placed inside another container (like a Frame or another Panel). Used to group related components together logically or for layout purposes. Does not have a title bar, borders, or window controls. Summary: An Applet is for web embedding, a Frame is a top-level application window, and a Panel is a sub-container used within Frames or Applets. How threads are made to communicate with each other? Threads often need to communicate to coordinate their actions, especially when sharing resources or when one thread needs to wait for another to complete a task or produce data. Java provides several mechanisms for inter-thread communication: wait() , notify() , notifyAll() methods (from Object class): These methods are used within synchronized blocks/methods. wait() : Causes the current thread to release the lock on the object and go into a waiting state until another thread invokes notify() or notifyAll() on the same object. notify() : Wakes up a single waiting thread on that object. notifyAll() : Wakes up all waiting threads on that object. Crucial: These methods must be called from a synchronized context (i.e., the thread must own the object's monitor). join() method: A thread can call join() on another thread. This makes the calling thread wait until the specified thread terminates. interrupt() method: Used to interrupt a thread. It sets the interrupted status of the thread. A thread can check its interrupted status and respond accordingly (e.g., by stopping its work). Piped Streams: Used for inter-thread communication where one thread writes data to a pipe and another thread reads from it. High-Level Concurrency Utilities (Java 5+): java.util.concurrent package: Provides more robust and flexible alternatives like BlockingQueue , CountDownLatch , CyclicBarrier , Exchanger , Semaphore , Lock interface (with Condition objects as replacements for wait/notify ). Example using wait() and notify() (Producer-Consumer problem): import java.util.LinkedList; import java.util.Queue; public class ProducerConsumerDemo { private static final int CAPACITY = 5; private final Queue<Integer> buffer = new LinkedList<>(); private final Object lock = new Object(); // Object to synchronize on class Producer extends Thread { @Override public void run() { int value = 0; while (true) { synchronized (lock) { while (buffer.size() == CAPACITY) { try { System.out.println("Producer: Buffer is full, waiting..."); lock.wait(); // Producer waits if buffer is full } catch (InterruptedException e) { Thread.currentThread().interrupt(); return; } } buffer.add(value); System.out.println("Producer: Produced " + value); value++; lock.notifyAll(); // Notify consumers that new data is available } try { Thread.sleep(100); // Simulate work } catch (InterruptedException e) { Thread.currentThread().interrupt(); return; } } } } class Consumer extends Thread { @Override public void run() { while (true) { synchronized (lock) { while (buffer.isEmpty()) { try { System.out.println("Consumer: Buffer is empty, waiting..."); lock.wait(); // Consumer waits if buffer is empty } catch (InterruptedException e) { Thread.currentThread().interrupt(); return; } } int consumedValue = buffer.remove(); System.out.println("Consumer: Consumed " + consumedValue); lock.notifyAll(); // Notify producers that space is available } try { Thread.sleep(200); // Simulate work } catch (InterruptedException e) { Thread.currentThread().interrupt(); return; } } } } public static void main(String[] args) { ProducerConsumerDemo pc = new ProducerConsumerDemo(); Thread producerThread = pc.new Producer(); Thread consumerThread = pc.new Consumer(); producerThread.start(); consumerThread.start(); } } 22. Short Note : (a) Dynamic Method Dispatch. (b) Co-Variant Return (a) Dynamic Method Dispatch (Runtime Polymorphism): Dynamic method dispatch is the mechanism by which a call to an overridden method is resolved at runtime rather than compile time. When a superclass reference variable refers to a subclass object, and an overridden method is called using that reference, the JVM determines which version of the method to execute based on the actual type of the object at runtime, not the type of the reference variable. This is a core concept behind method overriding and polymorphism in Java. class A { void show() { System.out.println("Inside A's show()"); } } class B extends A { @Override void show() { System.out.println("Inside B's show()"); } } class C extends A { @Override void show() { System.out.println("Inside C's show()"); } } public class DMDemo { public static void main(String args[]) { A ref; // A reference variable A a = new A(); B b = new B(); C c = new C(); ref = a; // ref refers to an A object ref.show(); // Calls A's show() ref = b; // ref refers to a B object ref.show(); // Calls B's show() - Dynamic dispatch here! ref = c; // ref refers to a C object ref.show(); // Calls C's show() - Dynamic dispatch here! } } (b) Covariant Return Types: Prior to Java 5, when overriding a method, the return type of the overriding method had to be exactly the same as the return type of the overridden method in the superclass. Since Java 5, covariant return types are allowed. This means that an overriding method can return a subtype of the type returned by the overridden method in the superclass. This enhances flexibility and type safety, as it allows methods to return more specific types while maintaining the parent-child relationship. class Vehicle { Vehicle getVehicle() { System.out.println("Returning a Vehicle object."); return new Vehicle(); } } class Car extends Vehicle { @Override Car getVehicle() { // Covariant return type: Car is a subtype of Vehicle System.out.println("Returning a Car object."); return new Car(); } } public class CovariantReturnDemo { public static void main(String[] args) { Vehicle v = new Vehicle(); Vehicle vehicleObj = v.getVehicle(); // Returns Vehicle Car c = new Car(); Car carObj = c.getVehicle(); // Returns Car (more specific type) // Polymorphic usage Vehicle polyVehicle = new Car(); Vehicle result = polyVehicle.getVehicle(); // Returns Car, but assigned to Vehicle reference System.out.println("Poly Vehicle result type: " + result.getClass().getName()); } } 23. Instance Block vs Static Block Feature Instance Initialization Block Static Initialization Block Keyword No specific keyword (just {} ) static {} Execution Timing Executed every time an object of the class is created, after constructors. Executed only once, when the class is loaded into the JVM. Purpose Used to initialize instance variables, common initialization logic for all constructors. Used to initialize static variables, perform one-time setup when the class is loaded. Access Can access both static and non-static members. Can only access static members. Number of runs Runs for each object created. Runs only once per class load. class BlockDemo { static { System.out.println("1. Static block executed (first)"); } { // Instance initialization block System.out.println("3. Instance block executed (before constructor)"); } BlockDemo() { System.out.println("4. Constructor executed"); } static { System.out.println("2. Second static block executed"); // Static blocks execute in order } } public class BlockExample { public static void main(String[] args) { System.out.println("Main method started."); BlockDemo obj1 = new BlockDemo(); System.out.println("Object 1 created.\n"); BlockDemo obj2 = new BlockDemo(); System.out.println("Object 2 created."); } } /* Output: 1. Static block executed (first) 2. Second static block executed Main method started. 3. Instance block executed (before constructor) 4. Constructor executed Object 1 created. 3. Instance block executed (before constructor) 4. Constructor executed Object 2 created. */ 24. Explain Encapsulation Encapsulation is one of the four fundamental principles of Object-Oriented Programming. It refers to the bundling of data (attributes) and the methods that operate on that data within a single unit, typically a class. It also involves restricting direct access to some of an object's components, meaning that the internal representation of an object is hidden from the outside. This is often achieved through the use of access modifiers (like private ) for variables and providing public methods (getters and setters) to access and modify those variables. Key aspects: Data Hiding: Protecting the internal state of an object by making its instance variables private . This prevents direct external manipulation of data. Abstraction: While not the same, encapsulation supports abstraction by hiding the "how" an object stores and manipulates its data, exposing only the "what" (its public API). Control: Getters and setters provide controlled access to data, allowing for validation or other logic before data is read or modified. Flexibility: The internal implementation can be changed without affecting the external code that uses the class, as long as the public interface remains consistent. Advantages: Security: Prevents unauthorized access or modification of data. Maintainability: Changes to the internal implementation of a class do not impact other parts of the code. Flexibility: Provides control over how data is accessed and modified. Modularity: Makes classes self-contained and easier to understand and reuse. class Employee { private String name; // Private data - encapsulated private double salary; // Private data - encapsulated public Employee(String name, double salary) { this.name = name; if (salary > 0) { this.salary = salary; } else { this.salary = 0; // Default or error handling } } // Public getter method for name public String getName() { return name; } // Public setter method for name public void setName(String name) { this.name = name; } // Public getter method for salary public double getSalary() { return salary; } // Public setter method for salary with validation public void setSalary(double salary) { if (salary > 0) { // Controlled modification this.salary = salary; } else { System.out.println("Salary cannot be negative. Not updated."); } } public void displayEmployeeDetails() { System.out.println("Employee Name: " + name + ", Salary: $" + salary); } } public class EncapsulationDemo { public static void main(String[] args) { Employee emp = new Employee("John Doe", 50000); emp.displayEmployeeDetails(); // Direct access to private fields is not possible (compile-time error) // emp.salary = 60000; // Access and modify via public methods (controlled access) emp.setSalary(55000); emp.displayEmployeeDetails(); emp.setSalary(-1000); // Validation in setter prevents invalid data emp.displayEmployeeDetails(); System.out.println("Employee's name: " + emp.getName()); } } Module-4: Java Virtual Machine (JVM) & Concurrency 1. What is JVM ? (Java Virtual Machine) The Java Virtual Machine (JVM) is an abstract machine that provides a runtime environment in which Java bytecode can be executed. It's a key component of the Java platform that enables Java's "Write Once, Run Anywhere" (WORA) capability. Function: The JVM reads .class files (which contain Java bytecode), interprets or compiles them into machine-specific instructions, and then executes those instructions. Platform Independence: Since the JVM is platform-dependent (there's a specific JVM implementation for Windows, Linux, macOS, etc.), the same Java bytecode can run on any operating system that has a compatible JVM. Key Components: Classloader: Loads .class files into memory. Method Area: Stores class structures, method data, static variables. Heap: Runtime data area where objects are allocated. Stack: Stores method call frames (local variables, operand stack, frame data). Each thread has its own stack. PC Registers: Stores the address of the next instruction to be executed for each thread. Native Method Stack: Stores native method information. Execution Engine: Executes the bytecode, including Interpreter, JIT Compiler, and Garbage Collector. 2. Discuss garbage collection procedure in Java Garbage Collection (GC) is an automatic memory management process in Java that reclaims memory occupied by objects that are no longer referenced by the program (i.e., "dead" or "unreachable" objects). This frees programmers from explicitly deallocating memory, reducing memory leaks and simplifying development. Procedure (Simplified): Marking: The GC identifies all live (reachable) objects in the heap. It starts from a set of "GC Roots" (like currently executing methods' local variables, active threads, static variables) and traverses the object graph, marking all objects it can reach. Sweeping: After marking, the GC sweeps through the heap and deletes all unmarked (unreachable/dead) objects. Compacting (Optional): Some garbage collectors also perform compaction, which moves live objects closer together in memory. This reduces fragmentation and makes larger contiguous blocks of free memory available for new object allocations. Generational Garbage Collection: Modern JVMs use generational GC, dividing the heap into generations (e.g., Young Generation, Old Generation, Permanent Generation/Metaspace). Objects are initially allocated in the Young Generation. Most objects die young. Objects that survive multiple GC cycles ("minor GCs") are promoted to the Old Generation. The Old Generation is cleaned less frequently by "major GCs." This approach is efficient because it leverages the "weak generational hypothesis" (most objects are short-lived, few objects are long-lived). 3. Why Java is called Compiler Interpreter language? Java is often referred to as both a compiled and an interpreted language because its execution process involves both compilation and interpretation (or Just-In-Time compilation). Compilation Phase: Java source code ( .java files) is first compiled into bytecode ( .class files) by the Java compiler ( javac ). This bytecode is a platform-independent, intermediate representation. Interpretation/Execution Phase: The JVM (Java Virtual Machine) then takes this bytecode. It can either interpret the bytecode instruction by instruction, or more commonly, use a Just-In-Time (JIT) compiler to translate frequently executed bytecode into native machine code at runtime. The JIT compiler optimizes performance by compiling hot spots (frequently used code) into native code, which then runs directly on the underlying hardware, providing near-native performance. So, Java is "compiled" to bytecode, and that bytecode is then "interpreted" or "JIT-compiled" by the JVM. This two-step process is what gives Java its platform independence and good performance. 4. What is thread? How to create Thread? Explain Thread life cycle*** A thread is a lightweight sub-process, the smallest unit of processing. It's a separate path of execution within a program. Threads allow a program to perform multiple tasks concurrently, improving application responsiveness and resource utilization. How to Create a Thread in Java: There are two main ways to create a thread: By extending the Thread class: Create a class that extends java.lang.Thread . Override the run() method, which contains the code that the thread will execute. Create an instance of your class and call its start() method. class MyThread extends Thread { @Override public void run() { for (int i = 0; i < 5; i++) { System.out.println(Thread.currentThread().getName() + ": " + i); try { Thread.sleep(100); } catch (InterruptedException e) {} } } } // Usage: new MyThread().start(); By implementing the Runnable interface: (Recommended, as it allows your class to extend another class) Create a class that implements java.lang.Runnable . Override the run() method. Create an instance of your class. Create a Thread object, passing your Runnable instance to its constructor. Call the start() method of the Thread object. class MyRunnable implements Runnable { @Override public void run() { for (int i = 0; i < 5; i++) { System.out.println(Thread.currentThread().getName() + ": " + i); try { Thread.sleep(100); } catch (InterruptedException e) {} } } } // Usage: Thread t = new Thread(new MyRunnable()); t.start(); Thread Life Cycle: A thread in Java goes through various states from its creation to its termination. These states are defined in the Thread.State enum: NEW: The thread has been created but has not yet started. It's in this state after instantiation but before start() is called. RUNNABLE: The thread is executing in the JVM. It may be running or waiting for CPU time from the operating system's scheduler. After start() is called, it enters this state. BLOCKED: A thread is blocked when it is waiting for a monitor lock to enter a synchronized block/method or reenter a synchronized block/method after calling wait() . WAITING: A thread is in a waiting state when it's waiting indefinitely for another thread to perform a particular action (e.g., calling wait() without a timeout, join() without a timeout, Lock.lock() ). TIMED_WAITING: A thread is in a timed waiting state when it's waiting for another thread to perform a specific action for a specified waiting time (e.g., sleep(millis) , wait(millis) , join(millis) ). TERMINATED: The thread has finished its execution, either normally ( run() method completes) or due to an unhandled exception. The thread object is still there, but it's no longer alive. NEW RUNNABLE BLOCKED WAITING TIMED_WAITING TERMINATED start() synchronized(obj) acquiring lock lock released sleep() / wait(t) timeout / notify() lock acquired wait() notify() / notifyAll() run() completes run() completes run() completes run() completes Module-5: UI, Concurrency & Collections 5. What does finalize() method do? The finalize() method (from the java.lang.Object class) is a special method that the Java Garbage Collector calls on an object just before it is garbage collected. Its primary purpose is to perform cleanup operations on external resources that the object might be holding (e.g., closing file streams, releasing network connections, freeing native memory). It's essentially a last chance for an object to clean up before being destroyed. Important Considerations: Not Guaranteed: There is no guarantee that finalize() will be called for every object before the program exits or even that it will be called in a timely manner. The Garbage Collector runs opportunistically. Performance Overhead: Using finalize() can introduce performance overhead because objects with finalize() methods take longer to garbage collect. Deprecation: The finalize() method is deprecated since Java 9 because of its unpredictable behavior and performance issues. Modern Java applications should prefer other mechanisms for resource management, such as try-with-resources for resources that implement AutoCloseable , or explicit cleanup methods. 6. Discuss shortly Model Viewer Controller. Disadvantage of MVC pattern The Model-View-Controller (MVC) is an architectural pattern that separates an application into three main logical components: Model: Represents the application's data, business logic, and rules. It is independent of the user interface. When the model's state changes, it notifies the associated views. View: Displays the data from the model to the user. It is responsible for the presentation layer. It observes the model for changes and updates itself accordingly. It typically sends user input to the controller. Controller: Handles user input and interactions. It receives input from the view, processes it (often by invoking operations on the model), and then updates the model and/or selects a view to display the result. It acts as an intermediary between the Model and View. Disadvantages of MVC Pattern: Increased Complexity: For simple applications, the separation into three components can introduce unnecessary complexity and overhead compared to a monolithic design. Steep Learning Curve: Understanding the interactions between Model, View, and Controller, especially for beginners, can be challenging. View-Controller Coupling: In some implementations, the View and Controller can become tightly coupled, making them less reusable independently. Maintenance Overhead: Keeping the three components synchronized and ensuring proper communication can be demanding for large applications. Testability Challenges: Testing complex interactions between components, especially the View and Controller, can sometimes be tricky. Not always a perfect fit: For certain types of applications (e.g., highly interactive, complex UI-driven apps), other patterns like MVVM (Model-View-ViewModel) or MVP (Model-View-Presenter) might be a better fit. 7. What are Wrapper class? Why do we need Wrapper classes? What is byte code? [2022] Wrapper Classes: In Java, primitive data types ( int , char , boolean , double , etc.) are not objects. Wrapper classes provide a way to use primitive data types as objects. For each primitive type, there is a corresponding wrapper class (e.g., Integer for int , Character for char , Boolean for boolean , Double for double ). They reside in the java.lang package. Java provides automatic conversion between primitive types and their corresponding wrapper classes ( Autoboxing for primitive to wrapper, Unboxing for wrapper to primitive). Why do we need Wrapper classes? Collections Framework: Java's Collections Framework (e.g., ArrayList , HashMap ) can only store objects, not primitive types. Wrapper classes allow primitives to be stored in collections. Generics: Generic types (e.g., List<Integer> ) require type parameters to be objects. Null Values: Wrapper class objects can hold a null value, which isn't possible for primitive types. Utility Methods: Wrapper classes provide useful utility methods (e.g., Integer.parseInt() , Double.valueOf() ) for conversions and other operations. Serialization: If an object needs to be serialized, all its fields must be objects. What is bytecode? Bytecode is a set of instructions that are executed by the Java Virtual Machine (JVM). It is the intermediate code generated by the Java compiler ( javac ) from Java source code ( .java files). It is stored in .class files. Bytecode is platform-independent, meaning the same .class file can be executed on any operating system that has a compatible JVM installed. The JVM translates this bytecode into native machine code at runtime (either by interpretation or JIT compilation). 8. Short Note: Multithreading, Synchronization . Multithreading: The ability of a program or an operating system to manage multiple user requests simultaneously. Within a single program, it allows multiple parts of the program to execute concurrently. Each part (thread) runs independently and can perform different tasks at the same time, sharing the same memory space and resources of the parent process. Advantages: Improved responsiveness, better resource utilization, reduced overhead compared to multiple processes. Disadvantages: Increased complexity in programming, potential for race conditions, deadlocks, and other concurrency issues. Synchronization: The process of controlling the access of multiple threads to shared resources. Without synchronization, multiple threads could try to access and modify the same data simultaneously, leading to inconsistent or incorrect results (race conditions). In Java, synchronization is primarily achieved using: synchronized keyword: Can be applied to methods or blocks of code. When a thread enters a synchronized method/block, it acquires a monitor lock on the object (or class, for static methods). Other threads trying to enter the same synchronized method/block on the same object will be blocked until the first thread releases the lock. java.util.concurrent.locks.Lock interface: Provides more flexible and explicit locking mechanisms than the synchronized keyword. Purpose: To ensure data integrity, prevent race conditions, and enable proper inter-thread communication. Module-5: UI, Concurrency & Collections (Continued) 1. Which method is used to set the graphics current color to the specified color in the graphics class? The method used to set the graphics current color in the Graphics class (from java.awt ) is setColor(Color c) . import java.awt.*; import javax.swing.*; class MyDrawingPanel extends JPanel { @Override protected void paintComponent(Graphics g) { super.paintComponent(g); g.setColor(Color.RED); // Set color to red g.fillRect(50, 50, 100, 50); // Draw a red rectangle g.setColor(Color.BLUE); // Set color to blue g.fillOval(150, 150, 80, 80); // Draw a blue oval } } public class SetColorDemo extends JFrame { public SetColorDemo() { setTitle("SetColor Demo"); setSize(300, 300); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); add(new MyDrawingPanel()); setVisible(true); } public static void main(String[] args) { new SetColorDemo(); } } 2. What is AWT (Abstract Window Toolkit)? What is Event Listener? [2022] AWT (Abstract Window Toolkit): AWT is Java's original platform-dependent GUI (Graphical User Interface) toolkit. It provides a set of classes for creating graphical user interfaces, including components like buttons, text fields, labels, frames, and panels. AWT components are "heavyweight," meaning they rely on the underlying operating system's native GUI components (peers). This can lead to platform-specific look and feel issues. It was largely superseded by Swing, which offers "lightweight" (pure Java) components, providing a consistent look and feel across platforms. Event Listener: In GUI programming (AWT, Swing, JavaFX), an event listener is an object that "listens" for specific events (e.g., button clicks, mouse movements, key presses) generated by GUI components. It implements a specific interface (e.g., ActionListener , MouseListener , KeyListener ) that defines methods for handling these events. When an event occurs, the GUI component notifies all registered listeners, and the appropriate event-handling method in the listener is invoked. This is a core part of the event-driven programming model used in GUI applications. import java.awt.*; import java.awt.event.*; import javax.swing.*; public class EventListenerDemo extends JFrame implements ActionListener { private JButton button; private JLabel label; public EventListenerDemo() { setTitle("Event Listener Demo"); setSize(300, 200); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setLayout(new FlowLayout()); button = new JButton("Click Me!"); button.addActionListener(this); // Registering 'this' (JFrame) as the ActionListener label = new JLabel("Button not clicked yet."); add(button); add(label); setVisible(true); } @Override public void actionPerformed(ActionEvent e) { // This method is called when the button is clicked if (e.getSource() == button) { label.setText("Button was clicked!"); System.out.println("Button clicked event received!"); } } public static void main(String[] args) { new EventListenerDemo(); } } 3. Discuss Applet Life cycle with functions. The Applet life cycle refers to the sequence of methods that the browser or applet viewer calls during the execution of an applet. Understanding these methods is crucial for managing applet resources and behavior. init() : The first method called. It's invoked once when the applet is first loaded. Used for one-time initialization, such as setting up the user interface, initializing variables, or loading resources. Similar to a constructor for an application, but takes no arguments. start() : Called after init() and every time the applet becomes active (e.g., when the user navigates back to the page containing the applet). Used to start any threads, animations, or other activities that should run when the applet is visible and active. paint(Graphics g) : Called when the applet needs to be redrawn (e.g., when it's first displayed, resized, or uncovered). Used to perform all drawing operations. You should never call paint() directly; instead, call repaint() , which schedules a call to update() (which in turn calls paint() ). stop() : Called when the applet becomes inactive (e.g., when the user navigates away from the page). Used to pause or stop any ongoing activities like animations or threads to save CPU cycles and resources. destroy() : The last method called. It's invoked once when the applet is about to be unloaded from memory (e.g., when the browser is closed). Used to perform final cleanup, such as releasing resources, closing connections, or saving state. Sequence: init() -> start() -> ( paint() multiple times) -> stop() -> start() (if reactivated) -> stop() -> destroy() . Born Initialized Running Stopped Dead init() start() stop() destroy() start() paint() / repaint() 4. Short notes on Java collection frameworks and Java Generics Java Collections Framework: A set of interfaces and classes that represent groups of objects (collections). It provides a unified architecture for storing and manipulating groups of objects. Interfaces: Collection (root interface) List (ordered, allows duplicates, e.g., ArrayList , LinkedList ) Set (unordered, no duplicates, e.g., HashSet , TreeSet ) Queue (FIFO, e.g., PriorityQueue , ArrayDeque ) Map (key-value pairs, no duplicate keys, e.g., HashMap , TreeMap , LinkedHashMap ) Benefits: Reduces programming effort, increases program speed and quality, allows interoperability between unrelated APIs. Java Generics: A feature introduced in Java 5 that allows types (classes and interfaces) to be parameters when defining classes, interfaces, and methods. Purpose: To enable creation of classes, interfaces, and methods that operate on types that are specified as parameters, improving type safety and reducing the need for type casting. Benefits: Type Safety: Catches type-related errors at compile time rather than runtime. Elimination of Casts: No need to explicitly cast objects retrieved from generic collections. Code Reusability: A single generic class/method can work with different types. Example: Instead of ArrayList list = new ArrayList(); list.add("hello"); String s = (String) list.get(0); , you use ArrayList<String> list = new ArrayList<>(); list.add("hello"); String s = list.get(0); 5. Explain any three events with suitable example [2023] [ concept of JS, html, CSS] This question seems to be mixing Java with web technologies (JS, HTML, CSS). Assuming the context is Java GUI events (AWT/Swing), here are three common events: ActionEvent (e.g., Button Click): Generated when a user performs an action on a component, such as clicking a button, pressing Enter in a text field, or selecting a menu item. Handled by implementing the ActionListener interface and its actionPerformed(ActionEvent e) method. // Example (see EventListenerDemo above for full code) JButton button = new JButton("Click Me!"); button.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { System.out.println("Button clicked!"); } }); MouseEvent (e.g., Mouse Click, Press, Release, Move): Generated when a user interacts with a component using the mouse. Handled by implementing MouseListener (for clicks, presses, releases, enters, exits) or MouseMotionListener (for moves, drags). // Example JPanel panel = new JPanel(); panel.addMouseListener(new MouseAdapter() { // MouseAdapter provides default empty implementations @Override public void mouseClicked(MouseEvent e) { System.out.println("Mouse clicked at (" + e.getX() + ", " + e.getY() + ")"); } }); KeyEvent (e.g., Key Press, Release, Type): Generated when a user presses, releases, or types a key on the keyboard while a component has focus. Handled by implementing the KeyListener interface and its keyPressed(KeyEvent e) , keyReleased(KeyEvent e) , keyTyped(KeyEvent e) methods. // Example JTextField textField = new JTextField(20); textField.addKeyListener(new KeyAdapter() { @Override public void keyTyped(KeyEvent e) { System.out.println("Key typed: " + e.getKeyChar()); } }); If the question truly refers to JS, HTML, CSS, then the answer would be different (e.g., HTML DOM events like onclick , onmouseover , onkeydown , handled by JavaScript functions). 6. Similarities and differences between ArrayList and Vector? Feature ArrayList Vector Synchronization Not synchronized (non-thread-safe) Synchronized (thread-safe) Performance Faster (no synchronization overhead) Slower (due to synchronization) API More modern API (part of Collections Framework) Legacy API (older, from Java 1.0) Growth Rate Increases capacity by 50% when full (approx.) Doubles its capacity when full Usage Preferred for single-threaded environments or when external synchronization is handled. Used in multi-threaded environments where thread safety is paramount and a legacy API is acceptable. Nulls Allows null elements. Allows null elements. Implementations Both implement the List interface and use a dynamic array internally. Similarities: Both ArrayList and Vector implement the List interface, are backed by a dynamic array, maintain insertion order, and allow duplicate elements and null values. 7. Just see Software Development process The Software Development Process (SDP) , also known as the Software Development Life Cycle (SDLC), is a structured framework that describes the stages involved in developing a software product. It provides a roadmap for planning, creating, testing, and deploying an information system. Common phases in a typical SDLC include: Requirement Gathering and Analysis: Understanding and documenting the needs of the users and the system. Involves interviews, surveys, and analysis of existing systems. Output: Software Requirement Specification (SRS) document. Design: Translating requirements into a detailed system design. Includes architectural design, database design, UI/UX design, and algorithm design. Output: Design Specification document (e.g., UML diagrams, data flow diagrams). Implementation/Coding: Writing the actual code based on the design specifications. This phase involves choosing appropriate programming languages, tools, and frameworks. Output: Source code. Testing: Systematically identifying and fixing defects (bugs) in the software. Involves unit testing, integration testing, system testing, and acceptance testing. Output: Test reports, bug reports. Deployment: Making the software available to the end-users. Involves installation, configuration, and release management. Maintenance: Ongoing support for the software after deployment. Includes bug fixes, performance enhancements, and new feature additions based on user feedback or changing requirements. Common SDLC models include Waterfall, Agile, Scrum, DevOps, Iterative, and Spiral, each with its own approach to managing these phases.