OOPJ SEM 4 PAPER SOLUTION (15/07/2023)
Q.1
(a) Differentiate between Procedure-Oriented Programming
(POP) and Object-Oriented Programming (OOP).
Procedure-Oriented Programming (POP)
- **Concept:** Focuses on functions/procedures.
- **Primary Elements:** Functions and data structures.
- **Data Handling:** Separate; data is passed to functions.
- **Modularity:** Achieved through functions.
- **Abstraction:** Functional abstraction.
- **Inheritance:** Not supported directly.
- **Polymorphism:** Not inherently supported.
- **Encapsulation:** Not inherent; data is exposed.
- **Maintenance:** Can become difficult as programs grow.
- **Examples:** C, Pascal.
Object-Oriented Programming (OOP)
- **Concept:** Focuses on objects and classes.
- **Primary Elements:** Objects and classes.
- **Data Handling:** Bundled within objects.
- **Modularity:** Achieved through objects and classes.
- **Abstraction:** Data abstraction and encapsulation.
- **Inheritance:** Supported, promoting code reuse.
- **Polymorphism:** Supported through method overriding and interfaces.
- **Encapsulation:** Core principle; objects manage their own state.
- **Maintenance:** Easier due to modularity and encapsulation.
- **Examples:** C++, Java, Python, C#.
(b) Explain Super keyword in inheritance with suitable example.
In Java, the `super` keyword is used in inheritance to refer to the parent class. It
is typically used for:
1. **Calling the parent class constructor:**
Ensures the parent class is properly initialized.
2. **Accessing parent class methods and properties:**
Allows the child class to utilize or override functionality from the parent class.
Example
class Parent {
String name;
Parent(String name) {
this.name = name;
}
void display() {
System.out.println("Parent Name: " + name);
}
}
class Child extends Parent {
int age;
Child(String name, int age) {
super(name); // Calls Parent's constructor
this.age = age;
}
@Override
void display() {
super.display(); // Calls Parent's display method
System.out.println("Child Age: " + age);
}
}
public class Main {
public static void main(String[] args) {
Child c = new Child("John", 25);
c.display();
}
}
Explanation
- **`super(name)`**: Calls the constructor of the parent class (`Parent`) to
initialize the `name` attribute.
- **`super.display()`**: Calls the `display` method of the parent class to print
the parent's name.
- The `Child` class then adds its own behavior to print the child's age.
Output:
```
Parent Name: John
Child Age: 25
This demonstrates how `super` facilitates proper initialization and method
inheritance from the parent class in Java.
(c) Define: Method Overriding. List out Rules for method overriding.
Write a java program that implements method overriding.
Method Overriding
**Definition:**
Method overriding occurs when a subclass provides a specific implementation
of a method that is already defined in its superclass. The overridden method in
the subclass should have the same name, return type, and parameters as the
method in the superclass.
Rules for Method Overriding
1. **Same Method Signature:** The method in the subclass must have the
same name, return type, and parameters as the method in the superclass.
2. **Access Modifier:** The access level cannot be more restrictive than the
overridden method's access level. For example, if the superclass method is
`protected`, the subclass method cannot be `private`.
3. **Instance Methods:** Only instance methods can be overridden, not static
methods.
4. **Superclass Method:** The method to be overridden must be defined in
the superclass.
5. **Non-Private Methods:** The method must not be `private` or `final` in the
superclass.
6. **Covariant Return Types:** The return type can be a subclass of the return
type declared in the original method.
Example Java Program Implementing Method Overriding
class Animal {
void sound() {
System.out.println("Animal makes a sound");
}
}
class Dog extends Animal {
@Override
void sound() {
System.out.println("Dog barks");
}
}
public class Main {
public static void main(String[] args) {
Animal myAnimal = new Animal();
Animal myDog = new Dog();
myAnimal.sound(); // Calls Animal's sound method
myDog.sound(); // Calls Dog's sound method (overridden)
}
}
Explanation
- **`Animal` class:** Defines a method `sound()`.
- **`Dog` class:** Extends `Animal` and overrides the `sound()` method with its
own implementation.
- **`main` method:** Demonstrates the use of method overriding by calling
the `sound()` method on both `Animal` and `Dog` objects.
Output:
Animal makes a sound
Dog barks
This example shows how the `Dog` class overrides the `sound()` method of the
`Animal` class, providing a specific implementation for dogs.
(c) Describe: Interface. Write a java program using interface to
demonstrate multiple inheritance.
Interface
**Definition:**
An interface in Java is a reference type, similar to a class, that can contain only
constants, method signatures, default methods, static methods, and nested
types. Interfaces cannot contain instance fields or constructors. They are used
to achieve abstraction and multiple inheritance in Java.
Example Java Program Using Interface to Demonstrate Multiple Inheritance
interface Animal {
void eat();
}
interface Pet {
void play();
}
class Dog implements Animal, Pet {
@Override
public void eat() {
System.out.println("Dog eats.");
}
@Override
public void play() {
System.out.println("Dog plays.");
}
}
public class Main {
public static void main(String[] args) {
Dog myDog = new Dog();
myDog.eat(); // Calls eat method from Animal interface
myDog.play(); // Calls play method from Pet interface
}
}
Explanation
- **`Animal` interface:** Declares the `eat()` method.
- **`Pet` interface:** Declares the `play()` method.
- **`Dog` class:** Implements both `Animal` and `Pet` interfaces, providing
implementations for `eat()` and `play()` methods.
- **`main` method:** Creates a `Dog` object and calls its `eat()` and `play()`
methods, demonstrating multiple inheritance through interfaces.
Output:
Dog eats.
Dog plays.
This example shows how Java allows a class (`Dog`) to inherit behavior from
multiple interfaces (`Animal` and `Pet`), demonstrating multiple inheritance.
Q.2
(a) Explain the Java Program Structure with example.
A typical Java program structure includes the following components:
1. **Package Declaration (optional):** Defines the package to which the class
belongs.
2. **Import Statements (optional):** Imports other Java classes or packages
needed in the program.
3. **Class Definition:** Defines the class, which is the fundamental unit of a
Java program.
4. **Main Method:** The entry point of any Java program. This method is
where the program starts execution.
Example Java Program
// Package declaration (optional)
package com.example;
// Import statements (optional)
import java.util.Scanner;
// Class definition
public class HelloWorld {
// Main method
public static void main(String[] args) {
// Print a message to the console
System.out.println("Hello, World!");
// Using Scanner for user input
Scanner scanner = new Scanner(System.in);
System.out.println("Enter your name:");
String name = scanner.nextLine();
System.out.println("Hello, " + name + "!");
// Close the scanner
scanner.close();
}
}
Explanation of the Example
1. **Package Declaration:**
package com.example;
- Specifies that the class belongs to the `com.example` package. This is
optional and can be omitted if not using packages.
2. **Import Statements:**
import java.util.Scanner;
- Imports the `Scanner` class from the `java.util` package to allow user input.
3. **Class Definition:**
public class HelloWorld {
- Defines a public class named `HelloWorld`.
4. **Main Method:**
public static void main(String[] args) {
- The entry point of the program. This method is executed when the program
runs.
5. **Print Statement and User Input:**
```java
System.out.println("Hello, World!");
```
- Prints "Hello, World!" to the console.
```java
Scanner scanner = new Scanner(System.in);
System.out.println("Enter your name:");
String name = scanner.nextLine();
System.out.println("Hello, " + name + "!");
scanner.close();
- Uses the `Scanner` class to read user input and then prints a personalized
greeting.
This example demonstrates the basic structure of a Java program, including
package declaration, import statements, class definition, and the main method.
(b) Explain static keyword with suitable example.
Static Keyword in Java
The `static` keyword in Java is used for memory management primarily. It can
be applied to variables, methods, blocks, and nested classes. The `static`
keyword indicates that the particular member belongs to the type itself, rather
than to instances of that type.
Key Points:
1. **Static Variables:**
- A static variable is shared among all instances of a class.
- Only one copy of the static variable exists, regardless of how many instances
of the class are created.
2. **Static Methods:**
- A static method belongs to the class rather than any specific instance.
- It can be called without creating an instance of the class.
- Static methods can only directly call other static methods and access static
data.
3. **Static Blocks:**
- A static block is used to initialize static data members.
- It gets executed when the class is loaded in memory.
4. **Static Nested Classes:**
- A static nested class does not have access to the instance variables of the
outer class.
Example
public class StaticExample {
// Static variable
static int staticCounter = 0;
// Instance variable
int instanceCounter = 0;
// Static method
public static void incrementStaticCounter() {
staticCounter++;
}
// Instance method
public void incrementInstanceCounter() {
instanceCounter++;
}
public static void main(String[] args) {
// Accessing static method and variable without creating an instance
System.out.println("Initial Static Counter: " + StaticExample.staticCounter);
StaticExample.incrementStaticCounter();
System.out.println("Static Counter after increment: " +
StaticExample.staticCounter);
// Creating instances
StaticExample obj1 = new StaticExample();
StaticExample obj2 = new StaticExample();
// Accessing instance methods and variables
obj1.incrementInstanceCounter();
obj2.incrementInstanceCounter();
System.out.println("Instance Counter for obj1: " + obj1.instanceCounter);
System.out.println("Instance Counter for obj2: " + obj2.instanceCounter);
// Static variable is shared among all instances
System.out.println("Static Counter accessed via obj1: " +
obj1.staticCounter);
System.out.println("Static Counter accessed via obj2: " +
obj2.staticCounter);
}
}
Explanation
- **Static Variable:**
static int staticCounter = 0;
- `staticCounter` is shared among all instances of `StaticExample`.
- **Static Method:**
public static void incrementStaticCounter() {
staticCounter++;
}
- `incrementStaticCounter` can be called without creating an instance of the
class.
- **Main Method:**
public static void main(String[] args) {
System.out.println("Initial Static Counter: " + StaticExample.staticCounter);
StaticExample.incrementStaticCounter();
System.out.println("Static Counter after increment: " +
StaticExample.staticCounter);
}
- Demonstrates accessing static variables and methods directly through the
class.
- **Instance Methods and Variables:**
public void incrementInstanceCounter() {
instanceCounter++;
}
- Each instance of `StaticExample` has its own `instanceCounter`.
- **Output:**
Initial Static Counter: 0
Static Counter after increment: 1
Instance Counter for obj1: 1
Instance Counter for obj2: 1
Static Counter accessed via obj1: 1
Static Counter accessed via obj2: 1
This example shows how static members are shared across instances, while
instance members are specific to each object.
(c) Define: Constructor. List out types of it. Explain Parameterized and
copy constructor with suitable example.
Constructor in Java
**Definition:**
A constructor is a special method in Java used to initialize objects. It is called
when an instance of a class is created. Constructors have the same name as the
class and do not have a return type.
Types of Constructors
1. **Default Constructor:**
- A no-argument constructor provided by Java if no other constructors are
defined.
2. **Parameterized Constructor:**
- A constructor that takes one or more parameters to initialize an object with
specific values.
3. **Copy Constructor:**
- A constructor that creates a new object as a copy of an existing object.
Parameterized Constructor
**Example:**
class Person {
String name;
int age;
// Parameterized constructor
Person(String name, int age) {
this.name = name;
this.age = age;
}
void display() {
System.out.println("Name: " + name + ", Age: " + age);
}
public static void main(String[] args) {
Person person1 = new Person("John", 25);
person1.display(); // Output: Name: John, Age: 25
}
}
Copy Constructor
**Example:**
class Person {
String name;
int age;
// Parameterized constructor
Person(String name, int age) {
this.name = name;
this.age = age;
}
// Copy constructor
Person(Person p) {
this.name = p.name;
this.age = p.age;
}
void display() {
System.out.println("Name: " + name + ", Age: " + age);
}
public static void main(String[] args) {
Person person1 = new Person("John", 25);
Person person2 = new Person(person1); // Using the copy constructor
person2.display(); // Output: Name: John, Age: 25
}
}
Explanation:
1. **Parameterized Constructor:**
Person(String name, int age) {
this.name = name;
this.age = age;
}
- Initializes `name` and `age` with specified values.
2. **Copy Constructor:**
Person(Person p) {
this.name = p.name;
this.age = p.age;
}
- Initializes a new object by copying the values from an existing object.
In both examples, constructors are used to initialize objects, with the
parameterized constructor setting initial values from parameters and the copy
constructor creating a new object based on an existing one.
Q.2
(a) Explain the Primitive Data Types and User Defined Data Types in
java.
Primitive Data Types in Java
Primitive data types are the most basic data types built into the Java language.
They are predefined by the language and named by a reserved keyword.
**Primitive Data Types:**
1. **byte:**
- Size: 8-bit
- Range: -128 to 127
2. **short:**
- Size: 16-bit
- Range: -32,768 to 32,767
3. **int:**
- Size: 32-bit
- Range: -2^31 to 2^31-1
4. **long:**
- Size: 64-bit
- Range: -2^63 to 2^63-1
5. **float:**
- Size: 32-bit floating point
- Range: Approximately ±3.40282347E+38F
6. **double:**
- Size: 64-bit floating point
- Range: Approximately ±1.79769313486231570E+308
7. **char:**
- Size: 16-bit
- Range: '\u0000' (0) to '\uffff' (65,535)
8. **boolean:**
- Values: `true` or `false`
User-Defined Data Types in Java
User-defined data types are data types that a programmer can create to suit
the needs of their program. They are built using classes, interfaces, and enums.
**User-Defined Data Types:**
1. **Classes:**
- Define a new data type with fields (variables) and methods.
- Example:
class Person {
String name;
int age;
Person(String name, int age) {
this.name = name;
this.age = age;
}
}
2. **Interfaces:**
- Define a contract that implementing classes must follow, specifying methods
that must be implemented.
- Example:
interface Animal {
void eat();
void sleep();
}
3. **Enums:**
- Define a fixed set of constants.
- Example:
```java
enum Day {
SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY
}
Example Combining Both
// Primitive data types example
int age = 25;
char initial = 'J';
boolean isStudent = true;
// User-defined data type example
class Person {
String name;
int age;
Person(String name, int age) {
this.name = name;
this.age = age;
}
void display() {
System.out.println("Name: " + name + ", Age: " + age);
}
}
// Using the class
public class Main {
public static void main(String[] args) {
Person person = new Person("John", 25);
person.display(); // Output: Name: John, Age: 25
}
}
Summary:
- **Primitive Data Types:** Basic built-in data types (e.g., `int`, `char`,
`boolean`).
- **User-Defined Data Types:** Custom data types created by the programmer
using classes, interfaces, and enums.
(b) Explain this keyword with suitable example.
In Java, the `this` keyword refers to the current instance of the class. It can be
used to refer to the current object's instance variables, methods, or
constructors.
Example:
class Person {
String name;
int age;
// Constructor with parameters
Person(String name, int age) {
this.name = name; // Assigning parameter value to instance variable using
"this"
this.age = age;
}
// Method to display details
void display() {
System.out.println("Name: " + this.name); // Accessing instance variable
using "this"
System.out.println("Age: " + this.age);
}
// Method to compare two Person objects
boolean isSamePerson(Person p) {
return this.name.equals(p.name) && this.age == p.age; // Using "this" to
refer to current object's instance variables
}
}
public class Main {
public static void main(String[] args) {
Person person1 = new Person("John", 25);
Person person2 = new Person("Alice", 30);
person1.display(); // Output: Name: John, Age: 25
person2.display(); // Output: Name: Alice, Age: 30
System.out.println("Are the two persons the same? " +
person1.isSamePerson(person2)); // Output: Are the two persons the same?
false
}
}
Explanation:
- **Constructor Usage:**
Person(String name, int age) {
this.name = name; // Assigning parameter value to instance variable using
"this"
this.age = age;
}
- `this.name` and `this.age` refer to the instance variables of the current
object.
- **Method Usage:**
void display() {
System.out.println("Name: " + this.name); // Accessing instance variable
using "this"
System.out.println("Age: " + this.age);
}
- `this.name` and `this.age` are used to access the instance variables within the
method.
- **Method Parameter Usage:**
boolean isSamePerson(Person p) {
return this.name.equals(p.name) && this.age == p.age; // Using "this" to
refer to current object's instance variables
}
- `this.name` and `this.age` are used to compare the instance variables of the
current object with another `Person` object passed as a parameter.
In summary, the `this` keyword in Java is used to refer to the current object's
instance variables, methods, or constructors within a class.
(c) Define Inheritance. List out types of it. Explain multilevel and
hierarchical inheritance with suitable example.
Inheritance
**Definition:**
Inheritance is a mechanism in object-oriented programming where a new class
(subclass or derived class) is created by inheriting properties and behaviors
(methods) from an existing class (superclass or base class). It allows the
subclass to reuse, extend, or modify the functionality of the superclass.
Types of Inheritance:
1. **Single Inheritance:**
- A subclass inherits from only one superclass.
2. **Multiple Inheritance (through interfaces):**
- A subclass inherits from multiple interfaces, but Java does not support
inheriting from multiple classes.
3. **Multilevel Inheritance:**
- A subclass inherits from another subclass, creating a chain of inheritance.
4. **Hierarchical Inheritance:**
- Multiple subclasses inherit from the same superclass.
Multilevel Inheritance in Java
**Example:**
class Animal {
void eat() {
System.out.println("Animal is eating.");
}
}
class Dog extends Animal {
void bark() {
System.out.println("Dog is barking.");
}
}
class Labrador extends Dog {
void run() {
System.out.println("Labrador is running.");
}
}
public class Main {
public static void main(String[] args) {
Labrador dog = new Labrador();
dog.eat(); // Output: Animal is eating.
dog.bark(); // Output: Dog is barking.
dog.run(); // Output: Labrador is running.
}
}
**Explanation:**
- `Labrador` inherits from `Dog`, which in turn inherits from `Animal`, creating a
chain of inheritance (`Animal` -> `Dog` -> `Labrador`).
- `Labrador` inherits properties and behaviors from both `Dog` and `Animal`.
- Instances of `Labrador` can access methods from all three classes in the
inheritance chain.
Hierarchical Inheritance in Java
**Example:**
class Animal {
void eat() {
System.out.println("Animal is eating.");
}
}
class Dog extends Animal {
void bark() {
System.out.println("Dog is barking.");
}
}
class Cat extends Animal {
void meow() {
System.out.println("Cat is meowing.");
}
}
public class Main {
public static void main(String[] args) {
Dog dog = new Dog();
dog.eat(); // Output: Animal is eating.
dog.bark(); // Output: Dog is barking.
Cat cat = new Cat();
cat.eat(); // Output: Animal is eating.
cat.meow(); // Output: Cat is meowing.
}
}
**Explanation:**
- Both `Dog` and `Cat` classes inherit from the `Animal` class.
- They share common properties and behaviors inherited from `Animal`.
- Instances of `Dog` and `Cat` can access methods from the `Animal` class.
Q. 3
(a) Explain Type Conversion and Casting in java.
**Type Conversion:**
- Type conversion is the process of converting a value from one data type to
another.
- Java supports two types of type conversions:
1. **Implicit Type Conversion (Widening Conversion):**
- Automatically performed by the compiler when a value of a smaller data
type is assigned to a larger data type.
- No loss of data occurs.
- Example: `int` to `long`, `float` to `double`.
2. **Explicit Type Conversion (Narrowing Conversion):**
- Also known as casting.
- Manually performed by the programmer when a value of a larger data type
is assigned to a smaller data type.
- May result in loss of data.
- Syntax: `(datatype) expression`.
- Example: `double` to `int`, `long` to `int`.
**Casting:**
- Casting is the process of explicitly converting a value from one data type to
another.
- It is done by placing the desired data type in parentheses in front of the value
to be converted.
- There are two types of casting in Java:
1. **Implicit Casting (Widening):**
- Automatically performed by the compiler when a value of a smaller data
type is assigned to a larger data type.
2. **Explicit Casting (Narrowing):**
- Manually performed by the programmer when a value of a larger data type
is assigned to a smaller data type.
- Requires the use of the cast operator `(datatype)`.
- Casting is necessary when performing arithmetic operations involving
different data types or when assigning a value of one data type to a variable of
another data type.
**Example:**
// Implicit Type Conversion (Widening)
int x = 10;
long y = x; // Implicit conversion from int to long
// Explicit Type Conversion (Narrowing)
double a = 10.5;
int b = (int) a; // Explicit conversion from double to int using casting
// Example of Implicit Casting (Widening)
int numInt = 100;
double numDouble = numInt; // Implicit casting from int to double
// Example of Explicit Casting (Narrowing)
double decimal = 10.99;
int integer = (int) decimal; // Explicit casting from double to int
In summary, type conversion and casting allow for the manipulation of data
between different data types in Java. Implicit conversion is performed
automatically by the compiler, while explicit conversion (casting) requires the
use of the cast operator and may result in data loss.
(b) Explain different visibility controls used in Java.
Visibility Controls in Java
Visibility controls in Java define the accessibility of classes, variables,
constructors, and methods from different parts of a Java program. There are
four visibility controls:
1. **Public:**
- Members declared as public are accessible from any other class.
- They have the widest visibility.
- Example: `public class MyClass { ... }`, `public void myMethod() { ... }`.
2. **Protected:**
- Members declared as protected are accessible within the same package and
by subclasses, even if they are in different packages.
- Example: `protected int myVariable;`, `protected void myMethod() { ... }`.
3. **Default (Package-private):**
- Members declared with no access control modifier (default) are accessible
only within the same package.
- They are not accessible by subclasses outside the package.
- Example: `class MyClass { ... }`, `int myVariable;`.
4. **Private:**
- Members declared as private are accessible only within the same class.
- They have the narrowest visibility.
- Example: `private int myVariable;`, `private void myMethod() { ... }`.
**Note:** In addition to these four visibility controls, there's also a visibility
modifier called `private protected`, which is used for members that are
accessible within the same module but not outside it. However, this modifier is
rarely used.
(c) Define: Thread. List different methods used to create Thread.
Explain Thread life cycle in detail.
Thread in Java
**Definition:**
A thread in Java represents a single sequential flow of control within a
program. It allows concurrent execution of multiple tasks within a single
program. Threads are lightweight processes that share the same memory space
and resources of a process.
Methods to Create Threads in Java
1. **Extending the Thread Class:**
- Define a class that extends the `Thread` class and override the `run()`
method.
- Instantiate an object of the subclass and call its `start()` method to begin
execution.
2. **Implementing the Runnable Interface:**
- Define a class that implements the `Runnable` interface and implement the
`run()` method.
- Create an object of the class and pass it as an argument to the `Thread`
constructor.
- Call the `start()` method on the `Thread` object to start execution.
Thread Life Cycle
1. **New (Born) State:**
- When a thread is instantiated using the `new` keyword but `start()` method
is not yet called, it is in the new state.
- The thread is not yet eligible for execution.
2. **Runnable (Ready to Run) State:**
- When the `start()` method is called, the thread enters the runnable state.
- The thread is ready to run but may or may not be executing at any given
time.
- The scheduler decides when to run the thread.
3. **Running State:**
- When the thread scheduler selects the thread for execution, it enters the
running state.
- The thread executes its `run()` method.
4. **Blocked (Waiting) State:**
- A thread enters the blocked state when it is waiting for a resource such as
I/O operation or a lock.
- It will remain in this state until the resource becomes available.
5. **Terminated (Dead) State:**
- A thread enters the terminated state when its `run()` method completes
execution or explicitly calls `stop()` method.
- Once terminated, a thread cannot be restarted.
Example:
// Extending the Thread class
class MyThread extends Thread {
public void run() {
System.out.println("Thread running...");
}
}
// Implementing the Runnable interface
class MyRunnable implements Runnable {
public void run() {
System.out.println("Runnable running...");
}
}
public class Main {
public static void main(String[] args) {
// Creating thread by extending Thread class
MyThread thread1 = new MyThread();
thread1.start();
// Creating thread by implementing Runnable interface
MyRunnable runnable = new MyRunnable();
Thread thread2 = new Thread(runnable);
thread2.start();
}
}
In this example, `thread1` is created by extending the `Thread` class, and
`thread2` is created by implementing the `Runnable` interface. Both threads go
through the thread life cycle: new, runnable, running, and terminated.
Q. 3
(a) Explain the purpose of JVM in java.
The purpose of the Java Virtual Machine (JVM) in Java is to execute Java
bytecode. It acts as an interpreter between the Java code and the underlying
hardware and operating system. Here's a short breakdown of its purpose:
1. **Platform Independence:**
- JVM enables Java programs to be platform-independent by providing a
runtime environment that abstracts away hardware and operating system
differences.
- Java code is compiled into bytecode, which can be executed by any JVM
regardless of the underlying platform.
2. **Memory Management:**
- JVM manages memory allocation and deallocation for Java programs,
including garbage collection.
- It automatically deallocates memory when objects are no longer referenced,
freeing resources and preventing memory leaks.
3. **Execution of Bytecode:**
- JVM interprets the Java bytecode and translates it into machine-specific
instructions that the underlying hardware can understand.
- It executes the bytecode efficiently, optimizing performance where possible.
4. **Security:**
- JVM provides built-in security features, such as sandboxing and bytecode
verification, to ensure that Java programs run safely without compromising the
system's security.
In summary, JVM plays a crucial role in making Java a portable, secure, and
efficient programming language by providing a runtime environment for
executing Java bytecode across different platforms.
(b) Define: Package. Write the steps to create a Package with
suitable example.
Package in Java
**Definition:**
A package in Java is a way to organize classes and interfaces into namespaces.
It helps in preventing naming conflicts, managing large projects, and improving
code modularity and reusability.
Steps to Create a Package
1. **Define Package Name:**
- Choose a name for the package that reflects its purpose or functionality.
- Use lowercase letters to avoid conflicts with Java's standard library
packages.
2. **Create Directory Structure:**
- Create a directory with the same name as the package.
- Use a directory structure that mirrors the package structure.
3. **Place Java Files in the Package Directory:**
- Create Java source files (`.java`) containing classes or interfaces.
- Place these files in the package directory.
4. **Add Package Declaration:**
- Add a `package` statement at the beginning of each Java source file to
specify the package name.
- The `package` statement should match the directory structure.
5. **Compile Java Files:**
- Compile the Java files using the `javac` compiler.
- Ensure that the compiler's classpath includes the root directory containing
the package.
Example
Suppose we want to create a package named `com.example.util` containing
utility classes.
Directory Structure:
project/
└── src/
└── com/
└── example/
└── util/
├── StringUtil.java
└── MathUtil.java
StringUtil.java:
package com.example.util;
public class StringUtil {
public static boolean isEmpty(String str) {
return str == null || str.isEmpty();
}
}
```
#### MathUtil.java:
```java
package com.example.util;
public class MathUtil {
public static int add(int a, int b) {
return a + b;
}
}
Steps:
1. Create the `src` directory.
2. Inside `src`, create the directory structure `com/example/util`.
3. Place `StringUtil.java` and `MathUtil.java` inside the `util` directory.
4. Add `package com.example.util;` at the beginning of each Java file.
5. Compile the Java files using `javac -d . StringUtil.java MathUtil.java` from the
`src` directory.
After compilation, you can use these utility classes in other Java files by
importing `com.example.util.*` or specific classes from the package.
(c) Explain Synchronization in Thread with suitable example.
Synchronization in Java Threads
**Definition:**
Synchronization in Java refers to the coordination of multiple threads to ensure
that they access shared resources in a controlled manner. It prevents race
conditions and data inconsistencies that may arise when multiple threads
access shared data concurrently.
Purpose of Synchronization:
1. **Thread Safety:**
- Ensures that only one thread can access a shared resource at a time,
preventing concurrent access and potential data corruption.
2. **Consistency:**
- Maintains consistency and integrity of shared data by enforcing a specific
order of execution among threads.
3. **Prevention of Race Conditions:**
- Avoids race conditions where the outcome of a program depends on the
timing or sequence of execution of multiple threads.
Example:
Consider a scenario where multiple threads are accessing and updating a
shared counter.
class Counter {
private int count = 0;
public void increment() {
count++;
}
public int getCount() {
return count;
}
}
class MyThread extends Thread {
private Counter counter;
public MyThread(Counter counter) {
this.counter = counter;
}
public void run() {
for (int i = 0; i < 1000; i++) {
counter.increment();
}
}
}
public class Main {
public static void main(String[] args) {
Counter counter = new Counter();
MyThread thread1 = new MyThread(counter);
MyThread thread2 = new MyThread(counter);
thread1.start();
thread2.start();
try {
thread1.join();
thread2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Final Count: " + counter.getCount());
}
}
In this example, multiple threads (`thread1` and `thread2`) are incrementing a
shared counter (`Counter` object). Without synchronization, there can be race
conditions where threads overwrite each other's updates, leading to incorrect
results.
Synchronization Using `synchronized` Keyword:
To synchronize access to shared resources, the `synchronized` keyword is used.
It ensures that only one thread can execute a synchronized block of code at a
time.
public synchronized void increment() {
count++;
}
By marking the `increment()` method as synchronized, only one thread can
execute this method at a time, preventing race conditions.
Summary:
Synchronization in Java is essential for ensuring thread safety, consistency, and
preventing race conditions when multiple threads access shared resources
concurrently. It is achieved using the `synchronized` keyword to coordinate
access to critical sections of code.
Q. 4
(a) Differentiate between String class and StringBuffer class.
Difference between String and StringBuffer in Java
1. **Immutability:**
- **String:**
- String objects are immutable, meaning their values cannot be changed
once they are created.
- Any operation that modifies a string actually creates a new string object.
- **StringBuffer:**
- StringBuffer objects are mutable, meaning their values can be changed
after creation.
- StringBuffer provides methods to modify the contents of the string without
creating a new object.
2. **Performance:**
- **String:**
- String concatenation using the `+` operator results in the creation of
multiple string objects, which can degrade performance, especially in loop
concatenation scenarios.
- **StringBuffer:**
- StringBuffer is more efficient for concatenating multiple strings or
performing multiple modifications because it does not create new objects for
each modification.
3. **Thread Safety:**
- **String:**
- String objects are immutable and inherently thread-safe.
- **StringBuffer:**
- StringBuffer is mutable but synchronized, making it thread-safe.
- StringBuffer methods are synchronized, ensuring that only one thread can
modify the string buffer at a time.
4. **Usage:**
- **String:**
- String is suitable for scenarios where the value of the string does not
change frequently, such as storing constant values or immutable data.
- **StringBuffer:**
- StringBuffer is preferable when frequent modifications to the contents of
the string are required, such as in building dynamic strings or performing string
manipulations in multi-threaded environments.
(b) Write a Java Program to find sum and average of 10 numbers of
an array.
public class Main {
public static void main(String[] args) {
// Array of 10 numbers
int[] numbers = {10, 20, 30, 40, 50, 60, 70, 80, 90, 100};
// Variables to store sum and average
int sum = 0;
double average;
// Calculate sum
for (int i = 0; i < numbers.length; i++) {
sum += numbers[i];
}
// Calculate average
average = (double) sum / numbers.length;
// Print sum and average
System.out.println("Sum of the numbers: " + sum);
System.out.println("Average of the numbers: " + average);
}
}
This program defines an array of 10 numbers, calculates the sum of all
numbers, and then computes the average by dividing the sum by the number
of elements in the array. Finally, it prints the sum and average.
(c) I) Explain abstract class with suitable example.
**Definition:**
- An abstract class in Java is a class that cannot be instantiated on its own and
can contain abstract methods.
- Abstract classes serve as blueprints for other classes and may contain both
abstract and non-abstract methods.
- Abstract methods are declared without a body and must be implemented by
subclasses.
**Example:**
abstract class Shape {
// Abstract method (no implementation)
abstract double area();
// Non-abstract method
void display() {
System.out.println("This is a shape.");
}
}
class Circle extends Shape {
private double radius;
// Constructor
public Circle(double radius) {
this.radius = radius;
}
// Implementing abstract method
double area() {
return Math.PI * radius * radius;
}
}
class Main {
public static void main(String[] args) {
// Creating object of subclass Circle
Circle circle = new Circle(5);
circle.display(); // Output: This is a shape.
System.out.println("Area of circle: " + circle.area()); // Output: Area of
circle: 78.53981633974483
}
}
In this example, `Shape` is an abstract class with an abstract method `area()`.
`Circle` is a subclass of `Shape` that implements the `area()` method. Since
`Shape` is abstract, it cannot be instantiated, but `Circle`, being a concrete
class, can be instantiated.
II) Explain final class with suitable example.
**Definition:**
- A final class in Java is a class that cannot be subclassed or extended.
- It prevents other classes from inheriting from it, making it impossible to
override its methods or modify its behavior.
**Example:**
final class FinalClass {
// Final class members and methods
void display() {
System.out.println("This is a final class.");
}
}
// Error: Cannot inherit from final class FinalClass
class SubClass extends FinalClass {
// Error: Cannot override final method
void display() {
System.out.println("This is a subclass.");
}
}
class Main {
public static void main(String[] args) {
FinalClass finalObj = new FinalClass();
finalObj.display(); // Output: This is a final class.
}
}
In this example, `FinalClass` is declared as final, so it cannot be subclassed.
Attempting to create a subclass `SubClass` results in a compilation error.
Additionally, final methods within a final class cannot be overridden.
Q. 4
(a) Explain Garbage Collection in Java.
**Definition:**
- Garbage collection in Java is the automatic process of reclaiming memory
occupied by objects that are no longer in use by the program.
- It is performed by the JVM's garbage collector, which identifies and frees up
memory occupied by unreachable objects.
**Key Points:**
1. **Automatic Process:**
- Garbage collection is automatic and transparent to the programmer.
- The programmer does not need to explicitly deallocate memory or destroy
objects.
2. **Identification of Unreachable Objects:**
- Garbage collector identifies objects that are no longer reachable or
referenced by the program.
- Unreachable objects are those that cannot be accessed or referenced by any
live thread.
3. **Reclaiming Memory:**
- Once unreachable objects are identified, the garbage collector deallocates
their memory.
- This memory is then made available for new objects to be allocated.
4. **Preventing Memory Leaks:**
- Garbage collection helps prevent memory leaks by reclaiming memory
occupied by unused objects.
- It ensures efficient memory usage and prevents the program from running
out of memory.
**Example:**
class MyClass {
public static void main(String[] args) {
// Creating objects
MyClass obj1 = new MyClass(); // Object 1
MyClass obj2 = new MyClass(); // Object 2
// Making obj1 reference null
obj1 = null;
// Garbage collection will reclaim memory of obj1
// as it is no longer reachable
}
}
In this example, once `obj1` is set to `null`, it becomes unreachable and eligible
for garbage collection. The garbage collector will reclaim the memory occupied
by `obj1` to make it available for other objects.
(b) Write a Java program to handle user defined exception for ‘Divide
by Zero’ error.
// Custom exception class
class DivideByZeroException extends Exception {
public DivideByZeroException(String message) {
super(message);
}
}
// Class to perform division operation
class Division {
// Method to perform division
public static double divide(int numerator, int denominator) throws
DivideByZeroException {
if (denominator == 0) {
throw new DivideByZeroException("Error: Divide by zero!");
}
return (double) numerator / denominator;
}
}
public class Main {
public static void main(String[] args) {
int numerator = 10;
int denominator = 0;
try {
double result = Division.divide(numerator, denominator);
System.out.println("Result of division: " + result);
} catch (DivideByZeroException e) {
System.out.println(e.getMessage());
}
}
}
In this program:
- We define a custom exception class `DivideByZeroException` that extends the
`Exception` class.
- The `Division` class contains a static method `divide` that takes two integers as
input and performs division. If the denominator is zero, it throws a
`DivideByZeroException`.
- In the `Main` class, we attempt to perform division and handle the
`DivideByZeroException` using a try-catch block. If the exception is caught, we
print the error message.
(c) Write a java program to demonstrate multiple try block and
multiple catch block exception.
blocks for exception handling:
public class Main {
public static void main(String[] args) {
try {
// First try block
int[] numbers = {1, 2, 3};
System.out.println(numbers[5]); // Accessing out-of-bound index
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("Array index out of bounds!");
}
try {
// Second try block
String str = null;
System.out.println(str.length()); // Attempting to invoke a method on
null object
} catch (NullPointerException e) {
System.out.println("NullPointerException occurred!");
}
try {
// Third try block
int result = 10 / 0; // Attempting to divide by zero
} catch (ArithmeticException e) {
System.out.println("ArithmeticException occurred: " + e.getMessage());
}
System.out.println("Program continues after exception handling.");
}
}
In this program:
- Three `try` blocks are used, each containing code that may potentially throw
an exception.
- Multiple `catch` blocks are provided to handle different types of exceptions
that may occur within each `try` block.
- If an exception occurs within a `try` block, the corresponding `catch` block is
executed, and then the program continues to execute the remaining code.
Q.5
(a) Write a program in Java to create a file and perform write
operation on this file.
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
public class Main {
public static void main(String[] args) {
// File path
String filePath = "example.txt";
try {
// Create a File object
File file = new File(filePath);
// Create a FileWriter object
FileWriter writer = new FileWriter(file);
// Write data to the file
writer.write("Hello, this is a write operation example in Java!");
// Close the writer
writer.close();
System.out.println("Data has been written to the file successfully.");
} catch (IOException e) {
System.out.println("An error occurred: " + e.getMessage());
}
}
}
In this program:
- We define a file path (`example.txt`) where we want to create and write data.
- Inside the `try` block, we create a `File` object representing the file at the
specified path.
- We create a `FileWriter` object to write data to the file.
- We use the `write()` method to write the desired data to the file.
- Finally, we close the `FileWriter` object to release system resources.
- If any `IOException` occurs during file creation or writing, it is caught in the
`catch` block, and an error message is displayed.
(b) Explain throw and finally in Exception Handling with example.
throw Statement:
- The `throw` statement in Java is used to explicitly throw an exception.
- It is typically used when a program encounters an exceptional condition that
cannot be handled by the program itself, and it needs to be propagated to the
calling method or caught by an appropriate exception handler.
Syntax:
throw throwableInstance;
Example:
public class Main {
public static void main(String[] args) {
try {
// Throw an ArithmeticException
throw new ArithmeticException("Example of throw statement");
} catch (ArithmeticException e) {
System.out.println("Exception caught: " + e.getMessage());
}
}
}
finally Block:
- The `finally` block in Java is used to define code that will be executed
regardless of whether an exception is thrown or not.
- It is generally used to release resources such as closing files or database
connections, ensuring that these resources are properly closed even if an
exception occurs.
Example:
import java.io.FileWriter;
import java.io.IOException;
public class Main {
public static void main(String[] args) {
FileWriter writer = null;
try {
writer = new FileWriter("example.txt");
writer.write("Hello, this is a test.");
} catch (IOException e) {
System.out.println("An error occurred: " + e.getMessage());
} finally {
// Close the FileWriter object in the finally block
try {
if (writer != null) {
writer.close();
}
} catch (IOException e) {
System.out.println("Error while closing the FileWriter: " +
e.getMessage());
}
}
}
}
In this example, even if an exception occurs while writing to the file, the
`finally` block ensures that the `FileWriter` object is properly closed, releasing
system resources.
(c) Describe: Polymorphism. Explain run time polymorphism with
suitable example in java.
**Definition:**
Polymorphism is a fundamental concept in object-oriented programming that
allows objects of different classes to be treated as objects of a common
superclass. It enables a single interface to be used for objects of different types,
providing flexibility and extensibility in code design.
Runtime Polymorphism
**Definition:**
Runtime polymorphism, also known as dynamic polymorphism, occurs when a
method is overridden by a subclass method and the appropriate method to be
invoked is determined at runtime based on the type of the object.
Example:
class Animal {
void sound() {
System.out.println("Animal makes a sound.");
}
}
class Dog extends Animal {
void sound() {
System.out.println("Dog barks.");
}
}
class Cat extends Animal {
void sound() {
System.out.println("Cat meows.");
}
}
public class Main {
public static void main(String[] args) {
Animal animal1 = new Dog(); // Upcasting
Animal animal2 = new Cat(); // Upcasting
animal1.sound(); // Output: Dog barks.
animal2.sound(); // Output: Cat meows.
}
}
Explanation:
- In this example, `Animal` is a superclass with a method `sound()`.
- `Dog` and `Cat` are subclasses of `Animal` and they override the `sound()`
method.
- At runtime, when `animal1.sound()` is called, since `animal1` refers to a `Dog`
object, the `sound()` method of `Dog` class is invoked.
- Similarly, when `animal2.sound()` is called, since `animal2` refers to a `Cat`
object, the `sound()` method of `Cat` class is invoked.
Summary:
Runtime polymorphism allows flexibility in method invocation at runtime based
on the actual type of the object. It facilitates code extensibility and reusability
by enabling method overriding in subclasses.
Q.5
(a) Write a program in Java that read the content of a file byte by
byte and copy it into another file.
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class Main {
public static void main(String[] args) {
// Source file and destination file paths
String sourceFilePath = "source.txt";
String destinationFilePath = "destination.txt";
try {
// Create FileInputStream and FileOutputStream objects
FileInputStream fis = new FileInputStream(sourceFilePath);
FileOutputStream fos = new FileOutputStream(destinationFilePath);
// Read bytes from source file and write them to destination file
int byteRead;
while ((byteRead = fis.read()) != -1) {
fos.write(byteRead);
}
// Close FileInputStream and FileOutputStream
fis.close();
fos.close();
System.out.println("File copied successfully.");
} catch (IOException e) {
System.out.println("An error occurred: " + e.getMessage());
}
}
}
In this program:
- We define the paths of the source file (`source.txt`) and the destination file
(`destination.txt`).
- Inside the `try` block:
- We create `FileInputStream` and `FileOutputStream` objects to read from
the source file and write to the destination file.
- We use a `while` loop to read bytes from the source file until the end of the
file is reached (`read()` method returns `-1`).
- For each byte read, we write it to the destination file using the `write()`
method.
- After copying is done, we close the `FileInputStream` and `FileOutputStream`
objects in the `finally` block.
- If any `IOException` occurs during file operations, it is caught in the `catch`
block, and an error message is displayed.
(b) Explain the different I/O Classes available with Java.
1. **Byte Stream Classes:**
- `InputStream` and `OutputStream`: Abstract classes for reading and writing
byte-oriented data.
- `FileInputStream` and `FileOutputStream`: Classes for reading from and
writing to files as byte streams.
- `ByteArrayInputStream` and `ByteArrayOutputStream`: Classes for reading
from and writing to byte arrays.
2. **Character Stream Classes:**
- `Reader` and `Writer`: Abstract classes for reading and writing character-
oriented data.
- `FileReader` and `FileWriter`: Classes for reading from and writing to files as
character streams.
- `BufferedReader` and `BufferedWriter`: Classes for efficient reading and
writing of characters by buffering input and output.
3. **Buffered Stream Classes:**
- `BufferedInputStream` and `BufferedOutputStream`: Classes for buffering
input and output streams for improved performance.
- `BufferedReader` and `BufferedWriter`: As mentioned above, used for
character-oriented buffered I/O.
4. **Object Stream Classes:**
- `ObjectInputStream` and `ObjectOutputStream`: Classes for reading and
writing serialized objects.
- These classes enable the serialization and deserialization of Java objects,
allowing objects to be written to and read from streams.
5. **File System Classes:**
- `File`: Represents a file or directory path in the file system.
- Provides methods for file and directory manipulation, such as creation,
deletion, renaming, etc.
6. **Piped Stream Classes:**
- `PipedInputStream` and `PipedOutputStream`: Classes for implementing
communication between threads using piped streams.
- `PipedReader` and `PipedWriter`: Similar to piped streams but for character-
oriented communication.
7. **Scanner and Formatter Classes:**
- `Scanner`: Allows parsing of primitive types and strings from various input
streams.
- `Formatter`: Allows formatting of textual output to various output streams.
These are some of the main I/O classes available in Java, providing a
comprehensive set of tools for handling input and output operations in various
scenarios.
(c) Write a java program that executes two threads. One thread
displays “Java Programming” every 3 seconds, and the other
displays “Semester - 4th IT” every 6 seconds.(Create the
threads by extending the Thread class)
class DisplayThread extends Thread {
private String message;
private int interval;
// Constructor to initialize message and interval
public DisplayThread(String message, int interval) {
this.message = message;
this.interval = interval;
}
// Run method to display the message at specified intervals
public void run() {
while (true) {
System.out.println(message);
try {
Thread.sleep(interval * 1000); // Sleep for 'interval' seconds
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class Main {
public static void main(String[] args) {
// Create and start threads
DisplayThread thread1 = new DisplayThread("Java Programming", 3);
DisplayThread thread2 = new DisplayThread("Semester - 4th IT", 6);
thread1.start();
thread2.start();
}
}
In this program:
- We create a class `DisplayThread` that extends the Thread class.
- The `DisplayThread` class has a constructor to initialize the message to be
displayed and the interval at which it should be displayed.
- Inside the `run()` method of `DisplayThread`, we use a loop to continuously
display the message and then sleep for the specified interval using
`Thread.sleep()`.
- In the `Main` class, we create two `DisplayThread` objects with different
messages and intervals, and then start both threads using the `start()` method.