0% found this document useful (0 votes)
7 views87 pages

28. (a) Java Virtual Machine (JVM) and Portability

The document covers various Java concepts including the Java Virtual Machine (JVM) and its role in portability, differences between abstract classes and interfaces, garbage collection, access specifiers, encapsulation, and the significance of constructors. It also discusses the use of packages, the super keyword, and the principles of inheritance and code reusability. Additionally, it highlights Java's security features, the handling of command-line arguments, and the distinction between primitive and reference data types.

Uploaded by

jiminej926
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
7 views87 pages

28. (a) Java Virtual Machine (JVM) and Portability

The document covers various Java concepts including the Java Virtual Machine (JVM) and its role in portability, differences between abstract classes and interfaces, garbage collection, access specifiers, encapsulation, and the significance of constructors. It also discusses the use of packages, the super keyword, and the principles of inheritance and code reusability. Additionally, it highlights Java's security features, the handling of command-line arguments, and the distinction between primitive and reference data types.

Uploaded by

jiminej926
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 87

28.

(a) Java Virtual Machine (JVM) and Portability


The Java Virtual Machine (JVM) is a runtime environment that executes Java bytecode. It's the
cornerstone of Java's portability. When you compile a Java program, the Java compiler
translates your source code into an intermediate format called bytecode, which is platform-
independent.
Working of the JVM:
1. Loading: The JVM loads the bytecode of a Java program.
2. Verification: The bytecode verifier checks the bytecode for security and integrity, ensuring
that it doesn't violate any JVM rules.
3. Execution: The JVM executes the bytecode. This can be done through interpretation or
just-in-time (JIT) compilation. JIT compilation involves compiling bytecode into native
machine code during runtime, which can significantly improve performance.
Contribution to Portability:
Java achieves portability through the JVM because the same bytecode can run on any
operating system that has a JVM implementation. As long as a platform has a JVM, a Java
application can run on it without modification. This "write once, run anywhere" capability is a key
feature of Java.
(b) Abstract Class vs. Interface

Feature Abstract Class Interface

Abstract Can have abstract and concrete All methods are implicitly abstract (since Java 5, can
Methods methods have default methods)

Can provide partial Cannot provide implementation (except for default


Implementation
implementation methods in Java 8+)

A class can extend only one


Inheritance A class can implement multiple interfaces
abstract class

Constructors Has constructors No constructors

Variables Can have instance variables Can have static final constants

Example:

// Abstract Class
abstract class Shape {
String color;
abstract double area(); // Abstract method
public String getColor() {
return color;
}
}

// Concrete class extending the abstract class


class Circle extends Shape {
double radius;

public Circle(double radius) {


this.radius = radius;
}

@Override
double area() {
return Math.PI * radius * radius;
}
}

// Interface
interface Drawable {
void draw(); // Abstract method
}

// Class implementing the interface


class Rectangle implements Drawable {
@Override
public void draw() {
System.out.println("Drawing a rectangle");
}
}

29. (a) Garbage Collection in Java


Garbage Collection (GC) is an automatic memory management feature in Java. It reclaims
memory occupied by objects that are no longer in use by the application.
Importance in Memory Management:
Automatic Memory Management: GC automates the process of freeing up memory,
reducing the risk of memory leaks and dangling pointers.
Efficient Memory Utilization: By reclaiming unused memory, GC ensures that memory
resources are used efficiently, preventing applications from running out of memory.
Simplified Development: Developers don't need to manually allocate and deallocate
memory, which simplifies development and reduces the likelihood of memory-related bugs.
(b) Manual vs. Automatic Garbage Collection
It is generally not recommended to manually invoke the garbage collector using System.gc() or
Runtime.getRuntime().gc(). The garbage collector is designed to run automatically in the
background when the JVM determines that it's necessary. Manually invoking it can interfere
with the JVM's garbage collection strategy and may not always result in immediate memory
reclamation. Relying solely on automatic garbage collection is usually the best approach.
30. (a) Access Specifiers in Java
Access Specifier Visibility

public Accessible from any class, anywhere.

protected Accessible within the same package and by subclasses in different packages.

default (no specifier) Accessible within the same package only.

private Accessible only within the class where it is declared.

(b) Encapsulation in Java


Encapsulation is the bundling of data (variables) and the methods that operate on that data into
a single unit called a class. It is one of the fundamental principles of object-oriented
programming.
Example:

class BankAccount {
private String accountNumber;
private double balance;

public BankAccount(String accountNumber, double balance) {


this.accountNumber = accountNumber;
this.balance = balance;
}

public double getBalance() {


return balance;
}

public void deposit(double amount) {


balance += amount;
}

public void withdraw(double amount) {


if (balance >= amount) {
balance -= amount;
} else {
System.out.println("Insufficient balance");
}
}
}

public class Main {


public static void main(String[] args) {
BankAccount account = new BankAccount("123456789", 1000.0);
account.deposit(500.0);
account.withdraw(200.0);
System.out.println("Balance: " + account.getBalance());
}
}
31. (a) Java Compiler Platform-Independence
Yes, the Java compiler is platform-independent. The Java compiler translates Java source code
(.java files) into bytecode (.class files), which is a platform-independent intermediate
representation. The bytecode can then be executed on any platform that has a Java Virtual
Machine (JVM).
(b) Primitive vs. Reference Data Types

Feature Primitive Data Types Reference Data Types

Stores the memory address (reference) of the


Storage Stores actual values directly in memory.
object.

Memory
Allocated on the stack. Allocated on the heap.
Allocation

Size Fixed size (e.g., int is always 4 bytes). Size depends on the object being referenced.

Cannot be null (except for Wrapper Can be null (meaning the reference does not
Null Value
classes like Integer). point to any object).

int, double, boolean, char, byte,


Examples Classes, Arrays, Interfaces
short, long, float

(c) Function Overloading vs. Function Overriding

Feature Function Overloading Function Overriding

Multiple methods in the same class with Method in a subclass has the same name and
Definition
the same name but different parameters. parameters as a method in its superclass.

To provide multiple ways to call a To provide a specific implementation of a


Purpose
method with different arguments. method in a subclass.

Occurs in different classes (superclass and


Class Occurs within the same class.
subclass).

Compile-
Resolved at compile time. Resolved at runtime.
time/Runtime

32. (a) Command-Line Arguments in Java


Command-line arguments are parameters passed to a Java program when it is executed from
the command line. They are accessed in the main method as an array of strings (String[] args).

public class SumNumbers {


public static void main(String[] args) {
int sum = 0;
for (String arg : args) {
try {
int number = Integer.parseInt(arg);
sum += number;
} catch (NumberFormatException e) {
System.err.println("Invalid argument: " + arg + ". It is not an integer."
}
}
System.out.println("Sum: " + sum);
}
}

To run this program:


1. Compile: javac SumNumbers.java

2. Run: java SumNumbers 1 2 3 4 5

Output:

Sum: 15

(b) Object Creation in Java


The process of object creation in Java involves using the new keyword followed by the class
name and constructor arguments.
Behind the Scenes:
1. Memory Allocation: The JVM allocates memory on the heap for the new object.
2. Initialization: The instance variables of the object are initialized with default values (0 for
numeric types, false for boolean, null for reference types).
3. Constructor Call: The appropriate constructor is called to initialize the object's state.
4. Reference Return: The new operator returns a reference to the newly created object, which
can be assigned to a variable.

class MyClass {
int x;
public MyClass(int x) {
this.x = x;
}
}

public class Main {


public static void main(String[] args) {
MyClass obj = new MyClass(10); // Object creation
}
}

33. (a) Inheritance and Code Reusability


Inheritance is a mechanism in which one class (subclass or derived class) inherits the properties
and behaviors of another class (superclass or base class). This promotes code reusability by
allowing the subclass to reuse the code already defined in the superclass.

class Animal {
String name;
public Animal(String name) {
this.name = name;
}

public void eat() {


System.out.println(name + " is eating");
}
}

class Dog extends Animal {


public Dog(String name) {
super(name); // Calling the superclass constructor
}

public void bark() {


System.out.println(name + " is barking");
}
}

public class Main {


public static void main(String[] args) {
Dog dog = new Dog("Buddy");
dog.eat(); // Inherited from Animal
dog.bark(); // Defined in Dog
}
}

(b) Purpose of a Constructor


A constructor is a special method in a class that is used to initialize objects of that class. It has
the same name as the class and is called automatically when an object is created.
Private Constructor:
Yes, a constructor can be private in Java. A private constructor is used to prevent the
instantiation of a class from outside the class itself. It is commonly used in singleton design
patterns or utility classes.

class Singleton {
private static Singleton instance;

private Singleton() {
// Private constructor to prevent instantiation from outside
}

public static Singleton getInstance() {


if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
public class Main {
public static void main(String[] args) {
Singleton singleton = Singleton.getInstance();
}
}

34. (a) final, finally, and finalize


Keyword Description

final Used to declare a constant variable, prevent method overriding, or prevent class inheritance.

Used in a try-catch block to ensure that a block of code is always executed, regardless of
finally
whether an exception is thrown or caught.

finalize A method that is called by the garbage collector before an object is reclaimed.

(b) Examples of final, finally, and finalize

// final
final class FinalClass {
final int x = 10;

final void finalMethod() {


System.out.println("This is a final method");
}
}

// finally
public class FinallyExample {
public static void main(String[] args) {
try {
int result = 10 / 0;
} catch (ArithmeticException e) {
System.err.println("Arithmetic Exception caught");
} finally {
System.out.println("Finally block executed");
}
}
}

// finalize
class FinalizeExample {
@Override
protected void finalize() throws Throwable {
System.out.println("Finalize method called");
}

public static void main(String[] args) {


FinalizeExample obj = new FinalizeExample();
obj = null;
System.gc(); // Request garbage collection
}
}
35. (a) Packages in Java
Packages in Java are a way to organize related classes and interfaces into namespaces. They
provide a way to group classes that are related logically, making it easier to manage and locate
classes. Packages also help avoid naming conflicts between classes.
(b) Creating and Using a Package
1. Create a Package:

// Create a directory named 'mypackage'


// Create a file named 'MyClass.java' inside 'mypackage'

package mypackage;

public class MyClass {


public void displayMessage() {
System.out.println("Hello from MyClass in mypackage");
}
}

2. Use the Package:

// In another file, e.g., Main.java


import mypackage.MyClass;

public class Main {


public static void main(String[] args) {
MyClass obj = new MyClass();
obj.displayMessage();
}
}

(c) super Keyword


The super keyword is used to refer to the superclass (parent class) from within a subclass. It can
be used to:
Call the superclass constructor.
Access superclass members (methods and variables).

class Animal {
String name;

public Animal(String name) {


this.name = name;
}

public void eat() {


System.out.println(name + " is eating");
}
}
class Dog extends Animal {
String breed;

public Dog(String name, String breed) {


super(name); // Call the superclass constructor
this.breed = breed;
}

public void displayBreed() {


System.out.println(name + " is a " + breed);
}

@Override
public void eat() {
super.eat(); // Call the superclass method
System.out.println("Dog is eating");
}
}

public class Main {


public static void main(String[] args) {
Dog dog = new Dog("Buddy", "Golden Retriever");
dog.displayBreed();
dog.eat();
}
}

36. (a) Java: Portable and Secure


Portable: Java achieves portability through the JVM, which allows the same bytecode to run on
any operating system with a JVM implementation ("write once, run anywhere").
Secure: Java incorporates several security features:
Bytecode Verification: The JVM verifies bytecode to ensure it doesn't violate security rules.
Security Manager: The Security Manager controls access to system resources, preventing
malicious code from performing unauthorized actions.
Automatic Memory Management: Garbage collection reduces the risk of memory-related
vulnerabilities.
No Explicit Pointers: Java doesn't support explicit pointers, which prevents unauthorized
memory access.
(b) Compilation and Execution of Test.java
If Test.java is compiled and contains only one public class named Test with public static void
main, it will generate a Test.class file.

To run the program with command-line arguments:


1. Compile: javac Test.java

2. Run: java Test arg1 arg2 arg3


The command-line arguments are stored in the String[] args array of the main method.
(c) Shared Variable Among Objects
To keep a variable that is accessed and modified by each object, and the modifications are
visible to each object, you declare the variable as static.

class MyClass {
static int sharedVariable = 0;

public MyClass() {
sharedVariable++;
}

public void displaySharedVariable() {


System.out.println("Shared Variable: " + sharedVariable);
}
}

public class Main {


public static void main(String[] args) {
MyClass obj1 = new MyClass();
MyClass obj2 = new MyClass();
obj1.displaySharedVariable(); // Output: Shared Variable: 2
obj2.displaySharedVariable(); // Output: Shared Variable: 2
}
}

(d) Destructor in Java


There is no explicit destructor in Java like in C++. Memory is deallocated in Java through
automatic garbage collection. When an object is no longer reachable (i.e., no longer referenced
by any active part of the program), the garbage collector reclaims the memory occupied by that
object. The finalize() method can be used to perform cleanup operations before an object is
garbage collected, but it is not guaranteed to be called and should not be relied upon for critical
resource management.

37. (a) Abstract Class Requirement


False. For a class in Java to be abstract, it is not necessary for the class to contain an abstract
method. A class can be declared as abstract even if it has no abstract methods.
(b) Example of Abstract Class

abstract class Vehicle {


String modelName;

public Vehicle(String modelName) {


this.modelName = modelName;
}

abstract void start(); // Abstract method


void displayModel() {
System.out.println("Model Name: " + modelName);
}
}

class Car extends Vehicle {


public Car(String modelName) {
super(modelName);
}

@Override
void start() {
System.out.println("Car started");
}
}

public class Main {


public static void main(String[] args) {
Car myCar = new Car("BMW");
myCar.start();
myCar.displayModel();
}
}

Output:

Car started
Model Name: BMW

(c) Instantiating an Abstract Class


No, you cannot instantiate an abstract class directly. Abstract classes are incomplete and are
meant to be subclassed by concrete classes that provide implementations for the abstract
methods.
Syntax to instantiate an abstract class is invalid:

//AbstractClass abstractClass = new AbstractClass(); // This is invalid

(d) Object-Oriented Paradigm Concepts Satisfied by Abstract Class


Abstraction: Abstract classes provide a way to define abstract concepts without specifying
their implementation details.
Inheritance: Abstract classes serve as base classes for other classes, allowing subclasses
to inherit and extend their functionality.
38. (a) Use of Interface
An interface is used to define a contract that classes can implement. It specifies a set of
methods that implementing classes must provide. Interfaces are used to achieve abstraction
and multiple inheritance in Java.

interface Animal {
void makeSound();
void eat();
}

class Dog implements Animal {


@Override
public void makeSound() {
System.out.println("Woof!");
}

@Override
public void eat() {
System.out.println("Dog is eating");
}
}

public class Main {


public static void main(String[] args) {
Dog myDog = new Dog();
myDog.makeSound();
myDog.eat();
}
}

Output:

Woof!
Dog is eating

(b) User-Defined Exception in calculate_marks Method

class Semester_answer {
String name;
int roll;
int no_of_questions_attempted;

public Semester_answer(String name, int roll, int no_of_questions_attempted) {


this.name = name;
this.roll = roll;
this.no_of_questions_attempted = no_of_questions_attempted;
}

public int calculate_marks() throws Exception {


if (no_of_questions_attempted > 4) {
throw new Exception("Marks of one question not to be added");
}
return no_of_questions_attempted * 10;
}

public static void main(String[] args) {


Semester_answer student = new Semester_answer("John", 123, 5);
try {
int marks = student.calculate_marks();
System.out.println("Marks: " + marks);
} catch (Exception e) {
System.err.println("Exception: " + e.getMessage());
}
}
}

39. (a) What is the difference of use of default and


protected access specifier?
(b) Write a Java program to do the following:
Create three threads named one, two, and three in the main thread. Each thread will print
multiples of 3, 4, and 5, respectively. The main thread waits for the child threads to join it
(c) Write a Java program to implement a JApplet to do the following:
There is an input textfield taking any string as input from the user. Your program will convert
lowercase letters to uppercase and vice versa and show that in the output textfield. For
example,
if AbCd is given as input, aBcD will be shown as the output.
40. (a) ls it possible in Java to implement multiple inheritance? Explain with an example how a
derived
class can inherit from more than one base classes.
(b) Write down the differences between interfaces and abstract classes.
(c) What is an abstract method? How is it implemented in Java?
41. (a) Write a program in java swing/applet to draw a polygon filled with green colour using the
rgb
format.
(b) What is the difference between Java applets and Java application programs?
(c) Explain the difference between creating a thread by extending the "Thread" class and
creating a
thread by implementing the "Runnable" interface, with suitable programs.
(d) How do we define "try" and "catch" block in Java?
42. (a) Write a sample Java code to demonstrate about ArrayIndexOutOfBoundsException,
ArithmeticException, NullPointerException exceptions.
(b) Create a package shape containing classes Circle, Triangle and Rectangle. Every class of
this
package should contain two methods, viz., area and perimeter. Write a sample Java code that
can
import shape package and use the methods to calculate area and perimeter of the respective
shape.
43. (a) With examples explain the scenario where the method in an interface can have a method
body.
(b) What is thread synchronization and why is it needed?
(c) What is package ? How do we add a class or an interface to a package ? What do you mean
by
CLASSPATH ?
44. (a) In a triangle, the sum of two sides is greater than the third. If we are given three values a,
b ,c then
a+b>c, b+c>a,c+a>b.
Write a sample code in java for class Triangle which throw an exception of type
TriangleException
(user defined exception) if any one of the above conditions is not satisfied else evaluate the area
of a triangle and display the output.
(b) Write a sample code in java to create a package mycomplex containing a class Complex.
This class
contains a constructor to initialize a complex number and three methods, viz., add, sub and mul
to return sum, difference and product of two complex numbers respectively. Import the package
to your sample code and show the use of the existing methods.
(c) What is partial implementation of an interface?
45. (a) What are exceptions ? Explain the user defined exceptions and system defined
exceptions with
suitable examples.
(b) How do we define try and catch block? Is it essential to catch all types of exceptions?
Explain.
(c) Briefly explain the use of "this" and "super" keywords ?
46. (a) What is multithreading programming ? Explain thread life cycle.
(b) Differentiate between checked and unchecked exceptions in java.
(c) What is the difference between throw and throws? Explain with example.
47. (a) Write an example Java program to implement thread communication using wait() and
notify()
method.
(b) Write a program in java to
(i) Print the name, priority, and Thread group of the thread.
(ii) Change the name of the current thread to “MyThread”.
(iii) Display the details of current thread.
(c) Create two user defined exceptions viz. TooHot and TooCold. Write a Java program and
throw
TooHot if the temperature exceeds 40 degrees and throw TooCold if the temperature be less
than
20 degrees.
48. (a) What are the similarities and differences between synchronized method and
synchronized block
in java thread, explain with examples.
(b) Write a Java swing program which will accept two values in text boxes and display addition
result
in third text box.
49. (a) With example explain any two methods of JFrame, JLabel and JPanel in Java swing.
(b) What is package? What is the use of it? Why do we need import statement?
(c) Write the uses of finally block in Java.
50. (a) Explain how an event delegation model works. Write a Java swingprogram to explain the
said
concept.
(b) What is the default type of variables in an interface?
(c) Consider the following Java program:
import java.util.*;
interface Department {
String depName="CSE";
void display();
}
class TestDepartment implements Department{
public void display() {
depName="CSE(AIML)";
System.out.println("Department name is" + depName);
}
public static void main(String args []) {
Department ref = new TestDepartment ();
ref.display();
}
}
Is there any error in the code? If yes fix the error.
51. (a) How is an abstract class different from an interface?
(b) How is an abstract class different from an interface?explain with example
(c) What is meant by Garbage Collection in OOPs world?
52. (a) What will be the output of the below code?
class Scaler
{
static int i;
static
{
System.out.println(“a”);
i = 100;
}
}
public class StaticBlock
{
static
{
System.out.println(“b”);
}
public static void main(String[] args)
{
System.out.println(“c”);
System.out.println(Scaler.i);
}
}
b)what is destructor?
c) Difference between an Error and an Exception.
Okay, I will provide the answers to your questions in the requested format.

39. (a) Difference between default and protected access specifiers


The default (no explicit specifier) and protected access specifiers in Java control the visibility of
classes, methods, and variables. Here's how they differ:
default Access Specifier:

When no access specifier is used (e.g., int count; or void myMethod() {}), it has default
access.
Members with default access are visible only within the same package.
They are not accessible from classes outside the package, even if those classes are
subclasses.
protected Access Specifier:

Members declared as protected are visible within the same package (like default).
Additionally, they are visible to subclasses in different packages. This means a
subclass in another package can inherit and access protected members of its
superclass.
Non-subclasses in different packages cannot access protected members.
In summary:

Different
Access Same Same Package Same Package Different Package
Package
Specifier Class (Non-Subclass) (Subclass) (Non-Subclass)
(Subclass)

default Yes Yes Yes No No

protected Yes Yes Yes Yes No

protected offers morevisibility than default by allowing access to subclasses outside the
package, which is crucial for inheritance across package boundaries.

39. (b) Java program with three threads printing multiples

class NumberPrinter implements Runnable {


private String threadName;
private int multipleOf;
private int count;

public NumberPrinter(String name, int multiple, int howMany) {


this.threadName = name;
this.multipleOf = multiple;
this.count = howMany;
System.out.println("Creating " + threadName);
}

@Override
public void run() {
System.out.println("Running " + threadName);
try {
for (int i = 1; i <= count; i++) {
System.out.println("Thread: " + threadName + ", Multiple: " + (multipleOf
// Adding a small delay to make output more readable
Thread.sleep(50);
}
} catch (InterruptedException e) {
System.out.println("Thread " + threadName + " interrupted.");
}
System.out.println("Thread " + threadName + " exiting.");
}
}

public class MultiThreadMultiples {


public static void main(String[] args) {
System.out.println("Main thread starting.");

Thread threadOne = new Thread(new NumberPrinter("one", 3, 5)); // Prints 5 multip


Thread threadTwo = new Thread(new NumberPrinter("two", 4, 5)); // Prints 5 multip
Thread threadThree = new Thread(new NumberPrinter("three", 5, 5)); // Prints 5 mu

threadOne.start();
threadTwo.start();
threadThree.start();

System.out.println("Main thread waiting for child threads to finish.");


try {
threadOne.join(); // Main thread waits for threadOne to complete
System.out.println("Thread one has joined.");
threadTwo.join(); // Main thread waits for threadTwo to complete
System.out.println("Thread two has joined.");
threadThree.join(); // Main thread waits for threadThree to complete
System.out.println("Thread three has joined.");
} catch (InterruptedException e) {
System.out.println("Main thread interrupted.");
}

System.out.println("Main thread exiting.");


}
}

Explanation:
1. NumberPrinter class: Implements Runnable. Each instance will print multiples of a given
number.
2. main method:
Creates three Thread objects, passing instances of NumberPrinter (configured for
multiples of 3, 4, and 5) to their constructors.
Starts each thread using the start() method.
The join() method is called on each child thread. This causes the main thread to pause
its execution and wait until the respective child thread has completed its run() method.
Once all child threads have joined, the main thread resumes and prints its exiting
message.

39. (c) JApplet for case conversion


Note: JApplets are considered legacy technology and are not widely used in modern web
development due to browser plugin restrictions. However, here's how you would implement it:

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

public class CaseConverterApplet extends JApplet implements ActionListener {


JTextField inputField;
JTextField outputField;
JButton convertButton;

@Override
public void init() {
// Set layout manager
setLayout(new FlowLayout());

// Initialize components
JLabel inputLabel = new JLabel("Enter text:");
inputField = new JTextField(20); // 20 columns wide

JLabel outputLabel = new JLabel("Converted text:");


outputField = new JTextField(20);
outputField.setEditable(false); // Output field should not be editable

convertButton = new JButton("Convert Case");

// Add components to the applet


add(inputLabel);
add(inputField);
add(convertButton);
add(outputLabel);
add(outputField);

// Register action listener for the button


convertButton.addActionListener(this);
}

@Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() == convertButton) {
String inputText = inputField.getText();
StringBuilder convertedText = new StringBuilder();

for (char c : inputText.toCharArray()) {


if (Character.isLowerCase(c)) {
convertedText.append(Character.toUpperCase(c));
} else if (Character.isUpperCase(c)) {
convertedText.append(Character.toLowerCase(c));
} else {
convertedText.append(c); // Append other characters as is
}
}
outputField.setText(convertedText.toString());
}
}

// To run this applet, you would typically embed it in an HTML file:


/*
<html>
<head>
<title>Case Converter Applet</title>
</head>
<body>
<applet code="CaseConverterApplet.class" width="300" height="150">
</applet>
</body>
</html>
*/
// Or use the appletviewer tool: appletviewer MyHtmlFile.html
}

Explanation:
1. init() method: This method is called when the applet is loaded. It initializes the UI
components:
JTextField for input.
JTextField for output (set to non-editable).
JButton to trigger the conversion.
Labels for clarity.
Components are added to the applet's content pane using FlowLayout.
2. actionPerformed() method: This method is called when the "Convert Case" button is
clicked.
It retrieves the text from the inputField.
It iterates through each character of the input string.
Character.isLowerCase() and Character.isUpperCase() are used to check the case of
each character.
Character.toUpperCase() and Character.toLowerCase() are used for conversion.
The converted string is built using a StringBuilder and then displayed in the
outputField.

To run this, you would compile CaseConverterApplet.java, create an HTML file to embed it, and
then open the HTML file in a browser with Java plugin support or use the appletviewer tool.

40. (a) Multiple Inheritance in Java


No, Java does not support multiple inheritance of classes directly. This means a class cannot
extend (inherit from) more than one superclass. This decision was made to avoid the "diamond
problem" – an ambiguity that arises when two parent classes implement a method with the same
signature, and the child class inherits from both.
However, Java achieves a form of multiple inheritance through interfaces. A class can
implement multiple interfaces. An interface defines a contract (a set of abstract methods and
constants) that implementing classes must adhere to.
Example using Interfaces:

interface Flyable {
void fly(); // Abstract method
}

interface Swimmable {
void swim(); // Abstract method
}

// Duck class implements both Flyable and Swimmable interfaces


class Duck implements Flyable, Swimmable {
private String name;

public Duck(String name) {


this.name = name;
}

@Override
public void fly() {
System.out.println(name + " is flying.");
}

@Override
public void swim() {
System.out.println(name + " is swimming.");
}

public void quack() {


System.out.println(name + " says Quack!");
}
}

public class MultipleInheritanceDemo {


public static void main(String[] args) {
Duck mallard = new Duck("Mallard");
mallard.fly();
mallard.swim();
mallard.quack();

Flyable flyer = mallard; // Can treat Duck as Flyable


flyer.fly();

Swimmable swimmer = mallard; // Can treat Duck as Swimmable


swimmer.swim();
}
}

In this example, the Duck class effectively inherits the "ability to fly" (contract from Flyable) and
the "ability to swim" (contract from Swimmable) by providing implementations for their respective
methods. It is inheriting behavior types or capabilities, not state or concrete implementations
from multiple parent classes.

40. (b) Differences between Interfaces and Abstract Classes


Feature Abstract Class Interface

To provide a common base for related To define a contract that unrelated classes can
Purpose
classes, sharing some implementation. implement.

Traditionally, only abstract methods. Since


Can have abstract methods (no body)
Methods Java 8, can have default and static
and concrete methods (with body).
methods with bodies.

Can have instance variables (non-static, Can only have public static final
Variables
non-final) and constants. variables (constants).

Can have constructors (called by


Constructors Cannot have constructors.
subclass constructors).

A class can extend only one abstract


Inheritance A class can implement multiple interfaces.
class.

Can have various access modifiers for Methods are implicitly public (before Java 9,
Access
members (public, protected, private methods were not allowed). Variables
Modifiers
private, default). are public static final.

Provides a specification; implementing classes


Implementation Can provide partial implementation. provide the full implementation (except for
default methods).

When you want to share code among When you want to define a capability or role
When to use closely related classes (IS-A relationship that different classes can adopt, regardless of
with shared state/behavior). their class hierarchy (HAS-A capability).

40. (c) Abstract Method


An abstract method is a method that is declared without an implementation (i.e., it has no
method body). It only has a method signature (name, parameters, return type) followed by a
semicolon.
Declaration:
Abstract methods are declared using the abstract keyword.
They can only exist within an abstract class or an interface.
Implementation in Java:
1. In an Abstract Class:
If a class contains one or more abstract methods, the class itself must also be declared
abstract.
Any concrete (non-abstract) subclass that extends this abstract class must provide an
implementation (override) for all inherited abstract methods.
// Abstract class with an abstract method
abstract class Shape {
String color;

public Shape(String color) {


this.color = color;
}

// Abstract method - no implementation here


abstract double getArea();

// Concrete method
public String getColor() {
return color;
}
}

// Concrete subclass implementing the abstract method


class Circle extends Shape {
double radius;

public Circle(String color, double radius) {


super(color);
this.radius = radius;
}

// Implementation of the abstract method


@Override
double getArea() {
return Math.PI * radius * radius;
}
}

public class AbstractMethodDemo {


public static void main(String[] args) {
Shape myCircle = new Circle("Red", 5.0);
System.out.println("Color: " + myCircle.getColor());
System.out.println("Area: " + myCircle.getArea()); // Calls the implemented m
}
}
2. In an Interface:
By default, all methods declared in an interface (prior to Java 8 default methods) are
implicitly public and abstract. You don't need to explicitly use the abstract keyword for
methods in an interface.
Any class that implements an interface must provide implementations for all its methods
(unless the class itself is abstract).
interface Drawable {
void draw(); // Implicitly public and abstract
}

class Rectangle implements Drawable {


@Override
public void draw() { // Must be public
System.out.println("Drawing a rectangle.");
}
}

The purpose of abstract methods is to define a common behavior that subclasses must
implement in their own specific way, enforcing a contract while allowing for polymorphic
behavior.

41. (a) Java Swing/Applet program to draw a filled polygon


Here's an example using a JPanel in a JFrame (Swing application), which is more common than
Applets today. The concept for drawing in an Applet's paint() method is very similar.

import javax.swing.*;
import java.awt.*;

class PolygonPanel extends JPanel {


@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g); // Always call super.paintComponent first

// Define the x and y coordinates of the polygon's vertices


int[] xPoints = {50, 150, 200, 100, 20};
int[] yPoints = {50, 20, 100, 180, 100};
int nPoints = xPoints.length; // Number of vertices

// Set the color to green using RGB format


// RGB for green: Red=0, Green=255, Blue=0
Color greenColor = new Color(0, 255, 0); // Equivalent to Color.GREEN
g.setColor(greenColor);

// Draw the filled polygon


g.fillPolygon(xPoints, yPoints, nPoints);

// Optionally, draw the outline


g.setColor(Color.BLACK);
g.drawPolygon(xPoints, yPoints, nPoints);
}
}
public class DrawFilledPolygon {
public static void main(String[] args) {
JFrame frame = new JFrame("Filled Polygon Demo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(300, 250);

PolygonPanel polygonPanel = new PolygonPanel();


frame.add(polygonPanel);

frame.setVisible(true);
}
}

Explanation:
1. PolygonPanel class: Extends JPanel. Custom drawing is done by overriding the
paintComponent(Graphics g) method.

2. paintComponent(Graphics g):

super.paintComponent(g); clears the panel before drawing.


xPoints and yPoints arrays define the vertices of the polygon.
nPoints is the number of vertices.
new Color(0, 255, 0) creates a green color object using RGB values.
g.setColor(greenColor); sets the current drawing color for the Graphics object.
g.fillPolygon(xPoints, yPoints, nPoints); draws the polygon and fills it with the
current color.
Optionally, g.drawPolygon(...) can be used to draw the outline.
3. DrawFilledPolygon class (main class):
Creates a JFrame to host the panel.
Creates an instance of PolygonPanel and adds it to the frame.
Sets the frame size and makes it visible.
If you strictly need an Applet:

import java.applet.Applet;
import java.awt.*;

public class FilledPolygonApplet extends Applet {


@Override
public void paint(Graphics g) {
// Define the x and y coordinates of the polygon's vertices
int[] xPoints = {50, 150, 200, 100, 20};
int[] yPoints = {50, 20, 100, 180, 100};
int nPoints = xPoints.length;

// Set the color to green using RGB format


Color greenColor = new Color(0, 255, 0);
g.setColor(greenColor);

// Draw the filled polygon


g.fillPolygon(xPoints, yPoints, nPoints);

// Optionally, draw the outline


g.setColor(Color.BLACK);
g.drawPolygon(xPoints, yPoints, nPoints);
}

// To run this Applet:


/*
<html>
<body>
<applet code="FilledPolygonApplet.class" width="300" height="250">
</applet>
</body>
</html>
*/
}

The drawing logic within the paint() method of the Applet is identical to the paintComponent()
method in the Swing JPanel.

41. (b) Difference between Java applets and Java application programs
Feature Java Applet Java Application Program

Execution Runs as a standalone program


Runs inside a web browser or an applet viewer.
Environment directly on the OS.

Starts execution with init(), start(), etc. Starts execution from the public
Entry Point (lifecycle methods). No main() method is directly static void main(String[]
called by the system to start it. args) method.

Runs in a "sandbox" with strict security Can have full access to system
Security restrictions (e.g., limited file system access, resources, depending on user
network connections to origin server only). permissions.

Primarily uses AWT or Swing for GUI, embedded Can use AWT, Swing, JavaFX for
GUI
within a browser page. GUI, or be command-line based.

Embedded in HTML pages using <applet> tag


Deployed as JAR files, executable
Deployment (older) or <object>/<embed> (for Java Web Start JARs, or platform-specific installers.
which is also deprecated).

Typically has its own window or


User Interface Part of a web page.
runs in a console.

Tied to the lifespan of the web page or applet Runs until it explicitly exits or is
Lifespan
viewer. terminated by the user/OS.

Modern Largely obsolete due to browser plugin removal Still widely used for various types of
Relevance and security concerns. software.
41. (c) Extending Thread class vs. Implementing Runnable interface
There are two primary ways to create a thread in Java:
1. Extending the Thread Class:
You create a new class that extends java.lang.Thread.
You override the run() method in your subclass to define the code executed by the
thread.
You create an instance of your subclass and call its start() method (inherited from
Thread) to begin execution.

2. Implementing the Runnable Interface:


You create a new class that implements the java.lang.Runnable interface.
You provide an implementation for the run() method (the only method in Runnable).
You create an instance of your class.
You create a Thread object, passing your Runnable instance to its constructor.
You call the start() method on the Thread object.
Differences and Recommendations:

Feature Extending Thread Class Implementing Runnable Interface

Not possible if your class already


Multiple extends another class (Java Preferred. Allows your class to extend another class if
Inheritance doesn't support multiple class needed, as it only implements an interface.
inheritance).

Better. Separates the task (what the thread does, in


Code Mixes thread control logic with
Runnable) from the thread mechanism itself.
Organization the task's logic.
Promotes better object-oriented design.

The task is tightly coupled with The Runnable task can be executed by different types
Reusability of Thread objects or even by an ExecutorService.
the Thread object.
More flexible.

Slightly more overhead as you are


Overhead Generally considered more lightweight and flexible.
creating a subclass of Thread.

Each thread is a distinct object of Multiple threads can share the same Runnable object
Instance
Sharing instance, allowing them to operate on the same data if
your Thread subclass.
designed carefully.

this refers to the Runnable object, not the thread.


this keyword this refers to the thread object
To get the current thread, use
in run() itself.
Thread.currentThread().

General Recommendation:
Implementing the Runnable interface is generally preferred over extending the Thread class
because:
It allows for better separation of concerns (task vs. thread mechanics).
It avoids the limitation of single class inheritance, making your class design more flexible.
Runnable instances can be shared among multiple threads or used with executor services.
Example Programs:
1. Extending Thread:

class MyThread extends Thread {


private String threadName;

public MyThread(String name) {


super(name); // Sets the thread name
this.threadName = name;
System.out.println("Creating " + threadName);
}

@Override
public void run() {
System.out.println("Running " + threadName);
try {
for (int i = 0; i < 3; i++) {
System.out.println("Thread: " + threadName + ", Count: " + i);
Thread.sleep(50);
}
} catch (InterruptedException e) {
System.out.println("Thread " + threadName + " interrupted.");
}
System.out.println("Thread " + threadName + " exiting.");
}
}

public class ExtendThreadDemo {


public static void main(String[] args) {
MyThread t1 = new MyThread("Thread-A-Extends");
MyThread t2 = new MyThread("Thread-B-Extends");

t1.start();
t2.start();
}
}

2. Implementing Runnable:

class MyRunnable implements Runnable {


private String runnableName;

public MyRunnable(String name) {


this.runnableName = name;
System.out.println("Creating Runnable: " + runnableName);
}

@Override
public void run() {
System.out.println("Running task for: " + runnableName + " on thread: " + Thread.
try {
for (int i = 0; i < 3; i++) {
System.out.println("Runnable: " + runnableName + ", Count: " + i);
Thread.sleep(50);
}
} catch (InterruptedException e) {
System.out.println("Runnable task for " + runnableName + " interrupted.");
}
System.out.println("Runnable task for " + runnableName + " exiting.");
}
}

public class ImplementRunnableDemo {


public static void main(String[] args) {
MyRunnable r1 = new MyRunnable("Task-1-Runnable");
MyRunnable r2 = new MyRunnable("Task-2-Runnable");

Thread t1 = new Thread(r1, "Thread-X-Implements"); // Pass Runnable and optionall


Thread t2 = new Thread(r2, "Thread-Y-Implements");

t1.start();
t2.start();
}
}

41. (d) How to define try and catch block in Java


In Java, try and catch blocks are fundamental components of exception handling. They allow
you to write code that might throw an exception and then gracefully handle that exception if it
occurs, preventing the program from crashing.
Syntax:

try {
// Code that might throw an exception (the "guarded region")
// ...
} catch (ExceptionType1 exceptionVariable1) {
// Code to handle ExceptionType1
// ...
} catch (ExceptionType2 exceptionVariable2) {
// Code to handle ExceptionType2
// ...
} finally { // Optional
// Code that will always execute, whether an exception occurred or not
// (e.g., for resource cleanup)
// ...
}

Explanation:
1. try block:
The try keyword introduces a block of code that is "guarded" or monitored for
exceptions.
If an exception occurs within the try block, the normal flow of execution is immediately
halted, and the Java runtime system (JRE) attempts to find a matching catch block.
If no exception occurs, the try block completes normally, and all catch blocks are
skipped. Execution then proceeds to the finally block (if present) or the code following
the try-catch structure.
2. catch block(s):
A try block must be followed by either one or more catch blocks, or a finally block (or
both).
Each catch block is an exception handler that specifies the type of exception it can
handle.
ExceptionType1:This is the class of the exception you want to catch (e.g.,
ArithmeticException, IOException, NullPointerException, or a custom exception
class).
exceptionVariable1: This is a variable name that will hold a reference to the caught
exception object. You can use this variable to get more information about the
exception (e.g., exceptionVariable1.getMessage()).
When an exception is thrown in the try block, the JRE checks the catch blocks
sequentially.
The first catch block whose ExceptionType matches the type of the thrown exception (or
is a superclass of it) is executed.
Only one catch block is executed for a given exception.
If no matching catch block is found in the current method, the exception propagates up
the call stack to the calling method, looking for a handler there. If it reaches the main
method without being caught, the program terminates, and the exception stack trace is
printed.
You can have multiple catch blocks to handle different types of exceptions specifically.
More specific exception types should be caught before more general ones (e.g., catch
(FileNotFoundException e) before catch (IOException e)).

3. finally block (Optional):


The finally block is optional.
If present, the code inside the finally block is always executed, regardless of whether
an exception was thrown or caught in the try block.
It executes even if there's a return, break, or continue statement in the try or catch
blocks.
The primary use of finally is for resource deallocation, such as closing files, network
connections, or database connections, ensuring these cleanup actions happen no
matter what.
Example:
public class TryCatchDemo {
public static void main(String[] args) {
try {
int[] numbers = {1, 2, 3};
System.out.println("Accessing element 5: " + numbers[4]); // This will throw
// int result = 10 / 0; // This would throw ArithmeticException
} catch (ArrayIndexOutOfBoundsException e) {
System.err.println("Error: Array index is out of bounds.");
System.err.println("Details: " + e.getMessage());
} catch (ArithmeticException e) {
System.err.println("Error: Cannot divide by zero.");
} catch (Exception e) { // Catches any other exception
System.err.println("An unexpected error occurred: " + e.getMessage());
} finally {
System.out.println("This finally block is always executed.");
}
System.out.println("Program continues after try-catch-finally.");
}
}

42. (a) Code demonstrating common exceptions

public class ExceptionDemonstration {

public static void demonstrateArrayIndexOutOfBounds() {


System.out.println("--- Demonstrating ArrayIndexOutOfBoundsException ---");
try {
int[] arr = {10, 20, 30};
System.out.println("Accessing arr[0]: " + arr[0]);
System.out.println("Accessing arr[3]: " + arr[3]); // This will cause the exc
} catch (ArrayIndexOutOfBoundsException e) {
System.err.println("Caught ArrayIndexOutOfBoundsException: " + e.getMessage()
// e.printStackTrace(); // Uncomment to see full stack trace
}
System.out.println("Finished ArrayIndexOutOfBoundsException demo.\n");
}

public static void demonstrateArithmeticException() {


System.out.println("--- Demonstrating ArithmeticException ---");
try {
int a = 10;
int b = 0;
System.out.println("Attempting to divide " + a + " by " + b);
int result = a / b; // This will cause the exception
System.out.println("Result: " + result);
} catch (ArithmeticException e) {
System.err.println("Caught ArithmeticException: " + e.getMessage());
}
System.out.println("Finished ArithmeticException demo.\n");
}

public static void demonstrateNullPointerException() {


System.out.println("--- Demonstrating NullPointerException ---");
try {
String str = null;
System.out.println("Attempting to get length of a null string.");
int length = str.length(); // This will cause the exception
System.out.println("Length: " + length);
} catch (NullPointerException e) {
System.err.println("Caught NullPointerException: Cannot invoke \"String.lengt
// System.err.println("Caught NullPointerException: " + e.getMessage()); // g
}
System.out.println("Finished NullPointerException demo.\n");
}

public static void main(String[] args) {


demonstrateArrayIndexOutOfBounds();
demonstrateArithmeticException();
demonstrateNullPointerException();
}
}

Explanation:
1. ArrayIndexOutOfBoundsException: Occurs when you try to access an array element using an
index that is outside the valid range (less than 0 or greater than or equal to array.length).
2. ArithmeticException: Occurs during an arithmetic operation under exceptional conditions,
most commonly integer division by zero.
3. NullPointerException: Occurs when you try to use a null reference as if it were pointing to
an actual object (e.g., calling a method on a null object, or accessing a field of a null
object).

42. (b) Package shape and usage


Step 1: Create the package directory structure and files.
Create a directory named shape. Inside shape, create the following Java files:
File: shape/Circle.java

package shape;

public class Circle {


private double radius;

public Circle(double radius) {


if (radius <= 0) {
throw new IllegalArgumentException("Radius must be positive.");
}
this.radius = radius;
}

public double area() {


return Math.PI * radius * radius;
}
public double perimeter() {
return 2 * Math.PI * radius;
}

public double getRadius() {


return radius;
}
}

File: shape/Triangle.java
(For simplicity, assuming a general triangle for perimeter and requiring sides for area, e.g., using
Heron's formula, or specific type like equilateral)
Let's make a simple equilateral triangle for this example.

package shape;

public class Triangle {


private double side; // Assuming equilateral triangle for simplicity

public Triangle(double side) {


if (side <= 0) {
throw new IllegalArgumentException("Side must be positive.");
}
this.side = side;
}

// Area of an equilateral triangle: (sqrt(3)/4) * side^2


public double area() {
return (Math.sqrt(3) / 4) * side * side;
}

// Perimeter of an equilateral triangle: 3 * side


public double perimeter() {
return 3 * side;
}

public double getSide() {


return side;
}
}

(A more general Triangle class would take three sides and check for validity, then calculate
area using Heron's formula. For this example, equilateral is simpler.)
File: shape/Rectangle.java

package shape;

public class Rectangle {


private double length;
private double width;

public Rectangle(double length, double width) {


if (length <= 0 || width <= 0) {
throw new IllegalArgumentException("Length and width must be positive.");
}
this.length = length;
this.width = width;
}

public double area() {


return length * width;
}

public double perimeter() {


return 2 * (length + width);
}

public double getLength() {


return length;
}

public double getWidth() {


return width;
}
}

Step 2: Compile the package.


Navigate to the directory containing the shape directory (i.e., the parent directory of shape) in
your terminal and compile:
javac shape/Circle.java shape/Triangle.java shape/Rectangle.java
This will create .class files inside the shape directory.
Step 3: Create a main class to use the package.
Create this file in the directory containing the shape directory (not inside shape).
File: ShapeDemo.java (sibling to the shape directory)

import shape.Circle;
import shape.Rectangle;
import shape.Triangle;

public class ShapeDemo {


public static void main(String[] args) {
try {
// Using Circle
Circle myCircle = new Circle(5.0);
System.out.println("Circle with radius " + myCircle.getRadius() + ":");
System.out.println(" Area: " + myCircle.area());
System.out.println(" Perimeter: " + myCircle.perimeter());
System.out.println();

// Using Rectangle
Rectangle myRectangle = new Rectangle(4.0, 6.0);
System.out.println("Rectangle with length " + myRectangle.getLength() + " and
System.out.println(" Area: " + myRectangle.area());
System.out.println(" Perimeter: " + myRectangle.perimeter());
System.out.println();

// Using Triangle (Equilateral)


Triangle myTriangle = new Triangle(7.0);
System.out.println("Equilateral Triangle with side " + myTriangle.getSide() +
System.out.println(" Area: " + String.format("%.2f", myTriangle.area())); //
System.out.println(" Perimeter: " + myTriangle.perimeter());
System.out.println();

} catch (IllegalArgumentException e) {
System.err.println("Error creating shape: " + e.getMessage());
}
}
}

Step 4: Compile and run ShapeDemo.java.


Ensure you are in the directory containing ShapeDemo.java and the shape sub-directory.
Compile: javac ShapeDemo.java
Run: java ShapeDemo
Expected Output:

Circle with radius 5.0:


Area: 78.53981633974483
Perimeter: 31.41592653589793

Rectangle with length 4.0 and width 6.0:


Area: 24.0
Perimeter: 20.0

Equilateral Triangle with side 7.0:


Area: 21.22
Perimeter: 21.0

This demonstrates creating a package, defining classes within it, and then importing and using
those classes in another program.

43. (a) Interface methods with a method body


Yes, since Java 8, methods in an interface can have a method body. This is possible in two
ways:
1. Default Methods:
Purpose: Default methods allow you to add new methods to existing interfaces without
breaking classes that already implement those interfaces. If an implementing class
doesn't provide its own implementation for a default method, it inherits the default
implementation from the interface.
Declaration: Declared using the default keyword.
Example:
interface Logger {
void log(String message); // Abstract method

// Default method with a body


default void logInfo(String message) {
System.out.println("[INFO] " + message);
log(message); // Can call other interface methods
}

// Another default method


default void logWarning(String message) {
System.out.println("[WARNING] " + message);
}
}

class ConsoleLogger implements Logger {


@Override
public void log(String message) {
System.out.println("Logging to console: " + message);
}

// Optionally, ConsoleLogger can override logInfo or logWarning


// @Override
// public void logInfo(String message) {
// System.out.println("Custom INFO: " + message);
// }
}

class FileLogger implements Logger {


@Override
public void log(String message) {
System.out.println("Logging to file: " + message);
}
}

public class DefaultMethodDemo {


public static void main(String[] args) {
Logger console = new ConsoleLogger();
console.log("This is a standard log.");
console.logInfo("This is an info log."); // Uses default implementation
console.logWarning("This is a warning log."); // Uses default implementation

Logger file = new FileLogger();


file.logInfo("Info for file."); // Uses default implementation
}
}

2. Static Methods:
Purpose: Static methods in interfaces are utility methods that are related to the
interface but are not tied to a specific instance of an implementing class. They are
called directly on the interface itself.
Declaration: Declared using the static keyword.
Example:
interface StringUtils {
// Static method with a body
static boolean isEmpty(String str) {
return str == null || str.trim().isEmpty();
}

// Another static method


static String reverse(String str) {
if (isEmpty(str)) { // Can call other static interface methods
return str;
}
return new StringBuilder(str).reverse().toString();
}

void processString(String s); // Abstract method for implementing classes


}

class MyStringProcessor implements StringUtils {


@Override
public void processString(String s) {
if (!StringUtils.isEmpty(s)) { // Calling static method from interface
System.out.println("Processing: " + s);
} else {
System.out.println("String is empty, nothing to process.");
}
}
}

public class StaticInterfaceMethodDemo {


public static void main(String[] args) {
System.out.println("Is 'hello' empty? " + StringUtils.isEmpty("hello")); // f
System.out.println("Is '' empty? " + StringUtils.isEmpty("")); // true
System.out.println("Is null empty? " + StringUtils.isEmpty(null)); // true

System.out.println("Reverse of 'world': " + StringUtils.reverse("world")); //

MyStringProcessor processor = new MyStringProcessor();


processor.processString("Test");
processor.processString(null);
}
}

Note: Prior to Java 9, interface methods could not be private. Java 9 introduced private static
and private instance (non-default) methods in interfaces, which can also have bodies. These are
typically helper methods for default or static public methods within the interface.

43. (b) Thread Synchronization and its need


What is Thread Synchronization?
Thread synchronization is a mechanism in concurrent programming that controls the access of
multiple threads to shared resources or data. When two or more threads need to access a
shared resource simultaneously, synchronization ensures that only one thread can access the
resource at any given time, preventing conflicts and maintaining data integrity.
In Java, synchronization can be achieved using:
1. synchronized methods: When a method is declared synchronized, a lock is acquired on the
object (this for instance methods, or the Class object for static methods) before the method
executes. No other thread can execute a synchronized method on the same object until the
lock is released (when the method completes).
2. synchronized blocks: Allows for finer-grained control by synchronizing only a specific part of
a method, rather than the entire method. You specify the object on which to lock.
3. java.util.concurrent.locks package: Provides more advanced and flexible locking
mechanisms like ReentrantLock.
4. Volatile keyword: Ensures visibility of changes to variables across threads, but doesn't
provide atomicity for compound actions.
Why is it needed?
Thread synchronization is crucial for several reasons:
1. Preventing Race Conditions:
A race condition occurs when multiple threads access and manipulate shared data
concurrently, and the final outcome depends on the unpredictable order in which their
operations are interleaved. This can lead to incorrect results.
Example: Two threads incrementing a shared counter. Without synchronization, both might
read the same value, increment it, and write back, resulting in only one increment being
effectively recorded.
2. Maintaining Data Integrity/Consistency:
When shared data is modified by multiple threads, synchronization ensures that the data
remains in a consistent state. Without it, one thread might see partially updated or corrupted
data modified by another thread.
Example: A complex data structure being updated. One thread might be in the middle of an
update (leaving it in an inconsistent state) when another thread reads it.
3. Ensuring Atomicity:
Some operations need to be atomic, meaning they must be executed as a single, indivisible
unit. Synchronization can group a sequence of operations so that they appear atomic to
other threads.
Example: Transferring money from one bank account to another involves debiting one and
crediting another. Both operations must complete successfully, or neither should, to maintain
consistency.
4. Preventing Interference:
Threads can interfere with each other when accessing shared resources. For instance, one
thread might be writing to a file while another is trying to read from it, leading to corrupted
data or errors.
5. Memory Visibility Issues (related to but distinct from just locking):
Without proper synchronization, changes made by one thread to shared variables might not
be visible to other threads due to caching or compiler optimizations. synchronized
blocks/methods and volatile variables help establish a "happens-before" relationship,
ensuring memory visibility.
In summary, thread synchronization is needed to build robust, correct, and predictable
multithreaded applications by managing access to shared resources, preventing data
corruption, and ensuring consistent program behavior.

43. (c) Package, adding class/interface to package, CLASSPATH


What is a Package?
In Java, a package is a namespace that organizes a set of related classes and interfaces. It's
essentially a way to group related types, similar to how folders organize files on a computer.
Packages serve several purposes:
1. Organization: They help in structuring large projects by grouping logically related classes
and interfaces together, making the codebase easier to understand, manage, and navigate.
2. Naming Conflict Prevention: Packages provide a unique namespace for the types they
contain. This means you can have two classes with the same name as long as they are in
different packages (e.g., java.util.Date and java.sql.Date). The fully qualified name of a
class includes its package name (e.g., com.example.MyClass).
3. Access Control: Packages play a role in access control. The default (package-private)
access level allows members to be accessed only by other types within the same package.
The protected access level also uses package boundaries for part of its visibility rules.
4. Reusability: Well-defined packages can be reused across different projects.
Standard Java libraries are organized into packages like java.lang, java.util, java.io, etc.
How do we add a class or an interface to a package?
To add a class or interface to a package, you use the package keyword as the first statement in
your Java source file (before any import statements or class/interface declarations).
Syntax:

package your.package.name; // This must be the first line

// import statements (optional)

public class MyClass {


// ... class content ...
}

interface MyInterface {
// ... interface content ...
}

Directory Structure:
The package name corresponds to a directory structure on the file system.
For a package named com.example.project, you would typically have a directory structure like:

<base_directory_for_source_files>/
└── com/
└── example/
└── project/
├── MyClass.java
└── MyInterface.java

When compiling, the compiler needs to be able to find these source files based on their package
declaration and the directory structure. The resulting .class files will also be placed in a similar
directory structure within the output/compilation directory.
What do you mean by CLASSPATH?
CLASSPATH is an environment variable or a command-line option that tells the Java Virtual
Machine (JVM) and the Java compiler where to find user-defined classes and packages (i.e.,
the compiled .class files and JAR files).
Purpose:
At Compile Time (for javac): The compiler uses the CLASSPATH to locate any library
classes or other pre-compiled classes that your source code depends on (e.g., classes from
imported packages or third-party libraries).
At Run Time (for java): The JVM uses the CLASSPATH to locate and load the .class files
needed to execute your application, including your application's own classes and any library
classes it uses.
How CLASSPATH works:
The CLASSPATH can specify:
1. Directories: The root directories where package hierarchies begin (e.g., if
com/example/MyClass.class is in /projects/classes, then /projects/classes would be on the
CLASSPATH).
2. JAR (Java Archive) files: Files that bundle multiple .class files and other resources.
3. ZIP files: Similar to JAR files.
Setting CLASSPATH:
Environment Variable: You can set a CLASSPATH environment variable in your operating
system. This is a global setting but can be overridden.
Example (Unix/Linux): export CLASSPATH=/path/to/classes:/path/to/lib/mylib.jar:.

Example (Windows): set CLASSPATH=C:\path\to\classes;C:\path\to\lib\mylib.jar;.


(Note: . refers to the current directory)
Command-Line Options: This is often preferred as it's specific to a single compilation or
execution:
For javac: javac -cp /path/to/classes:/path/to/lib/mylib.jar:. MyProgram.java
javac -classpath /path/to/classes:/path/to/lib/mylib.jar:. MyProgram.java

For java: java -cp /path/to/classes:/path/to/lib/mylib.jar:. com.example.MyProgram


java -classpath /path/to/classes:/path/to/lib/mylib.jar:. com.example.MyProgram

Default CLASSPATH:
If the CLASSPATH is not explicitly set, it defaults to the current directory (.). This is often
sufficient for simple programs that don't use external libraries or complex package structures.
Modern IDEs (like IntelliJ IDEA, Eclipse) usually manage the CLASSPATH for your projects
automatically based on project settings and library configurations, abstracting much of this
detail from the developer during development. However, understanding CLASSPATH is crucial
for troubleshooting "class not found" errors and for deploying applications.

44. (a) TriangleException and area calculation


Step 1: Define the user-defined exception TriangleException.java

// TriangleException.java
public class TriangleException extends Exception {
public TriangleException(String message) {
super(message);
}
}

Step 2: Define the Triangle.java class

// Triangle.java
public class Triangle {
private double sideA;
private double sideB;
private double sideC;

public Triangle(double a, double b, double c) throws TriangleException {


if (a <= 0 || b <= 0 || c <= 0) {
throw new TriangleException("Sides of a triangle must be positive.");
}
if (!((a + b > c) && (b + c > a) && (c + a > b))) {
throw new TriangleException("The given sides do not form a valid triangle (su
}
this.sideA = a;
this.sideB = b;
this.sideC = c;
System.out.println("Triangle created successfully with sides: " + a + ", " + b +
}

// Calculate area using Heron's formula


public double calculateArea() {
// Semi-perimeter
double s = (sideA + sideB + sideC) / 2;
// Area
return Math.sqrt(s * (s - sideA) * (s - sideB) * (s - sideC));
}

public static void main(String[] args) {


// Test cases
try {
Triangle validTriangle = new Triangle(3, 4, 5);
System.out.println("Area of valid triangle (3,4,5): " + validTriangle.calcula
} catch (TriangleException e) {
System.err.println("Error: " + e.getMessage());
}

System.out.println("\n--- Test with invalid sides (violating triangle inequality)


try {
Triangle invalidTriangle1 = new Triangle(1, 2, 5); // 1+2 is not > 5
System.out.println("Area of invalid triangle (1,2,5): " + invalidTriangle1.ca
} catch (TriangleException e) {
System.err.println("Error: " + e.getMessage());
}

System.out.println("\n--- Test with non-positive side ---");


try {
Triangle invalidTriangle2 = new Triangle(3, 4, -5);
System.out.println("Area of invalid triangle (3,4,-5): " + invalidTriangle2.c
} catch (TriangleException e) {
System.err.println("Error: " + e.getMessage());
}

System.out.println("\n--- Test with zero side ---");


try {
Triangle invalidTriangle3 = new Triangle(3, 0, 5);
System.out.println("Area of invalid triangle (3,0,5): " + invalidTriangle3.ca
} catch (TriangleException e) {
System.err.println("Error: " + e.getMessage());
}
}
}

Explanation:
1. TriangleException.java: A simple custom exception class that extends java.lang.Exception.
2. Triangle.java:
The constructor Triangle(double a, double b, double c) takes three side lengths.
It first checks if any side is non-positive. If so, it throws a TriangleException.
It then checks the triangle inequality conditions: a+b>c, b+c>a, and c+a>b. If any of these
conditions are not met, it throws a TriangleException.
If all conditions are met, the sides are stored in instance variables.
The calculateArea() method uses Heron's formula to calculate the area of the triangle.
The main method demonstrates creating valid and invalid triangles and catching the
TriangleException.

To compile and run:


1. Save both files (TriangleException.java and Triangle.java) in the same directory.
2. Compile: javac TriangleException.java Triangle.java

3. Run: java Triangle

Expected Output:

Triangle created successfully with sides: 3.0, 4.0, 5.0


Area of valid triangle (3,4,5): 6.0

--- Test with invalid sides (violating triangle inequality) ---


Error: The given sides do not form a valid triangle (sum of two sides must be greater tha

--- Test with non-positive side ---


Error: Sides of a triangle must be positive.

--- Test with zero side ---


Error: Sides of a triangle must be positive.

44. (b) mycomplex package with Complex class


Step 1: Create the package directory structure and the Complex.java file.
Create a directory named mycomplex. Inside mycomplex, create Complex.java:
File: mycomplex/Complex.java

package mycomplex;

public class Complex {


private double real;
private double imaginary;

// Constructor to initialize a complex number


public Complex(double real, double imaginary) {
this.real = real;
this.imaginary = imaginary;
}

// Getter for real part


public double getReal() {
return real;
}

// Getter for imaginary part


public double getImaginary() {
return imaginary;
}

// Method to add two complex numbers


// Returns a new Complex number as the result
public Complex add(Complex other) {
double newReal = this.real + other.real;
double newImaginary = this.imaginary + other.imaginary;
return new Complex(newReal, newImaginary);
}

// Method to subtract another complex number from this one


// Returns a new Complex number as the result
public Complex sub(Complex other) {
double newReal = this.real - other.real;
double newImaginary = this.imaginary - other.imaginary;
return new Complex(newReal, newImaginary);
}

// Method to multiply two complex numbers


// (a + bi) * (c + di) = (ac - bd) + (ad + bc)i
// Returns a new Complex number as the result
public Complex mul(Complex other) {
double newReal = (this.real * other.real) - (this.imaginary * other.imaginary);
double newImaginary = (this.real * other.imaginary) + (this.imaginary * other.rea
return new Complex(newReal, newImaginary);
}

// Override toString() for better display


@Override
public String toString() {
if (imaginary >= 0) {
return real + " + " + imaginary + "i";
} else {
return real + " - " + Math.abs(imaginary) + "i";
}
}
}

Step 2: Compile the package.


Navigate to the directory containing the mycomplex directory and compile:
javac mycomplex/Complex.java

Step 3: Create a main class to use the package.


Create this file in the directory containing the mycomplex directory.
File: ComplexDemo.java

import mycomplex.Complex; // Import the Complex class from the package

public class ComplexDemo {


public static void main(String[] args) {
// Create two complex numbers
Complex c1 = new Complex(2.5, 3.0); // 2.5 + 3.0i
Complex c2 = new Complex(1.0, -1.5); // 1.0 - 1.5i

System.out.println("Complex number c1: " + c1);


System.out.println("Complex number c2: " + c2);
System.out.println();

// Perform addition
Complex sum = c1.add(c2);
System.out.println("c1 + c2 = " + sum); // Expected: (2.5+1.0) + (3.0-1.5)i = 3.5
// Perform subtraction
Complex difference = c1.sub(c2);
System.out.println("c1 - c2 = " + difference); // Expected: (2.5-1.0) + (3.0-(-1.

// Perform multiplication
// (2.5 + 3.0i) * (1.0 - 1.5i)
// = (2.5*1.0 - 3.0*(-1.5)) + (2.5*(-1.5) + 3.0*1.0)i
// = (2.5 + 4.5) + (-3.75 + 3.0)i
// = 7.0 - 0.75i
Complex product = c1.mul(c2);
System.out.println("c1 * c2 = " + product);

}
}

Step 4: Compile and run ComplexDemo.java.


Ensure you are in the directory containing ComplexDemo.java and the mycomplex sub-directory.
Compile: javac ComplexDemo.java
Run: java ComplexDemo
Expected Output:

Complex number c1: 2.5 + 3.0i


Complex number c2: 1.0 - 1.5i

c1 + c2 = 3.5 + 1.5i
c1 - c2 = 1.5 + 4.5i
c1 * c2 = 7.0 - 0.75i

44. (c) What is partial implementation of an interface?


"Partial implementation of an interface" can refer to a couple of related scenarios in Java:
1. Abstract Class Implementing an Interface:
A class can declare that it implements an interface but not provide implementations for all of
the interface's abstract methods. In such a case, the class itself must be declared abstract.
This abstract class provides a "partial implementation" because it might implement some
interface methods while leaving others abstract for its concrete subclasses to implement.
interface Worker {
void work();
void takeBreak();
String getTask();
}

// AbstractOfficeWorker partially implements Worker


abstract class AbstractOfficeWorker implements Worker {
private String currentTask;

public AbstractOfficeWorker(String task) {


this.currentTask = task;
}

@Override
public String getTask() { // Implemented method
return currentTask;
}

@Override
public void takeBreak() { // Implemented method
System.out.println("Taking a 15-minute coffee break.");
}

// work() method is NOT implemented, so AbstractOfficeWorker must be abstract


// public abstract void work(); // This is implicitly required or explicitly decl
}

class Programmer extends AbstractOfficeWorker {


public Programmer(String task) {
super(task);
}

@Override
public void work() { // Programmer provides the missing implementation
System.out.println("Programmer is working on: " + getTask());
}
}

public class PartialInterfaceImplDemo {


public static void main(String[] args) {
Worker dev = new Programmer("Developing new feature");
dev.work();
dev.takeBreak();
}
}

Here, AbstractOfficeWorker provides implementations for getTask() and takeBreak() but


leaves work() abstract (it doesn't provide a body for it). Therefore, AbstractOfficeWorker is a
partial implementation of the Worker interface.
2. Interfaces with Default Methods (Java 8+):
Since Java 8, interfaces themselves can provide default implementations for methods. If an
interface has, say, three methods, and two of them are default methods (with bodies), then
a concrete class implementing this interface only needs to provide an implementation for the
one abstract method.
In a sense, the interface itself offers a "partial implementation" through its default methods,
which implementing classes can choose to use or override.
interface Notifier {
void sendNotification(String message); // Abstract method - must be implemented

default void onSuccess(String operation) { // Default method - provides an implem


System.out.println("SUCCESS: Operation '" + operation + "' completed.");
}
default void onError(String operation, String error) { // Default method - provid
System.err.println("ERROR: Operation '" + operation + "' failed: " + error);
}
}

class EmailNotifier implements Notifier {


@Override
public void sendNotification(String message) {
System.out.println("Sending email notification: " + message);
// Suppose this operation was successful
onSuccess("Email Sending"); // Uses default method from interface
}
}

class SMSNotifier implements Notifier {


@Override
public void sendNotification(String message) {
System.out.println("Sending SMS notification: " + message);
// Suppose this operation failed
onError("SMS Sending", "Network unavailable"); // Uses default method
}

@Override
public void onSuccess(String operation) { // Overrides default method
System.out.println("SMS NOTIFICATION SUCCESS for: " + operation);
}
}

Here, EmailNotifier only implements sendNotification and uses the default implementations
for onSuccess and onError. SMSNotifier implements sendNotification and overrides
onSuccess. Both are complete implementations of the Notifier contract, but they benefit
from the partial implementation provided by the interface's default methods.
The first definition (an abstract class implementing an interface partially) is the more traditional
understanding of "partial implementation of an interface" by a class. The second definition
highlights how interfaces themselves can now contribute to partial implementation.

45. (a) Exceptions: User-defined and System-defined


What are Exceptions?
In Java, an exception is an event that occurs during the execution of a program that disrupts
the normal flow of instructions. When an error occurs within a method, the method creates an
object (an exception object) and hands it off to the runtime system. This exception object
contains information about the error, including its type and the state of the program when the
error occurred. The process of creating and handing off this object is called throwing an
exception.
Java's exception handling mechanism allows programs to catch and handle these exceptional
conditions gracefully, rather than abruptly terminating.
Exceptions are broadly categorized into:
1. Checked Exceptions: Exceptions that are checked at compile-time. If a method can throw
a checked exception, it must either handle it using a try-catch block or declare it using the
throws keyword in its signature. Examples: IOException, SQLException,
ClassNotFoundException.

2. Unchecked Exceptions (Runtime Exceptions): Exceptions that are not checked at


compile-time. These usually indicate programming errors (e.g., logic errors) or
unrecoverable issues. They extend RuntimeException. Examples: NullPointerException,
ArrayIndexOutOfBoundsException, ArithmeticException.

3. Errors: These are also unchecked but represent serious problems that a reasonable
application should not try to catch (e.g., OutOfMemoryError, StackOverflowError). They
extend Error.
System-defined Exceptions (Built-in Exceptions):
These are exceptions that are part of the Java Standard Library (Java API). They are
predefined by the Java language to represent common error conditions that can occur during
program execution.
Examples of System-defined Exceptions:
NullPointerException: Thrown when an application attempts to use null in a case where an
object is required (e.g., calling a method on a null reference).
String str = null;
try {
System.out.println(str.length()); // Throws NullPointerException
} catch (NullPointerException e) {
System.err.println("Error: Cannot access length of a null string. " + e);
}

ArrayIndexOutOfBoundsException: Thrown to indicate that an array has been accessed with


an illegal index. The index is either negative or greater than or equal to the size of the array.
int[] arr = {1, 2, 3};
try {
System.out.println(arr[5]); // Throws ArrayIndexOutOfBoundsException
} catch (ArrayIndexOutOfBoundsException e) {
System.err.println("Error: Array index out of bounds. " + e);
}

ArithmeticException: Thrown when an exceptional arithmetic condition has occurred, such


as division by zero.
try {
int result = 10 / 0; // Throws ArithmeticException
} catch (ArithmeticException e) {
System.err.println("Error: Division by zero. " + e);
}
IOException: Thrown when an I/O operation fails or is interrupted. This is a checked
exception.
// import java.io.*;
// try {
// FileReader fr = new FileReader("nonexistentfile.txt");
// } catch (FileNotFoundException e) { // FileNotFoundException is a subclass of IOEx
// System.err.println("Error: File not found. " + e);
// }

User-defined Exceptions (Custom Exceptions):


These are exceptions created by programmers to represent specific error conditions relevant to
their application's domain or logic. User-defined exceptions are typically created by extending
one of the standard Java exception classes (usually Exception for checked exceptions or
RuntimeException for unchecked exceptions).

Why use User-defined Exceptions?


To handle errors specific to the application's business logic.
To provide more context or specific information about an error than a generic system
exception could.
To differentiate application-specific errors from general system errors.
Example of User-defined Exception:

// 1. Define the custom exception class


class InsufficientFundsException extends Exception { // Extends Exception for a checked e
private double shortfall;

public InsufficientFundsException(String message, double shortfall) {


super(message);
this.shortfall = shortfall;
}

public double getShortfall() {


return shortfall;
}
}

// 2. Use the custom exception in application logic


class BankAccount {
private double balance;

public BankAccount(double initialBalance) {


this.balance = initialBalance;
}

public void withdraw(double amount) throws InsufficientFundsException {


if (amount <= 0) {
throw new IllegalArgumentException("Withdrawal amount must be positive."); //
}
if (amount > balance) {
double needed = amount - balance;
throw new InsufficientFundsException("Insufficient funds to withdraw " + amou
}
balance -= amount;
System.out.println("Withdrawn: " + amount + ". Remaining balance: " + balance);
}
}

// 3. Handle the custom exception


public class CustomExceptionDemo {
public static void main(String[] args) {
BankAccount account = new BankAccount(100.0);
try {
account.withdraw(50.0);
account.withdraw(70.0); // This will throw InsufficientFundsException
} catch (InsufficientFundsException e) {
System.err.println("Transaction Failed: " + e.getMessage());
System.err.println("Amount short: " + e.getShortfall());
} catch (IllegalArgumentException e) {
System.err.println("Invalid Input: " + e.getMessage());
}
}
}

In this example, InsufficientFundsException is a user-defined exception specific to the banking


application's logic.

45. (b) try and catch block definition; catching all exceptions
How do we define try and catch block?
As explained in question 41(d), try and catch blocks are used for exception handling in Java.
Syntax Recap:

try {
// Code that might throw an exception
// ...
} catch (ExceptionType1 e1) {
// Handler for ExceptionType1
// ...
} catch (ExceptionType2 e2) {
// Handler for ExceptionType2
// ...
} // ... more catch blocks if needed
finally { // Optional
// Code that always executes
// ...
}

try block: Encloses the code that might generate an exception.


catch block(s): Follows the try block. Each catch block specifies an exception type it can
handle. If an exception of that type (or its subtype) occurs in the try block, the
corresponding catch block is executed.
Is it essential to catch all types of exceptions? Explain.
No, it is not essential, and often not advisable, to catch all types of exceptions using a single,
overly broad catch block like catch (Exception e) or catch (Throwable t) everywhere.
Explanation:
1. Specificity is Key:
It's generally better to catch specific exceptions that you anticipate and know how to
handle. This allows for more targeted error recovery and makes the code easier to
understand and maintain. For example, if you're reading a file, you might specifically catch
FileNotFoundException to prompt the user for a different file, and IOException for other I/O
related issues.
2. Hiding Bugs:
Catching a very general exception like Exception can hide bugs or unexpected runtime
issues. If your code throws an unexpected NullPointerException or
ArrayIndexOutOfBoundsException (which are RuntimeExceptions, subtypes of Exception), a
generic catch (Exception e) block will catch it. While this prevents the program from
crashing immediately, it might mask the underlying problem, making it harder to debug. The
program might continue in an erroneous state.
3. Unrecoverable Errors (Error class):
You should almost never try to catch Error or its subclasses (like OutOfMemoryError,
StackOverflowError). These indicate serious problems in the JVM or system resources that
your application usually cannot recover from. Attempting to catch them might lead to further
instability.
4. Checked vs. Unchecked Exceptions:
Checked Exceptions: The compiler forces you to either handle (catch) them or declare
them using throws. For these, you must provide a handler if you don't propagate them.
Unchecked Exceptions (RuntimeException and Error): You are not required by the
compiler to catch these. They often indicate programming errors (NullPointerException,
IllegalArgumentException) or critical system issues. It's often better to let these
propagate (especially during development) so they can be identified and fixed, rather
than silently catching and ignoring them.
When might catching Exception be acceptable?
Top-level Handlers: In the outermost layer of an application (e.g., in the main method of a
simple application, or in a framework's central error handling mechanism), a catch
(Exception e) block might be used as a last resort to log the error and terminate gracefully
or display a generic error message to the user, rather than letting the program crash
abruptly.
Resource Cleanup with finally: Even if you re-throw an exception or don't handle it
specifically, a finally block should still be used for crucial cleanup.
Frameworks/Libraries: Some frameworks or libraries might catch broader exceptions to
ensure their own stability and provide consistent error reporting.
Best Practices:
Catch the most specific exception type first.
Handle exceptions in a way that makes sense for the application (e.g., retry, log, inform user,
re-throw as a custom exception).
Don't use empty catch blocks that do nothing – this is known as "swallowing" exceptions
and makes debugging very difficult. At least log the exception.
Only catch exceptions that you can meaningfully handle at that point in the code. If you
can't handle it, let it propagate to a higher-level handler or declare it with throws.
So, while you can catch all types of exceptions, it's a practice that should be used judiciously
and with a clear understanding of its implications.

45. (c) Briefly explain the use of "this" and "super" keywords
this Keyword:

The this keyword in Java is a reference variable that refers to the current instance of the class
in which it is used. Its primary uses are:
1. Disambiguate Instance Variables from Local Variables/Parameters:
When an instance variable and a local variable (or method parameter) have the same name,
this can be used to explicitly refer to the instance variable.

class Box {
private int width;
private int height;

public Box(int width, int height) {


this.width = width; // 'this.width' is the instance variable
// 'width' is the parameter
this.height = height;
}
}

2. Call Another Constructor of the Same Class (Constructor Chaining):


this() can be used to call another constructor from within a constructor of the same class. If
used, it must be the first statement in the constructor.
class Rectangle {
private int x, y, width, height;

public Rectangle(int x, int y, int width, int height) {


this.x = x; this.y = y;
this.width = width; this.height = height;
}
public Rectangle(int width, int height) {
this(0, 0, width, height); // Calls the first constructor
}
}

3. Pass the Current Object as an Argument to a Method:


You can pass the current object instance as a parameter to another method.
class EventSource {
public void registerListener(EventListener listener) {
listener.onEvent(this); // Pass current EventSource instance
}
}
interface EventListener { void onEvent(EventSource source); }

4. Return the Current Object Instance from a Method:


Often used in builder patterns or for fluent interfaces.
class ConfigBuilder {
public ConfigBuilder setOptionA() { /* ... */ return this; }
public ConfigBuilder setOptionB() { /* ... */ return this; }
}
// Usage: new ConfigBuilder().setOptionA().setOptionB();

super Keyword:

The super keyword in Java is a reference variable that is used to refer to the immediate parent
class (superclass) object. Its primary uses are:
1. Call Superclass Constructor:
super() can be used to call a constructor of the superclass from a subclass's constructor. If
used, it must be the first statement in the subclass constructor. If no explicit call to super() is
made, the compiler implicitly calls the no-argument constructor of the superclass.
class Animal {
String name;
public Animal(String name) {
this.name = name;
}
}
class Dog extends Animal {
public Dog(String name) {
super(name); // Calls Animal's constructor
}
}

2. Access Superclass Members (Methods and Variables):


When a subclass has a member (method or variable) with the same name as a member in its
superclass (i.e., overriding a method or hiding a variable), super can be used to explicitly
access the superclass's version of that member.
class Vehicle {
void display() {
System.out.println("This is a Vehicle.");
}
}
class Car extends Vehicle {
@Override
void display() {
super.display(); // Calls Vehicle's display() method
System.out.println("This is a Car.");
}
}

In essence, this refers to the current object instance, while super refers to the superclass portion
of the current object instance.

46. (a) Multithreading programming? Explain thread life cycle.


What is Multithreading Programming?
Multithreading is a programming concept that allows a single program to execute multiple parts
of its code (called threads) concurrently. Each thread is an independent path of execution within
the program. All threads within a single process share the same memory space (heap memory),
which allows them to share data and resources easily, but also necessitates careful
synchronization to avoid conflicts.
Benefits of Multithreading:
1. Improved Responsiveness: In applications with a user interface, multithreading can keep
the UI responsive while background tasks (like calculations, file I/O, network requests) are
being performed in separate threads.
2. Increased Performance/Efficiency: On multi-core processors, threads can run truly in
parallel, significantly speeding up CPU-bound tasks by dividing the work. Even on single-
core processors, concurrency can improve efficiency by allowing one thread to execute
while another is waiting for I/O.
3. Resource Sharing: Threads within the same process share memory and resources, which is
more efficient than inter-process communication.
4. Simplified Modeling: Some problems are naturally modeled using multiple concurrent
threads of activity.
Java Thread Life Cycle:
A thread in Java goes through various states during its lifetime. The java.lang.Thread.State
enum defines these states:
1. NEW:
A thread is in this state when it has been created (e.g., Thread t = new MyThread();) but
its start() method has not yet been called.
The thread object exists, but it is not yet alive or eligible to run.
2. RUNNABLE:
A thread enters this state after its start() method is invoked.
It means the thread is either currently running (its run() method is being executed by
the CPU) or it is ready to run and is waiting for its turn to be scheduled by the thread
scheduler.
The thread scheduler allocates CPU time to threads in the RUNNABLE state.
3. BLOCKED:
A thread is in this state when it is waiting to acquire a monitor lock to enter a
synchronized block/method, or after calling Object.wait() and then re-entering a
synchronized block/method.

A thread in the BLOCKED state is temporarily inactive and is not consuming CPU cycles. It
becomes RUNNABLE again when it acquires the lock.
4. WAITING:
A thread is in this state when it is waiting indefinitely for another thread to perform a
particular action. A thread transitions to this state by calling one of the following
methods without a timeout:
Object.wait() (without timeout)
Thread.join() (without timeout)
LockSupport.park()

A thread in this state can only become RUNNABLE if another thread explicitly wakes it up
(e.g., by calling Object.notify(), Object.notifyAll(), or LockSupport.unpark(Thread)).
5. TIMED_WAITING:
A thread is in this state when it is waiting for another thread to perform an action for up
to a specified waiting time. A thread transitions to this state by calling one of the
following methods with a timeout:
Thread.sleep(long millis)

Object.wait(long timeout)

Thread.join(long millis)

LockSupport.parkNanos(long nanos)

LockSupport.parkUntil(long deadline)

The thread becomes RUNNABLE when the timeout expires or when it is woken up by
another thread (e.g., notify()/notifyAll()).
6. TERMINATED (DEAD):
A thread is in this state when its run() method has completed execution (either normally
or due to an unhandled exception).
Once a thread is terminated, it cannot be restarted. Calling start() on a terminated
thread will throw an IllegalThreadStateException.
State Transitions (Simplified):

start()
NEW -------------> RUNNABLE <-----------------------\
| ^ | (Lock acquired)
| | (Notified/Timeout/Interrupted)
V |
(Waiting for lock) BLOCKED
|
| (Lock needed for wait()/join()/sleep())
V
wait(), join(), sleep(timeout)
RUNNABLE ---------> WAITING / TIMED_WAITING
|
| (run() method completes/exits)
V
TERMINATED

Understanding the thread life cycle is crucial for writing correct and efficient multithreaded
programs, especially when dealing with synchronization and inter-thread communication.

46. (b) Differentiate between checked and unchecked exceptions in Java


The primary difference between checked and unchecked exceptions in Java lies in how the
compiler handles them and the typical scenarios they represent.

Feature Checked Exceptions Unchecked Exceptions

Checked at compile-time. The


Not checked at compile-time. The compiler
Compiler Check compiler verifies that they are handled
does not force you to handle or declare them.
or declared.

Must be caught using a try-catch


Not mandatory to handle or declare. Can be
Handling block, or the method must declare it
caught, but it's often a sign of a
Requirement using the throws keyword in its
programming error if they occur.
signature.

Directly inherit from Inherit from


Parent Class java.lang.Exception (but not from java.lang.RuntimeException or
java.lang.RuntimeException). java.lang.Error.

Typically represent an exceptional Usually indicate programming errors (bugs in


condition external to the program that
the code like NullPointerException,
a well-written application should
Purpose/Indication ArrayIndexOutOfBoundsException) or
anticipate and recover from (e.g., I/O
errors, network issues, database critical, unrecoverable system issues (Error
problems). like OutOfMemoryError).

NullPointerException,
IOException,
ArrayIndexOutOfBoundsException,
FileNotFoundException,
ArithmeticException,
SQLException,
IllegalArgumentException,
Examples ClassNotFoundException,
ClassCastException,
InterruptedException, user-
OutOfMemoryError,
defined exceptions extending
StackOverflowError, user-defined
Exception.
exceptions extending RuntimeException.

Often recoverable. The program can Often not easily recoverable without fixing
Recovery take alternative actions or inform the the underlying code bug. For Errors,
user. recovery is generally not possible.
Feature Checked Exceptions Unchecked Exceptions

Conditions outside the immediate


Logic flaws within the program code or
When they occur control of the program (e.g., a file is
severe resource limitations.
missing, network is down).

Mandatory if not caught within the Optional in the throws clause (though
throws clause
method. sometimes documented for clarity).

Key Distinction:
Checked Exceptions: "If this method might encounter this external problem (which is not
necessarily a bug in my code, but something I should prepare for), the caller needs to be
aware of it and handle it."
Unchecked Exceptions:
RuntimeException: "This indicates a bug in my code (or code I'm calling) that should
ideally be fixed, not just caught and ignored."
Error: "This is a severe system-level problem that my application likely cannot handle."
Why the distinction?
The designers of Java introduced checked exceptions to encourage more robust programming
by forcing developers to think about and handle potential external failures. However, there's
ongoing debate about whether they are always beneficial or sometimes lead to overly verbose
code (e.g., excessive try-catch blocks or long throws clauses).

46. (c) Difference between throw and throws? Explain with example.
throw Keyword:

Purpose: The throw keyword is used to explicitly throw an exception object from a method
or any block of code.
Usage: It is followed by an instance of an Exception class (or its subclasses, including
Throwable).

Action: When throw is executed, the normal flow of the program stops, and the Java
Runtime System (JRE) searches for an appropriate exception handler (catch block) in the
call stack.
Where it's used: Inside a method body or a block of code.
throws Keyword:

Purpose: The throws keyword is used in a method signature to declare that the method
might throw one or more specified types of checked exceptions.
Usage: It is part of the method declaration and is followed by a comma-separated list of
exception class names.
Action: It informs the caller of the method that these exceptions could be thrown during the
method's execution and that the caller must either handle them (using try-catch) or also
declare them using throws.
Where it's used: In the method signature.
Applicability: Primarily relevant for checked exceptions. While you can list unchecked
exceptions in a throws clause, it's not required by the compiler and is mainly for
documentation.
Summary of Differences:

Feature throw throws

What it Declares that a method might throw certain types


Manually throws an exception instance.
does of exceptions.

Type A statement used within a method body. A keyword used in the method signature.

Followed by an instance of an
Argument Followed by one or more exception class names.
Exception (or Throwable).

To signal an exceptional condition has To inform callers about potential checked


Purpose
occurred. exceptions they need to handle.

When an error condition is detected and When defining a method that can propagate
When used
needs to be raised. checked exceptions.

Example:

import java.io.IOException;

public class ThrowVsThrowsDemo {

// Method that uses 'throws' to declare it might throw IOException (a checked excepti
public static void readFile(String filePath) throws IOException {
if (filePath == null || filePath.isEmpty()) {
// Using 'throw' to explicitly throw an IllegalArgumentException (an unchecke
throw new IllegalArgumentException("File path cannot be null or empty.");
}

boolean fileExists = false; // Simulate file check


if (filePath.equals("nonexistent.txt")) {
fileExists = false;
} else if (filePath.equals("data.txt")) {
fileExists = true;
}

if (!fileExists) {
// Using 'throw' to explicitly throw an IOException (a checked exception)
// This matches the 'throws IOException' in the method signature.
throw new IOException("File not found: " + filePath);
}
System.out.println("Successfully opened file: " + filePath);
// ... imagine file reading logic here ...
}

public static void processFile(String path) {


try {
readFile(path); // Caller must handle or declare IOException
System.out.println("File processed successfully.");
} catch (IOException e) {
System.err.println("IO Error during file processing: " + e.getMessage());
} catch (IllegalArgumentException e) {
System.err.println("Input Error for file processing: " + e.getMessage());
}
}

public static void main(String[] args) {


System.out.println("--- Test 1: Valid file (simulated) ---");
processFile("data.txt");

System.out.println("\n--- Test 2: Non-existent file ---");


processFile("nonexistent.txt"); // Will trigger IOException

System.out.println("\n--- Test 3: Null file path ---");


processFile(null); // Will trigger IllegalArgumentException
}
}

Explanation of the Example:


1. readFile(String filePath) throws IOException:

The throws IOException clause indicates that this method might throw an IOException (a
checked exception). Callers of readFile are thus warned and must handle it.
Inside the method:
throw new IllegalArgumentException(...): IllegalArgumentException is an
unchecked exception. We are explicitly throwing it if the filePath is invalid. We
don't have to declare IllegalArgumentException in the throws clause, but we can.
throw new IOException(...): If the simulated file doesn't exist, an IOException is
explicitly thrown. This is consistent with the throws IOException declaration.
2. processFile(String path):

This method calls readFile(path). Because readFile declares throws IOException,


processFile must either:

Catch the IOException (as done in the example using try-catch).


Or, processFile itself must be declared with throws IOException to pass the
responsibility further up the call stack.
It also catches IllegalArgumentException which might be thrown by readFile.
3. main method:
Calls processFile with different inputs to demonstrate the exception handling.
This example illustrates how throw is used to create and signal an exception, and throws is used
to propagate the possibility of a checked exception to callers.
47. (a) Thread communication using wait() and notify()
wait(), notify(), and notifyAll() are methods of the java.lang.Object class and are
fundamental for inter-thread communication in Java. They allow threads to coordinate their
activities by pausing (waiting) until a certain condition is met and then being signaled (notified)
by another thread that the condition has changed.
Key Requirements for using wait() and notify():
1. Synchronization: These methods must be called from within a synchronized block or
synchronized method. The lock held must be on the object whose wait() or notify() method
is being called.
2. Object Lock: wait() causes the current thread to release the lock on the object and go into
a waiting state. notify() or notifyAll() wakes up one or all threads, respectively, that are
waiting on that object's monitor. The awakened thread(s) will then attempt to reacquire the
lock before proceeding.
3. Condition Loop: wait() should almost always be called inside a loop that checks the
condition being waited for. This is to guard against "spurious wakeups" (where a thread can
wake up without notify() being called) and to ensure the condition is actually met before
proceeding.
Example: Producer-Consumer Problem
This classic problem demonstrates wait() and notify(). A producer thread produces items and
puts them into a shared buffer, and a consumer thread takes items from the buffer.

import java.util.LinkedList;
import java.util.Queue;

class SharedBuffer {
private Queue<Integer> buffer;
private int capacity;
private int itemCounter = 0; // For producing unique items

public SharedBuffer(int capacity) {


this.buffer = new LinkedList<>();
this.capacity = capacity;
}

// Producer method
public synchronized void produce() throws InterruptedException {
while (true) { // Keep producing
// Wait if the buffer is full
while (buffer.size() == capacity) {
System.out.println("Buffer is full. Producer (" + Thread.currentThread().
wait(); // Release lock and wait
}

int item = ++itemCounter;


buffer.add(item);
System.out.println("Producer (" + Thread.currentThread().getName() + ") produ
// Notify one consumer thread that an item is available
notify(); // Or notifyAll() if multiple consumers

Thread.sleep(500); // Simulate time taken to produce


}
}

// Consumer method
public synchronized void consume() throws InterruptedException {
while (true) { // Keep consuming
// Wait if the buffer is empty
while (buffer.isEmpty()) {
System.out.println("Buffer is empty. Consumer (" + Thread.currentThread()
wait(); // Release lock and wait
}

int item = buffer.poll();


System.out.println("Consumer (" + Thread.currentThread().getName() + ") consu

// Notify one producer thread that space is available


notify(); // Or notifyAll() if multiple producers

Thread.sleep(1000); // Simulate time taken to consume


}
}
}

class Producer implements Runnable {


private SharedBuffer sharedBuffer;

public Producer(SharedBuffer buffer) {


this.sharedBuffer = buffer;
}

@Override
public void run() {
try {
sharedBuffer.produce();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
System.out.println("Producer interrupted.");
}
}
}

class Consumer implements Runnable {


private SharedBuffer sharedBuffer;

public Consumer(SharedBuffer buffer) {


this.sharedBuffer = buffer;
}

@Override
public void run() {
try {
sharedBuffer.consume();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
System.out.println("Consumer interrupted.");
}
}
}

public class WaitNotifyDemo {


public static void main(String[] args) {
SharedBuffer buffer = new SharedBuffer(3); // Buffer capacity of 3

Thread producerThread1 = new Thread(new Producer(buffer), "Producer-1");


Thread consumerThread1 = new Thread(new Consumer(buffer), "Consumer-1");
// Thread producerThread2 = new Thread(new Producer(buffer), "Producer-2");
// Thread consumerThread2 = new Thread(new Consumer(buffer), "Consumer-2");

producerThread1.start();
consumerThread1.start();
// producerThread2.start();
// consumerThread2.start();
}
}

Explanation:
1. SharedBuffer Class:
Holds the shared Queue (buffer) and its capacity.
produce() and consume() methods are synchronized on the SharedBuffer instance (this).
2. produce() Method:
Enters a while (buffer.size() == capacity) loop. If the buffer is full, it prints a message
and calls wait(). This releases the lock on sharedBuffer and the producer thread enters
the WAITING state.
If the buffer is not full, it produces an item, adds it to the buffer.
It then calls notify(). This wakes up a single thread (if any) that is waiting on the
sharedBuffer object's monitor (typically a consumer that was waiting for an item).

3. consume() Method:
Enters a while (buffer.isEmpty()) loop. If the buffer is empty, it prints a message and
calls wait(). This releases the lock and the consumer thread enters the WAITING state.
If the buffer is not empty, it consumes an item from the buffer.
It then calls notify(). This wakes up a single thread (if any) waiting on sharedBuffer
(typically a producer that was waiting for space).
4. Producer and Consumer Classes: Implement Runnable and call the respective methods on the
shared buffer.
5. WaitNotifyDemo (main): Creates the shared buffer, producer, and consumer threads, and
starts them.
When you run this, you'll see the producer and consumer coordinating. The producer will wait
when the buffer is full, and the consumer will wait when it's empty. notify() ensures that waiting
threads are awakened when the condition they are waiting for might have changed. Using
notifyAll() is generally safer if multiple threads could be waiting for different conditions or if
multiple producers/consumers are involved, as it wakes all waiting threads, and they recheck
their conditions in the while loop.

47. (b) Java program for thread properties

public class ThreadPropertiesDemo {

public static void main(String[] args) {


// (i) Print the name, priority, and Thread group of the current (main) thread.
Thread currentThread = Thread.currentThread();
System.out.println("--- Initial Main Thread Details ---");
System.out.println("Thread Name: " + currentThread.getName());
System.out.println("Thread Priority: " + currentThread.getPriority());
System.out.println("Thread Group: " + currentThread.getThreadGroup().getName());
System.out.println();

// (ii) Change the name of the current thread to “MyThread”.


System.out.println("--- Changing Current Thread Name ---");
currentThread.setName("MyThread-Main");
System.out.println("Thread name changed successfully.");
System.out.println();

// (iii) Display the details of current thread (after name change).


System.out.println("--- Updated Main Thread Details ---");
System.out.println("Thread Name: " + currentThread.getName());
System.out.println("Thread Priority: " + currentThread.getPriority()); // Priorit
System.out.println("Thread ID: " + currentThread.getId());
System.out.println("Thread State: " + currentThread.getState()); // Should be RUN
System.out.println("Is Daemon: " + currentThread.isDaemon());
System.out.println("Thread Group: " + currentThread.getThreadGroup().getName());
System.out.println();

// Example with a new thread


Runnable task = () -> {
Thread childThread = Thread.currentThread();
System.out.println("--- Child Thread Details ---");
System.out.println("Child Thread Name: " + childThread.getName());
childThread.setName("MyChildThread-Worker"); // Changing child thread name
System.out.println("Child Thread New Name: " + childThread.getName());
System.out.println("Child Thread Priority: " + childThread.getPriority());
System.out.println("Child Thread Group: " + childThread.getThreadGroup().getN
System.out.println("Child Thread State (in run): " + childThread.getState());
};

Thread newThread = new Thread(task, "InitialChildName");


newThread.setPriority(Thread.MAX_PRIORITY); // Setting priority for the new threa
newThread.start();

try {
newThread.join(); // Wait for the new thread to finish for clean output
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Main thread finished.");
}
}

Explanation:
1. Thread.currentThread(): This static method returns a reference to the currently executing
Thread object.

2. (i) Initial Details:


getName(): Returns the name of the thread.
getPriority():Returns the priority of the thread (an integer between
Thread.MIN_PRIORITY (1) and Thread.MAX_PRIORITY (10)).

getThreadGroup().getName(): Returns the name of the thread group to which this thread
belongs.
3. (ii) Change Thread Name:
setName(String name): Changes the name of the thread.
4. (iii) Display Updated Details:
getId(): Returns the identifier of this thread.
getState(): Returns the current state of this thread (e.g., RUNNABLE, BLOCKED).
isDaemon(): Tests if this thread is a daemon thread.
5. Example with a New Thread:
A new thread newThread is created with an initial name "InitialChildName".
Inside its run() method (defined by the lambda expression), it prints its own details and
then changes its name to "MyChildThread-Worker".
The priority of newThread is set using setPriority().
newThread.join() makes the main thread wait for newThread to complete its execution,
ensuring that the output from the child thread is printed before the main thread finishes.
Sample Output:

--- Initial Main Thread Details ---


Thread Name: main
Thread Priority: 5
Thread Group: main

--- Changing Current Thread Name ---


Thread name changed successfully.

--- Updated Main Thread Details ---


Thread Name: MyThread-Main
Thread Priority: 5
Thread ID: 1
Thread State: RUNNABLE
Is Daemon: false
Thread Group: main

--- Child Thread Details ---


Child Thread Name: InitialChildName
Child Thread New Name: MyChildThread-Worker
Child Thread Priority: 10
Child Thread Group: main
Child Thread State (in run): RUNNABLE
Main thread finished.

47. (c) User-defined exceptions TooHot and TooCold


Step 1: Define the custom exception classes.
TooHot.java

public class TooHot extends Exception {


public TooHot(String message) {
super(message);
}
}

TooCold.java

public class TooCold extends Exception {


public TooCold(String message) {
super(message);
}
}

Step 2: Write the Java program to use these exceptions.

public class TemperatureChecker {

public static void checkTemperature(int temperature) throws TooHot, TooCold {


System.out.println("Checking temperature: " + temperature + " degrees Celsius.");

if (temperature > 40) {


throw new TooHot("Temperature is Too Hot! (" + temperature + "°C)");
} else if (temperature < 20) {
throw new TooCold("Temperature is Too Cold! (" + temperature + "°C)");
} else {
System.out.println("Temperature is just right (" + temperature + "°C).");
}
}

public static void main(String[] args) {


int[] temperaturesToTest = {15, 25, 45, 10, 30, 50};

for (int temp : temperaturesToTest) {


try {
checkTemperature(temp);
} catch (TooHot e) {
System.err.println("Caught Exception: " + e.getMessage());
} catch (TooCold e) {
System.err.println("Caught Exception: " + e.getMessage());
} finally {
System.out.println("--- Temperature check complete for " + temp + "°C ---
}
}
}
}

Explanation:
1. Custom Exception Classes (TooHot, TooCold):
These classes extend java.lang.Exception, making them checked exceptions.
They each have a constructor that takes a message string, which is passed to the
superclass (Exception) constructor.
2. TemperatureChecker Class:
checkTemperature(int temperature) method:

It is declared with throws TooHot, TooCold because it can throw these checked
exceptions.
If temperature exceeds 40, it throws a new TooHot exception.
If temperature is less than 20, it throws a new TooCold exception.
Otherwise, it prints that the temperature is acceptable.
main method:

An array temperaturesToTest holds various temperature values.


It iterates through these temperatures.
For each temperature, it calls checkTemperature inside a try block.
There are separate catch blocks for TooHot and TooCold exceptions to handle them
specifically.
A finally block is included to print a separator message after each temperature
check, regardless of whether an exception was thrown or not.
To compile and run:
1. Save TooHot.java, TooCold.java, and TemperatureChecker.java in the same directory.
2. Compile: javac TooHot.java TooCold.java TemperatureChecker.java

3. Run: java TemperatureChecker

Expected Output:

Checking temperature: 15 degrees Celsius.


Caught Exception: Temperature is Too Cold! (15°C)
--- Temperature check complete for 15°C ---

Checking temperature: 25 degrees Celsius.


Temperature is just right (25°C).
--- Temperature check complete for 25°C ---

Checking temperature: 45 degrees Celsius.


Caught Exception: Temperature is Too Hot! (45°C)
--- Temperature check complete for 45°C ---

Checking temperature: 10 degrees Celsius.


Caught Exception: Temperature is Too Cold! (10°C)
--- Temperature check complete for 10°C ---

Checking temperature: 30 degrees Celsius.


Temperature is just right (30°C).
--- Temperature check complete for 30°C ---

Checking temperature: 50 degrees Celsius.


Caught Exception: Temperature is Too Hot! (50°C)
--- Temperature check complete for 50°C ---

48. (a) Similarities and differences: synchronized method vs. synchronized block
Similarities:
1. Purpose: Both synchronized methods and synchronized blocks are used to achieve thread
safety in Java by controlling access to shared resources. They prevent multiple threads
from concurrently executing critical sections of code that modify shared data, thus avoiding
race conditions and ensuring data consistency.
2. Locking Mechanism: Both rely on an intrinsic lock (also known as a monitor lock)
associated with an object. When a thread enters a synchronized method or block, it
acquires the lock; when it exits, it releases the lock.
3. Mutual Exclusion: Only one thread can hold the lock on a particular object at any given
time. Any other thread attempting to acquire the same lock will be blocked until the lock is
released.
4. Memory Visibility: Synchronization establishes a "happens-before" relationship. When a
thread releases a lock, any changes it made to shared variables are flushed to main
memory. When another thread acquires the same lock, it reads the updated values from
main memory. This ensures memory visibility across threads.
5. Reentrancy: Intrinsic locks in Java are reentrant. This means if a thread already holds the
lock on an object, it can re-acquire the same lock (e.g., by calling another synchronized
method on the same object) without deadlocking itself.
Differences:
Feature synchronized Method synchronized Block

The entire method body is


synchronized. The lock is
Scope of Only the specific block of code enclosed by
acquired when the method is
Lock synchronized(...) { ... } is synchronized.
entered and released when it
exits.

- For instance methods: The lock


is acquired on the instance of the
The lock can be acquired on any specified object. This
class (this object) on which the
object is explicitly provided in the parentheses:
method is invoked.
Lock Object synchronized(objectReference) { ... }. This
- For static methods: The lock is
can be this, another specific object, or even a dedicated
acquired on the Class object
lock object.
associated with the class (e.g.,
MyClass.class).

Coarse-grained locking. If a
method has multiple sections,
Fine-grained locking. Allows you to synchronize only the
only some of which need
Granularity critical sections of code, leaving non-critical parts
synchronization, the entire
outside the block, which can improve concurrency.
method is still locked, potentially
reducing concurrency.

Less flexible in choosing the lock More flexible. You can choose different objects to lock
on, allowing for more complex synchronization
Flexibility object (it's either this or the
strategies (e.g., locking on different objects to protect
Class object).
different shared resources).

Can sometimes lead to lower


Can potentially offer better performance by minimizing
performance if the synchronized
the time threads spend holding locks, thus increasing
Performance method is long and only a small
parallelism. However, overuse of fine-grained locking can
part of it needs protection, as
also add complexity.
threads wait longer.

Examples:
1. synchronized Method:

class CounterMethodSync {
private int count = 0;

// Entire method is synchronized on 'this' instance of CounterMethodSync


public synchronized void increment() {
// Critical section:
count++;
System.out.println(Thread.currentThread().getName() + " incremented count to: " +
// Other non-critical operations could also be here, but they'd still be under lo
}

public synchronized int getCount() {


return count;
}
}

class WorkerMethod implements Runnable {


CounterMethodSync counter;
public WorkerMethod(CounterMethodSync c) { this.counter = c; }
public void run() {
for (int i = 0; i < 3; i++) {
counter.increment();
try { Thread.sleep(10); } catch (InterruptedException e) {}
}
}
}

2. synchronized Block:

class CounterBlockSync {
private int count1 = 0;
private int count2 = 0;
private final Object lock1 = new Object(); // Dedicated lock object for count1
private final Object lock2 = new Object(); // Dedicated lock object for count2

public void incrementCount1() {


// Non-critical operations here
System.out.println(Thread.currentThread().getName() + " preparing to increment co

synchronized (lock1) { // Synchronized only on lock1


// Critical section for count1:
count1++;
System.out.println(Thread.currentThread().getName() + " incremented count1 to
}
// Other non-critical operations here
}

public void incrementCount2() {


// Non-critical operations here
System.out.println(Thread.currentThread().getName() + " preparing to increment co
synchronized (lock2) { // Synchronized only on lock2
// Critical section for count2:
count2++;
System.out.println(Thread.currentThread().getName() + " incremented count2 to
}
}

// Or synchronizing on 'this' for a specific block


public void incrementSharedCount() {
synchronized(this) { // Lock on the current instance for this block
count1++; // Assuming count1 is shared and needs this specific lock
}
}

public int getCount1() { synchronized(lock1) { return count1; } }


public int getCount2() { synchronized(lock2) { return count2; } }
}

class WorkerBlock implements Runnable {


CounterBlockSync counter;
public WorkerBlock(CounterBlockSync c) { this.counter = c; }
public void run() {
for (int i = 0; i < 3; i++) {
counter.incrementCount1();
counter.incrementCount2(); // Threads can interleave incrementCount1 and incr
try { Thread.sleep(10); } catch (InterruptedException e) {}
}
}
}

public class SyncDemo {


public static void main(String[] args) throws InterruptedException {
System.out.println("--- Synchronized Method Demo ---");
CounterMethodSync methodCounter = new CounterMethodSync();
Thread tm1 = new Thread(new WorkerMethod(methodCounter), "MethodWorker-1");
Thread tm2 = new Thread(new WorkerMethod(methodCounter), "MethodWorker-2");
tm1.start(); tm2.start();
tm1.join(); tm2.join();
System.out.println("Final count (method sync): " + methodCounter.getCount());

System.out.println("\n--- Synchronized Block Demo ---");


CounterBlockSync blockCounter = new CounterBlockSync();
Thread tb1 = new Thread(new WorkerBlock(blockCounter), "BlockWorker-A");
Thread tb2 = new Thread(new WorkerBlock(blockCounter), "BlockWorker-B");
tb1.start(); tb2.start();
tb1.join(); tb2.join();
System.out.println("Final count1 (block sync): " + blockCounter.getCount1());
System.out.println("Final count2 (block sync): " + blockCounter.getCount2());
}
}

In CounterBlockSync, incrementCount1() and incrementCount2() can be executed concurrently by


different threads if they use different lock objects (lock1 and lock2), leading to potentially higher
throughput compared to if both operations were part of a single, larger synchronized method.
When to use which:
Use synchronized method if the entire logic of the method manipulates shared state and
needs to be protected. It's simpler to write.
Use synchronized block for finer control:
When only a part of a method needs synchronization.
When you need to lock on an object other than this or the Class object.
When you want to use different locks to protect different resources within the same
class, allowing more concurrency.

48. (b) Java Swing program for addition

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

public class SimpleCalculator extends JFrame implements ActionListener {


JTextField numField1;
JTextField numField2;
JTextField resultField;
JButton addButton;
JLabel plusLabel;
JLabel equalsLabel;

public SimpleCalculator() {
// Frame setup
setTitle("Simple Adder");
setSize(400, 150);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLayout(new FlowLayout(FlowLayout.CENTER, 10, 20)); // Centered FlowLayout with

// Initialize components
numField1 = new JTextField(5); // Approximate width for 5 characters
numField1.setToolTipText("Enter first number");

plusLabel = new JLabel("+");

numField2 = new JTextField(5);


numField2.setToolTipText("Enter second number");

equalsLabel = new JLabel("=");

resultField = new JTextField(8);


resultField.setToolTipText("Result of addition");
resultField.setEditable(false); // Result field should not be directly editable
resultField.setFont(new Font("Arial", Font.BOLD, 14)); // Make result stand out

addButton = new JButton("Add");


addButton.setToolTipText("Click to perform addition");

// Add components to the frame


add(new JLabel("Number 1:"));
add(numField1);
add(plusLabel);
add(new JLabel("Number 2:"));
add(numField2);
add(addButton); // Place button before equals and result for better flow
add(equalsLabel);
add(resultField);

// Register action listener for the button


addButton.addActionListener(this);

// Make the frame visible


setLocationRelativeTo(null); // Center on screen
setVisible(true);
}

@Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() == addButton) {
try {
// Get numbers from text fields
double num1 = Double.parseDouble(numField1.getText().trim());
double num2 = Double.parseDouble(numField2.getText().trim());

// Perform addition
double sum = num1 + num2;

// Display result
resultField.setText(String.valueOf(sum));
resultField.setForeground(Color.BLACK); // Reset color on success

} catch (NumberFormatException ex) {


// Handle invalid input (non-numeric)
resultField.setText("Error!");
resultField.setForeground(Color.RED); // Indicate error
JOptionPane.showMessageDialog(this,
"Invalid input. Please enter valid numbers.",
"Input Error",
JOptionPane.ERROR_MESSAGE);
numField1.requestFocus(); // Set focus to the first field
} catch (Exception ex) {
// Handle any other unexpected errors
resultField.setText("Error!");
resultField.setForeground(Color.RED);
JOptionPane.showMessageDialog(this,
"An unexpected error occurred: " + ex.getMessage(),
"Error",
JOptionPane.ERROR_MESSAGE);
}
}
}

public static void main(String[] args) {


// Ensure GUI updates are done on the Event Dispatch Thread
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new SimpleCalculator();
}
});
}
}

Explanation:
1. Class SimpleCalculator: Extends JFrame to create the main window and implements
ActionListener to handle button clicks.

2. Components:
numField1, numField2: JTextFields for user to input two numbers.
resultField: A JTextField (set to non-editable) to display the sum.
addButton: A JButton labeled "Add".
plusLabel, equalsLabel: JLabels for "+" and "=".
3. Constructor SimpleCalculator():
Sets up the frame's title, size, close operation, and layout manager (FlowLayout).
Initializes all Swing components. setToolTipText is used to provide hints.
Adds the components to the frame in a logical order.
Registers this (the SimpleCalculator instance) as an ActionListener for the addButton.
This means the actionPerformed method will be called when the button is clicked.
Makes the frame visible.
4. actionPerformed(ActionEvent e) method:

This method is invoked when the addButton is clicked (e.getSource() == addButton).

It uses a try-catch block to handle potential NumberFormatException if the user enters


non-numeric text.
numField1.getText().trim() and numField2.getText().trim(): Get the text from input
fields and trim() whitespace.
Double.parseDouble(): Converts the string inputs to double values.
The sum is calculated.
resultField.setText(String.valueOf(sum)): The sum is converted back to a string and
displayed in the resultField.
If a NumberFormatException occurs, an error message is displayed in resultField and a
JOptionPane dialog appears.

5. main method:
SwingUtilities.invokeLater(...): This is the standard and recommended way to create
and show Swing GUIs. It ensures that GUI-related code is executed on the Event
Dispatch Thread (EDT), which is crucial for thread safety in Swing.
This program provides a simple graphical interface for adding two numbers.

49. (a) Methods of JFrame, JLabel, JPanel


Here are explanations and examples of two methods for each JFrame, JLabel, and JPanel in Java
Swing:
JFrame

JFrame is a top-level window with a title and a border.


1. setSize(int width, int height)
Purpose: Sets the dimensions (width and height in pixels) of the frame.
Example:
import javax.swing.JFrame;

public class JFrameExample {


public static void main(String[] args) {
JFrame myFrame = new JFrame("My Application Window");
myFrame.setSize(400, 300); // Sets the frame to be 400 pixels wide and 30
myFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
myFrame.setVisible(true);
}
}

2. setVisible(boolean b)

Purpose: Shows or hides the frame. If b is true, the frame is made visible; if false, it's
hidden. This method is crucial because frames are not visible by default after creation.
Example: (Combined with the above)
import javax.swing.JFrame;

public class JFrameExample {


public static void main(String[] args) {
JFrame myFrame = new JFrame("My Application Window");
myFrame.setSize(400, 300);
myFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// ... add components to myFrame ...
myFrame.setVisible(true); // Makes the frame appear on the screen
}
}

Note: It's generally recommended to call setVisible(true) after adding all components
and setting other properties of the frame.
JLabel

JLabel is a display area for a short text string, an image, or both.


1. setText(String text)
Purpose: Sets the text string that the label displays. If the label previously displayed an
image, it will be replaced by the text.
Example:
import javax.swing.*;
import java.awt.FlowLayout;

public class JLabelExample {


public static void main(String[] args) {
JFrame frame = new JFrame("JLabel Demo");
frame.setLayout(new FlowLayout());
frame.setSize(300, 100);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

JLabel myLabel = new JLabel("Initial Text");


frame.add(myLabel);
frame.setVisible(true);

// Later, you might change the text:


try { Thread.sleep(2000); } catch (InterruptedException e) {}
myLabel.setText("Updated Text for Label!");
}
}
2. setIcon(Icon icon)
Purpose: Sets the image that the label displays. The Icon interface is typically
implemented by ImageIcon.
Example: (Assuming you have an image file named smile.png in your project's root or
classpath)
import javax.swing.*;
import java.awt.FlowLayout;

public class JLabelImageExample {


public static void main(String[] args) {
JFrame frame = new JFrame("JLabel Image Demo");
frame.setLayout(new FlowLayout());
frame.setSize(300, 200);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

JLabel imageLabel = new JLabel();


// Load an image icon (ensure 'smile.png' is accessible)
// For robust path handling, use getResource:
// ImageIcon smileIcon = new ImageIcon(JLabelImageExample.class.getResour
// If smile.png is in the same directory as the .class files (or root of
ImageIcon smileIcon = new ImageIcon("smile.png");

if (smileIcon.getImageLoadStatus() == java.awt.MediaTracker.ERRORED) {
System.err.println("Error loading image smile.png");
imageLabel.setText("Image not found");
} else {
imageLabel.setIcon(smileIcon);
imageLabel.setText("Smiling!"); // Can have text and icon
imageLabel.setHorizontalTextPosition(JLabel.CENTER);
imageLabel.setVerticalTextPosition(JLabel.BOTTOM);
}
frame.add(imageLabel);
frame.setVisible(true);
}
}

JPanel

JPanel is a generic lightweight container used to organize and group other components.
1. add(Component comp)
Purpose: Adds a specified component to this panel. The placement of the component
depends on the layout manager set for the panel.
Example:
import javax.swing.*;
import java.awt.BorderLayout; // Using a layout manager

public class JPanelExample {


public static void main(String[] args) {
JFrame frame = new JFrame("JPanel Demo");
frame.setSize(300, 200);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

JPanel mainPanel = new JPanel();


mainPanel.setLayout(new BorderLayout()); // Set a layout manager for the

JLabel nameLabel = new JLabel("Name:");


JTextField nameField = new JTextField(15);
JButton submitButton = new JButton("Submit");

// Add components to the panel


mainPanel.add(nameLabel, BorderLayout.WEST); // Add label to the west
mainPanel.add(nameField, BorderLayout.CENTER); // Add text field to the
mainPanel.add(submitButton, BorderLayout.SOUTH); // Add button to the sou

frame.add(mainPanel); // Add the panel to the frame


frame.setVisible(true);
}
}

2. setLayout(LayoutManager mgr)
Purpose: Sets the layout manager for this panel. The layout manager determines how
components are arranged within the panel (e.g., FlowLayout, BorderLayout, GridLayout,
GridBagLayout). If no layout manager is set, JPanel uses FlowLayout by default.

Example: (Shown in the JPanel.add() example above)


// ... (inside JPanelExample main method)
JPanel controlPanel = new JPanel();
// Set the layout to GridLayout with 2 rows and 1 column
controlPanel.setLayout(new GridLayout(2, 1));

JButton okButton = new JButton("OK");


JButton cancelButton = new JButton("Cancel");

controlPanel.add(okButton);
controlPanel.add(cancelButton);

// frame.add(controlPanel, BorderLayout.EAST); // If frame uses BorderLayout


// ...

Setting the layout manager is crucial for controlling the visual organization of
components within the panel.
These methods are fundamental to building GUIs with Swing. JFrame provides the window, JPanel
helps organize content within it, and JLabel displays static information or images.

49. (b) What is package? What is the use of it? Why do we need import
statement?
What is a Package?
(This was also covered in question 43(c))
In Java, a package is a namespace that organizes a set of related classes and interfaces. It's a
mechanism for:
Grouping logically related types.
Preventing naming conflicts between classes from different sources.
Controlling access to types and their members.
Think of packages like folders in a file system, where each folder contains related files. The Java
platform itself provides a vast library of classes organized into packages (e.g., java.lang,
java.util, java.io, javax.swing).

What is the use of it? (Why are packages needed?)


1. Organization and Modularity:
Packages help structure large applications by breaking them down into smaller,
manageable, and logical units. This improves code readability and maintainability.
For example, all GUI-related classes might be in a com.example.ui package, data access
classes in com.example.dao, and utility classes in com.example.util.
2. Naming Conflict Prevention (Namespace Management):
Without packages, all class names would have to be unique across an entire project or
even across all libraries used. This would be extremely difficult to manage.
Packages provide a unique namespace. A class is uniquely identified by its fully
qualified name (FQN), which is packageName.ClassName.
For instance, java.util.Date and java.sql.Date are two different classes named Date
because they reside in different packages.
3. Access Control:
Packages play a role in Java's access control mechanism.
The default (package-private) access level allows a class, method, or variable to be
accessed only by other code within the same package.
The protected access specifier also considers package boundaries for visibility to non-
subclasses.
4. Reusability and Distribution:
Well-defined packages can be easily reused in other projects.
Libraries are distributed as collections of packages (often in JAR files).
5. Encapsulation at a Higher Level:
Packages can be seen as a way to encapsulate a set of related functionalities, exposing
only necessary public classes and interfaces while hiding internal implementation
details.
Why do we need import statement?
The import statement in Java allows you to refer to classes and interfaces by their simple names
(e.g., ArrayList) rather than their fully qualified names (e.g., java.util.ArrayList) in your code.
Purpose of import:
1. Convenience and Readability:
Using fully qualified names everywhere would make code verbose and harder to read.
import statements let the compiler know which specific class you mean when you use a
simple name.
Example:
// Without import
java.util.ArrayList<String> list1 = new java.util.ArrayList<>();
java.util.HashMap<String, Integer> map1 = new java.util.HashMap<>();

// With import
import java.util.ArrayList;
import java.util.HashMap;
// ...
ArrayList<String> list2 = new ArrayList<>();
HashMap<String, Integer> map2 = new HashMap<>();

2. Avoiding Ambiguity (when simple names might clash):


If you need to use two classes with the same simple name from different packages, you
must use the fully qualified name for at least one of them, or for both if you don't import
either. The import statement helps resolve which one is referred to by the simple name.
If you import both, it will lead to a compilation error due to ambiguity unless you use
FQNs.
Example:
import java.util.Date;
// import java.sql.Date; // This would cause an error if both are imported and 'D

public class DateDemo {


public static void main(String[] args) {
java.util.Date utilDate = new java.util.Date(); // Using FQN for clarity
Date anotherUtilDate = new Date(); // Refers to java.util.Date due to the

java.sql.Date sqlDate = new java.sql.Date(System.currentTimeMillis()); //


}
}

Types of import statements:


1. Single-Type Import: Imports a specific class or interface.
import packageName.ClassName;
Example: import java.util.ArrayList;

2. On-Demand (Wildcard) Import: Imports all public classes and interfaces from a package.
import packageName.*;
Example: import java.util.*;

This does not import sub-packages.


It does not increase the size of the compiled code; it's just a convenience for the
compiler during compilation.
Some style guides prefer single-type imports for explicitness, while others find on-
demand imports acceptable for commonly used packages like java.util.
Note: Classes in the java.lang package (like String, Integer, System, Object) are automatically
imported into every Java source file, so you don't need to explicitly import them.
In summary, packages organize code, and import statements make it convenient to use types
from those packages without constantly typing their full names.

49. (c) Write the uses of finally block in Java.


The finally block in Java's try-catch-finally exception handling structure is used to execute a
block of code regardless of whether an exception is thrown or caught within the try block, or
even if a return, break, or continue statement causes control to leave the try or catch block.
Key Uses of the finally Block:
1. Resource Cleanup and Deallocation:
This is the most common and crucial use of finally. It ensures that resources acquired
in the try block are released, preventing resource leaks.
Examples:
Closing files: FileInputStream, FileOutputStream, FileReader, FileWriter, etc.
Closing network connections: Socket, ServerSocket.
Closing database connections: Connection, Statement, ResultSet.
Releasing locks or other synchronization primitives.
Closing other system resources like graphics contexts or native resources.

import java.io.FileInputStream;
import java.io.IOException;

public class FinallyResourceCleanup {


public static void readFile(String filePath) {
FileInputStream fis = null;
try {
fis = new FileInputStream(filePath);
System.out.println("File opened successfully.");
int data = fis.read(); // Might throw IOException
while (data != -1) {
System.out.print((char) data);
data = fis.read();
}
} catch (IOException e) {
System.err.println("\nError reading file: " + e.getMessage());
} finally {
System.out.println("\nExecuting finally block.");
if (fis != null) {
try {
fis.close(); // Ensure the file stream is closed
System.out.println("File stream closed.");
} catch (IOException e) {
System.err.println("Error closing file stream: " + e.getMessage()
}
}
}
}
public static void main(String[] args) {
readFile("test.txt"); // Assuming test.txt exists or doesn't
}
}

Note: With Java 7 and later, the try-with-resources statement provides a more concise way
to handle resource cleanup for resources that implement AutoCloseable.
2. Guaranteed Code Execution:
Sometimes, there's code that absolutely must run after a try block, irrespective of
exceptions or control flow changes (like return statements). finally guarantees this
execution.
Example: Resetting a state, logging completion of an operation.

public class FinallyGuaranteedExecution {


public static int processValue(int value) {
try {
System.out.println("In try block. Value: " + value);
if (value < 0) {
throw new IllegalArgumentException("Value cannot be negative.");
}
if (value == 0) {
System.out.println("Returning from try block.");
return 100; // Control leaves here
}
return value * 2;
} catch (IllegalArgumentException e) {
System.err.println("Caught exception: " + e.getMessage());
System.out.println("Returning from catch block.");
return -1; // Control leaves here
} finally {
// This block will execute even if return statements are hit in try or ca
System.out.println("Executing finally block after processing value: " + v
}
// Code here would be unreachable if try/catch always returns.
}

public static void main(String[] args) {


System.out.println("Result for 5: " + processValue(5));
System.out.println("\nResult for 0: " + processValue(0));
System.out.println("\nResult for -5: " + processValue(-5));
}
}

Output of processValue(0):
In try block. Value: 0
Returning from try block.
Executing finally block after processing value: 0
Result for 0: 100

3. Preventing Dangling State:


If an operation modifies some state and an exception occurs midway, the finally block
can be used to revert the state to a consistent or known condition.
Important Considerations:
If an exception is thrown in the finally block itself, and there's no catch for it within the
finally block, then this new exception will propagate, potentially masking any exception
that might have been thrown from the try or catch block.
A finally block will execute even if the try block or a catch block has a return statement.
A finally block will not execute if the JVM exits during the try or catch block (e.g., due to
System.exit()) or if a catastrophic error occurs that halts the JVM (like a hardware failure or
an unrecoverable JVM error).
In modern Java (7+), try-with-resources is often preferred for resource management as it's
more concise and less error-prone for closing

50. (a) Explain how an event delegation model


works. Write a Java swingprogram to explain the
said
concept.
(b) What is the default type of variables in an interface?
(c) Consider the following Java program:
import java.util.*;
interface Department {
String depName="CSE";
void display();
}
class TestDepartment implements Department{
public void display() {
depName="CSE(AIML)";
System.out.println("Department name is" + depName);
}
public static void main(String args []) {
Department ref = new TestDepartment ();
ref.display();
}
}
Is there any error in the code? If yes fix the error.
51. (a) How is an abstract class different from an interface?
(b) How is an abstract class different from an interface?explain with example
(c) What is meant by Garbage Collection in OOPs world?
52. (a) What will be the output of the below code?
class Scaler
{
static int i;
static
{
System.out.println(“a”);
i = 100;
}
}
public class StaticBlock
{
static
{
System.out.println(“b”);
}
public static void main(String[] args)
{
System.out.println(“c”);
System.out.println(Scaler.i);
}
}
b)what is destructor?
c) Difference between an Error and an Exception.
Certainly! Here are the answers to your questions 50 to 52 in proper question-answer format:

50. (a) Event Delegation Model and Example in Java Swing

Event Delegation Model Explanation


The event delegation model in Java is a design pattern that handles events by delegating
event-handling responsibilities to separate listener objects rather than directly processing them
in the event source object.
Key points:
The source component generates events (e.g., button clicks).
Event listeners register with event sources to receive event notifications.
When an event occurs, the event source dispatches the event to registered listener objects.
This model improves modularity and efficiency as multiple listeners can share event-
handling logic, and the events are dispatched to appropriate objects.
Advantages:
Separation of event-handling logic from GUI components.
Multiple listeners can listen to the same event.
Improves reuse and organization of code.

Java Swing Example Demonstrating Event Delegation

import javax.swing.*;
import java.awt.event.*;

public class EventDelegationDemo extends JFrame implements ActionListener {


private JButton button;

public EventDelegationDemo() {
setTitle("Event Delegation Example");
setSize(300, 150);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLayout(null);

button = new JButton("Click Me");


button.setBounds(100, 40, 100, 30);

// Register the listener (this class) to the button's action event


button.addActionListener(this);

add(button);

setVisible(true);
}

// This method handles the button click event


@Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() == button) {
JOptionPane.showMessageDialog(this, "Button was clicked!");
}
}

public static void main(String[] args) {


new EventDelegationDemo();
}
}

Explanation:
The button is the event source.
The EventDelegationDemo class implements ActionListener and registers itself as the listener
on the button.
When the button is clicked, the actionPerformed method is invoked with the event object,
and we can handle the event accordingly.
50. (b) Default Type of Variables in an Interface
All variables declared in a Java interface are implicitly:
public

static

final

That means interface variables are constants accessible globally and cannot be changed.
Example:

interface MyInterface {
int VALUE = 100; // public static final int VALUE = 100;
}

50. (c) Code Analysis and Fix


Given code:

import java.util.*;
interface Department {
String depName="CSE";
void display();
}
class TestDepartment implements Department{
public void display() {
depName="CSE(AIML)"; // Error here
System.out.println("Department name is" + depName);
}
public static void main(String args []) {
Department ref = new TestDepartment ();
ref.display();
}
}

Is there an error?
Yes. The error is here:

depName = "CSE(AIML)";

Because:
depName in an interface is implicitly public static final (a constant).
You cannot assign a new value to a final variable.
Fixed Code
To fix the error, depName should be declared as a non-final variable, which is not possible in
interfaces. Instead, use an instance variable inside the class to store modifiable data.
Solution: Remove depName from interface and define it in the class:

interface Department {
void display();
}

class TestDepartment implements Department {


String depName = "CSE";

public void display() {


depName = "CSE(AIML)"; // Legal now, class instance variable
System.out.println("Department name is " + depName);
}

public static void main(String args[]) {


Department ref = new TestDepartment();
ref.display();
}
}

51. (a) How is an abstract class different from an interface?


Abstract Class Interface

Can have both abstract and concrete Traditionally only abstract methods (without implementation); since
methods (with implementation). Java 8, default and static methods with implementation are allowed.

Can have instance variables (fields)


Can only have public static final variables (constants).
with any access modifiers.

Supports constructors. No constructors allowed.

A class can extend only one abstract A class can implement multiple interfaces (multiple inheritance of
class (single inheritance). type).

Provides partial implementation. Provides full abstraction (before Java 8).

All methods and variables are public (variables are static final,
Can have protected/private members.
methods are public).

51. (b) Explanation with Example


Abstract Class Example

abstract class Animal {


abstract void sound(); // Abstract method

void sleep() { // Concrete method


System.out.println("Sleeping...");
}
}

class Dog extends Animal {


void sound() {
System.out.println("Barking...");
}
}

public class Main {


public static void main(String[] args) {
Dog d = new Dog();
d.sound(); // Output: Barking...
d.sleep(); // Output: Sleeping...
}
}

Interface Example

interface Animal {
void sound(); // Abstract method (implicitly public)
}

class Dog implements Animal {


public void sound() { // Must be public
System.out.println("Barking...");
}
}

public class Main {


public static void main(String[] args) {
Dog d = new Dog();
d.sound(); // Output: Barking...
}
}

51. (c) Garbage Collection in OOPs


Garbage Collection (GC) is an automatic memory management process in object-oriented
programming languages like Java.
It automatically identifies and frees memory occupied by objects that are no longer
referenced or needed by the program.
This prevents memory leaks and ensures efficient use of memory.
Developers do not need to manually release memory; GC runs in the background to reclaim
memory from objects that are unreachable.

52. (a) Output of the code

class Scaler {
static int i;
static {
System.out.println("a");
i = 100;
}
}

public class StaticBlock {


static {
System.out.println("b");
}
public static void main(String[] args) {
System.out.println("c");
System.out.println(Scaler.i);
}
}

Explanation of output:
When StaticBlock class is loaded, its static block executes first: prints "b".
The main method runs and prints "c".
When Scaler.i is accessed for the first time inside main, the Scaler class is loaded, and its
static block runs, printing "a".
Then the value of Scaler.i (which is 100) is printed.

Final output:

b
c
a
100

52. (b) What is destructor?


Java does not have destructors, unlike C++.
Instead, Java uses garbage collection to automatically reclaim memory of objects that are
no longer in use.
The method finalize() can be overridden to perform cleanup before the GC destroys an
object, but it is deprecated and not reliable.
Resource management should be done explicitly (e.g., closing files in finally blocks or
using try-with-resources).

52. (c) Difference between an Error and an Exception


Aspect Exception Error

Conditions that applications might want to Serious problems from which an


Definition
catch and recover from. application usually cannot recover.

Hierarchy Subclass of java.lang.Exception. Subclass of java.lang.Error.

Checked or unchecked exceptions.


Unchecked. Generally not handled by
Checked/Unchecked Checked exceptions must be handled or
applications.
declared.

OutOfMemoryError,
IOException, NullPointerException,
Examples StackOverflowError,
SQLException.
VirtualMachineError.

Generally not intended to be caught by


Handling Applications can catch and recover.
application code.

Mostly caused by program errors or Caused by serious JVM problems or


Cause
unusual but recoverable conditions. hardware failures.

If you need further clarifications or code samples, feel free to ask!

You might also like