28. (a) Java Virtual Machine (JVM) and Portability
28. (a) Java Virtual Machine (JVM) and Portability
Abstract Can have abstract and concrete All methods are implicitly abstract (since Java 5, can
Methods methods have default methods)
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;
}
}
@Override
double area() {
return Math.PI * radius * radius;
}
}
// Interface
interface Drawable {
void draw(); // Abstract method
}
protected Accessible within the same package and by subclasses in different packages.
class BankAccount {
private String accountNumber;
private double balance;
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).
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.
Compile-
Resolved at compile time. Resolved at runtime.
time/Runtime
Output:
Sum: 15
class MyClass {
int x;
public MyClass(int x) {
this.x = x;
}
}
class Animal {
String name;
public Animal(String name) {
this.name = name;
}
class Singleton {
private static Singleton instance;
private Singleton() {
// Private constructor to prevent instantiation from outside
}
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.
// final
final class FinalClass {
final int x = 10;
// 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");
}
package mypackage;
class Animal {
String name;
@Override
public void eat() {
super.eat(); // Call the superclass method
System.out.println("Dog is eating");
}
}
class MyClass {
static int sharedVariable = 0;
public MyClass() {
sharedVariable++;
}
@Override
void start() {
System.out.println("Car started");
}
}
Output:
Car started
Model Name: BMW
interface Animal {
void makeSound();
void eat();
}
@Override
public void eat() {
System.out.println("Dog is eating");
}
}
Output:
Woof!
Dog is eating
class Semester_answer {
String name;
int roll;
int no_of_questions_attempted;
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)
protected offers morevisibility than default by allowing access to subclasses outside the
package, which is crucial for inheritance across package boundaries.
@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.");
}
}
threadOne.start();
threadTwo.start();
threadThree.start();
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.
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
@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
@Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() == convertButton) {
String inputText = inputField.getText();
StringBuilder convertedText = new StringBuilder();
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.
interface Flyable {
void fly(); // Abstract method
}
interface Swimmable {
void swim(); // Abstract method
}
@Override
public void fly() {
System.out.println(name + " is flying.");
}
@Override
public void swim() {
System.out.println(name + " is swimming.");
}
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.
To provide a common base for related To define a contract that unrelated classes can
Purpose
classes, sharing some implementation. implement.
Can have instance variables (non-static, Can only have public static final
Variables
non-final) and constants. variables (constants).
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.
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).
// Concrete method
public String getColor() {
return color;
}
}
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.
import javax.swing.*;
import java.awt.*;
frame.setVisible(true);
}
}
Explanation:
1. PolygonPanel class: Extends JPanel. Custom drawing is done by overriding the
paintComponent(Graphics g) method.
2. paintComponent(Graphics g):
import java.applet.Applet;
import java.awt.*;
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
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.
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.
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.
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.
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:
@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.");
}
}
t1.start();
t2.start();
}
}
2. Implementing Runnable:
@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.");
}
}
t1.start();
t2.start();
}
}
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)).
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).
package shape;
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;
(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;
import shape.Circle;
import shape.Rectangle;
import shape.Triangle;
// 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();
} catch (IllegalArgumentException e) {
System.err.println("Error creating shape: " + e.getMessage());
}
}
}
This demonstrates creating a package, defining classes within it, and then importing and using
those classes in another program.
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();
}
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.
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:.
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.
// TriangleException.java
public class TriangleException extends Exception {
public TriangleException(String message) {
super(message);
}
}
// Triangle.java
public class Triangle {
private double sideA;
private double sideB;
private double sideC;
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.
Expected Output:
package mycomplex;
// 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);
}
}
c1 + c2 = 3.5 + 1.5i
c1 - c2 = 1.5 + 4.5i
c1 * c2 = 7.0 - 0.75i
@Override
public String getTask() { // Implemented method
return currentTask;
}
@Override
public void takeBreak() { // Implemented method
System.out.println("Taking a 15-minute coffee break.");
}
@Override
public void work() { // Programmer provides the missing implementation
System.out.println("Programmer is working on: " + getTask());
}
}
@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.
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);
}
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
// ...
}
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;
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
}
}
In essence, this refers to the current object instance, while super refers to the superclass portion
of the current object instance.
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.
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
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:
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).
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;
// 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.");
}
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 ...
}
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):
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
// 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
}
// 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
}
@Override
public void run() {
try {
sharedBuffer.produce();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
System.out.println("Producer interrupted.");
}
}
}
@Override
public void run() {
try {
sharedBuffer.consume();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
System.out.println("Consumer interrupted.");
}
}
}
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.
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.
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:
TooCold.java
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:
Expected Output:
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
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).
Examples:
1. synchronized Method:
class CounterMethodSync {
private int count = 0;
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
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
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");
@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
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:
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.
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;
Note: It's generally recommended to call setVisible(true) after adding all components
and setting other properties of the frame.
JLabel
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
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.
controlPanel.add(okButton);
controlPanel.add(cancelButton);
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).
// With import
import java.util.ArrayList;
import java.util.HashMap;
// ...
ArrayList<String> list2 = new ArrayList<>();
HashMap<String, Integer> map2 = new HashMap<>();
2. On-Demand (Wildcard) Import: Imports all public classes and interfaces from a package.
import packageName.*;
Example: import java.util.*;
import java.io.FileInputStream;
import java.io.IOException;
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.
Output of processValue(0):
In try block. Value: 0
Returning from try block.
Executing finally block after processing value: 0
Result for 0: 100
import javax.swing.*;
import java.awt.event.*;
public EventDelegationDemo() {
setTitle("Event Delegation Example");
setSize(300, 150);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLayout(null);
add(button);
setVisible(true);
}
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;
}
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();
}
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.
A class can extend only one abstract A class can implement multiple interfaces (multiple inheritance of
class (single inheritance). type).
All methods and variables are public (variables are static final,
Can have protected/private members.
methods are public).
Interface Example
interface Animal {
void sound(); // Abstract method (implicitly public)
}
class Scaler {
static int i;
static {
System.out.println("a");
i = 100;
}
}
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
OutOfMemoryError,
IOException, NullPointerException,
Examples StackOverflowError,
SQLException.
VirtualMachineError.