Java Question Bank with Answers

Answers for Core Java Question Bank

Chapter 2: Objects and Classes.

Moderate Level Questions

8. Describe the concept of "defining user-defined classes" with respect to real-world entities. Provide a Java code snippet for a simple Student class including relevant attributes (e.g., name, rollNo).

Answer:
Defining User-Defined Classes with Real-World Entities:
In Object-Oriented Programming using Java, "defining user-defined classes" involves creating custom blueprints that model real-world entities or concepts. This process allows developers to structure their programs in a way that closely mirrors the problem domain. When modeling real-world entities (e.g., a student, a car), we identify their characteristics (properties/attributes) and actions (behaviors/methods). A user-defined class encapsulates these properties (as instance variables) and behaviors (as methods) into a single, cohesive unit, promoting modularity and reusability.

Java Code Snippet for a Simple Student Class:

 public class Student {

    // Attributes (instance variables) of a Student

    String name;

    int rollNo;

    String major;

    double cgpa; // Cumulative Grade Point Average

 

    // Constructor to initialize a Student object

    public Student(String name, int rollNo, String major, double cgpa) {

        this.name = name;

        this.rollNo = rollNo;

        this.major = major;

        this.cgpa = cgpa;

    }

 

    // Method to display student’s information (behavior)

    public void displayStudentInfo() {

        System.out.println("— Student Details —");

        System.out.println("Name: " + name);

        System.out.println("Roll No: " + rollNo);

        System.out.println("Major: " + major);

        System.out.println("CGPA: " + cgpa);

        System.out.println("———————–");

    }

 

    // Example of another behavior: checking eligibility

    public boolean isEligibleForScholarship() {

        return cgpa >= 3.5;

    }

 

    // Main method for demonstration

    public static void main(String[] args) {

        // Create objects (instances) of the Student class

        Student student1 = new Student("Alice Smith", 101, "Computer Science", 3.8);

        Student student2 = new Student("Bob Johnson", 102, "Mathematics", 3.2);

 

        // Call methods on the objects

        student1.displayStudentInfo();

        System.out.println(student1.name + " is eligible for scholarship: " + student1.isEligibleForScholarship());

 

        student2.displayStudentInfo();

        System.out.println(student2.name + " is eligible for scholarship: " + student2.isEligibleForScholarship());

    }

}

9. Compare and contrast the protected and default (package-private) access specifiers in Java. Provide a scenario where protected would be preferred over default.

Answer:

Comparison Table:

Feature

protected

default (package-private)

Keyword

protected

No keyword (implicit if no other modifier is used)

Same Class

Yes

Yes

Same Package, Subclass

Yes

Yes

Same Package, Non-Subclass

Yes

Yes

Different Package, Subclass

Yes (through inheritance)

No

Different Package, Non-Subclass

No

No

Purpose

Provides inheritance-based access. Designed for members that should be accessible to subclasses even if they are in different packages, but hidden from unrelated classes outside the package.

Provides package-level access. Designed for internal components within a package that don’t need to be exposed to the outside world, or to subclasses outside the package.

Scenario where protected would be preferred over default:

A protected member is preferred when you intend for certain internal functionalities or data to be accessible by subclasses, even if those subclasses reside in different packages. This is common in framework design where core components are defined in one package, and users extend them in their own application packages.

Example:
Consider a base
Renderer class in a com.graphics.core package, which has a protected method renderPrimitive() that subclasses should use and potentially customize. User-defined renderers, residing in a different package (e.g., com.mygame.renderer), would extend this Renderer class. If renderPrimitive() were default, the subclass in a different package would not be able to access it. With protected, the subclass can access and utilize renderPrimitive() for its rendering logic.

 

package com.graphics.core;

 

public class Renderer {

 

    // Protected method: accessible by subclasses in any package

    protected void renderPrimitive(Shape shape) { // <– added parameter

        System.out.println("Core rendering of a primitive shape.");

        // Complex rendering logic

    }

 

    // Default access method: accessible only within com.graphics.core package

    void internalUtility() {

        System.out.println("Internal utility for the graphics core.");

    }

}

 

// Placeholder Shape class

class Shape {}

 

package com.mygame.renderer;

 

import com.graphics.core.Renderer;

import com.graphics.core.Shape; // Import Shape if needed

 

public class CustomGameRenderer extends Renderer {

 

    public void drawGameScene() {

        System.out.println("Drawing game scene using custom renderer.");

        Shape circle = new Shape();

        this.renderPrimitive(circle); // Works because renderPrimitive is protected

        // super.internalUtility(); // Won’t compile: internalUtility has default access

    }

 

    public static void main(String[] args) {

        CustomGameRenderer gameRenderer = new CustomGameRenderer();

        gameRenderer.drawGameScene();

    }

}

10. Write a Java program to create an Array of Objects for the Student class defined in Question 8. Store details for three students and then display their information.

Answer:

// Program 10: Create an Array of Student Objects and Display Their Information

 

public class StudentArrayDemo {

    public static void main(String[] args) {

 

        // Step 1: Declare and create an array of Student objects (size 3)

        Student[] studentList = new Student[3];

 

        // Step 2: Create Student objects and assign them to the array elements

        studentList[0] = new Student("Alice Wonderland", 101, "Computer Science", 3.8);

        studentList[1] = new Student("Bob The Builder", 102, "Mechanical Engineering", 3.1);

        studentList[2] = new Student("Charlie Chaplin", 103, "Film Studies", 3.9);

 

        System.out.println("— Displaying Student Information from Array —");

 

        // Step 3: Using normal for loop

        for (int i = 0; i < studentList.length; i++) {

            System.out.println("\nStudent " + (i + 1) + ":");

            studentList[i].displayStudentInfo();

        }

 

        // Step 4: Using enhanced for loop

        System.out.println("\n— Displaying Student Information using Enhanced For Loop —");

        int count = 1;

        for (Student student : studentList) {

            System.out.println("\nStudent " + (count++) + ":");

            student.displayStudentInfo();

        }

    }

}

 

// Reusing Student class from Question 8

class Student {

    String name;

    int rollNo;

    String major;

    double cgpa;

 

    // Constructor

    public Student(String name, int rollNo, String major, double cgpa) {

        this.name = name;

        this.rollNo = rollNo;

        this.major = major;

        this.cgpa = cgpa;

    }

 

    // Method to display student information

    public void displayStudentInfo() {

        System.out.println("Name: " + name);

        System.out.println("Roll No: " + rollNo);

        System.out.println("Major: " + major);

        System.out.println("CGPA: " + cgpa);

    }

}

11. Explain "Constructor Overloading" with a suitable Java example. Demonstrate how different constructors can be used to initialize an object in various ways.

Answer:
Constructor Overloading:
Constructor overloading is a feature in Java that allows a class to have multiple constructors, provided that each constructor has a unique parameter list (i.e., different number of parameters, different types of parameters, or different order of parameters). The compiler differentiates between overloaded constructors based on their signatures. This mechanism provides flexibility in object creation, enabling objects to be initialized with varying sets of initial data, making the class more versatile.

Java Example:
Consider a
Book class where you might want to create a book object with just a title and author, or with a title, author, and an ISBN, or even with a full set of details.

// Java Example: Demonstration of Constructor Overloading and Constructor Chaining

 

public class Book {

    String title;

    String author;

    String isbn;

    double price;

 

    // 1. Default Constructor

    public Book() {

        this.title = "Untitled";

        this.author = "Unknown";

        this.isbn = "N/A";

        this.price = 0.0;

        System.out.println("Book created with default values.");

    }

 

    // 2. Constructor with Title and Author

    public Book(String title, String author) {

        this(); // Calls the default constructor first

        this.title = title;

        this.author = author;

        System.out.println("Book created with title and author.");

    }

 

    // 3. Constructor with Title, Author, and ISBN

    public Book(String title, String author, String isbn) {

        this(title, author); // Calls the (title, author) constructor

        this.isbn = isbn;

        System.out.println("Book created with title, author, and ISBN.");

    }

 

    // 4. Constructor with all details

    public Book(String title, String author, String isbn, double price) {

        this(title, author, isbn); // Calls the (title, author, isbn) constructor

        this.price = price;

        System.out.println("Book created with all details.");

    }

 

    // Method to display book details

    public void displayBookDetails() {

        System.out.println("————————-");

        System.out.println("Title : " + title);

        System.out.println("Author: " + author);

        System.out.println("ISBN  : " + isbn);

        System.out.println("Price : $" + String.format("%.2f", price));

        System.out.println("————————-");

    }

 

    // Main method to demonstrate different constructors

    public static void main(String[] args) {

        // 1. Default constructor

        Book book1 = new Book();

        book1.displayBookDetails();

 

        // 2. Constructor with title and author

        Book book2 = new Book("The Java Programming Language", "James Gosling");

        book2.displayBookDetails();

 

        // 3. Constructor with title, author, and ISBN

        Book book3 = new Book("Effective Java", "Joshua Bloch", "978-0134685991");

        book3.displayBookDetails();

 

        // 4. Constructor with all details

        Book book4 = new Book("Clean Code", "Robert C. Martin", "978-0132350884", 45.99);

        book4.displayBookDetails();

    }

}

This example shows how Book objects can be created and initialized using four different constructors, each catering to a different level of detail required at the time of object creation. The this() call within constructors demonstrates constructor chaining, where one constructor calls another constructor of the same class.

12. Discuss two distinct uses of the this keyword in Java with illustrative code examples for each.

Answer:
The
this keyword in Java is a reference to the current object. It is implicitly passed to every non-static method and constructor.

1. To Differentiate Between Instance Variables and Local Variables/Parameters:

  • Purpose: When a method parameter or a local variable has the same name as an instance variable, it creates a name conflict. The this keyword is used to explicitly refer to the instance variable of the current object, distinguishing it from the local variable.

public class Product {

    String name;   // Instance variable

    double price;  // Instance variable

 

    // Constructor with parameters

    public Product(String name, double price) {

        // ‘name’ and ‘price’ on the right are parameters.

        // ‘this.name’ and ‘this.price’ refer to the instance variables.

        this.name = name;

        this.price = price;

    }

 

    // Method to display product details

    public void display() {

        System.out.println("Product: " + this.name + ", Price: $" + this.price);

    }

 

    // Main method to test the Product class

    public static void main(String[] args) {

        Product p1 = new Product("Laptop", 85000.50);

        Product p2 = new Product("Smartphone", 29999.99);

 

        p1.display();

        p2.display();

    }

}

In the constructor, this.name = name; assigns the value of the name parameter to the name instance variable of the Product object being created.

2. To Invoke the Current Class’s Constructor:

  • Purpose: The this() (with parentheses) keyword is used to call another constructor of the same class from within a constructor (Knüppel et al., 2018). This is known as constructor chaining and is useful for reducing code duplication when multiple constructors perform common initialization tasks (Knüppel et al., 2018). this() must be the first statement in the constructor.
  • Example:

public class Employee {

    int id;

    String name;

    double salary;

 

    // Constructor 1: Initializes ID and Name, calls Constructor 2

    public Employee(int id, String name) {

        this(id, name, 0.0); // Calls the 3-parameter constructor

        System.out.println("Employee created with ID and Name.");

    }

 

    // Constructor 2: Initializes ID, Name, and Salary

    public Employee(int id, String name, double salary) {

        this.id = id;

        this.name = name;

        this.salary = salary;

        System.out.println("Employee created with ID, Name, and Salary.");

    }

 

    // Constructor 3: Default Constructor (initializes with default values)

    public Employee() {

        this(0, "Guest", 0.0); // Calls the 3-parameter constructor

        System.out.println("Default Employee created.");

    }

 

    public static void main(String[] args) {

        Employee emp1 = new Employee(); // Calls default constructor

        System.out.println("emp1 Name: " + emp1.name);

 

        Employee emp2 = new Employee(101, "Alice"); // Calls (101, "Alice")

        System.out.println("emp2 Salary: " + emp2.salary);

    }

}

In this example, the two-parameter constructor Employee(int id, String name) uses this(id, name, 0.0) to call the three-parameter constructor, ensuring that the salary is also initialized (to a default value) without duplicating the id and name initialization logic.

13. Explain the concept of a "Static Block" in Java. When is a static block executed, and what is its typical use? Provide a code example.

Answer:
Static Block:
A static block in Java is a block of code within a class that is prefixed with the
static keyword. It is used to initialize static data members (variables) of a class or to perform any one-time setup that needs to happen when the class is first loaded . A class can have multiple static blocks, and they will be executed in the order they appear in the class.

When is a static block executed?
A static block is executed exactly once when the class is loaded into memory by the Java ClassLoader . This happens at the very first time the class is accessed in any way, such as:

  • When an object of the class is created (new ClassName()).
  • When any static member (method or variable) of the class is accessed .
  • When Class.forName("ClassName") is called.

Typical Use:

  • Complex Static Variable Initialization: For initializing static variables that require more complex logic than a simple one-line assignment .
  • Loading Native Libraries: If a class relies on native (non-Java) code, the static block is a suitable place to load these libraries (System.loadLibrary()).
  • Registering Drivers: Database drivers often use static blocks to register themselves with the DriverManager.
  • One-Time Resource Setup: Any other setup that is expensive or only needs to be done once for the entire class, rather than for each object.

Code Example:

import java.util.ArrayList;

import java.util.List;

 

public class StaticBlockExample {

 

    // Static variables

    public static String COMPANY_NAME = "MyTech Solutions";

    public static int MAX_USERS;

    public static final List<String> FEATURES = new ArrayList<>(); // Static list

 

    // 🔹 Static Block 1

    static {

        System.out.println("Static Block 1 executed.");

        // Initialize static variable MAX_USERS

        MAX_USERS = 1000;

        System.out.println("MAX_USERS initialized to: " + MAX_USERS);

    }

 

    // 🔹 Static Block 2 (demonstrating multiple static blocks)

    static {

        System.out.println("Static Block 2 executed.");

        // Initialize static list

        FEATURES.add("Login");

        FEATURES.add("Dashboard");

        FEATURES.add("Reports");

        System.out.println("Features list initialized.");

    }

 

    // 🔹 Constructor — runs when an object is created

    public StaticBlockExample() {

        System.out.println("Constructor executed.");

    }

 

    // 🔹 Static Method — can access only static members

    public static void displayStaticInfo() {

        System.out.println("\n— Static Information —");

        System.out.println("Company: " + COMPANY_NAME);

        System.out.println("Max Allowed Users: " + MAX_USERS);

        System.out.println("Available Features: " + FEATURES);

        System.out.println("————————–");

    }

 

    // 🔹 Main Method — entry point

    public static void main(String[] args) {

        System.out.println("Main method started.");

 

        // Static blocks execute before this line (class loading time)

        StaticBlockExample.displayStaticInfo();

 

        // Creating an object (constructor will run, static blocks won’t)

        StaticBlockExample obj = new StaticBlockExample();

        StaticBlockExample.displayStaticInfo(); // Static blocks won’t run again

 

        System.out.println("Main method finished.");

    }

}

As seen in the output, the static blocks execute first, even before the main method (which is itself a static method) is fully processed. They execute only once.

14. What are Inner Classes in Java? Briefly describe two common types of inner classes (e.g., Member Inner Class, Anonymous Inner Class) and when you might use them.

Answer:
Inner Classes:
An inner class (or nested class) in Java is a class defined within another class . The enclosing class is called the outer class. Inner classes allow you to logically group classes that are only used in one place, increase encapsulation, and create more readable and maintainable code. They have full access to all the members (including private) of the outer class.

Two Common Types of Inner Classes:

1.     Member Inner Class:

o    Description: A member inner class is a non-static class defined inside another class, outside of any method . It behaves like an instance member of the outer class, meaning it must be instantiated with respect to an instance of the outer class. It can access all members of the outer class, both static and non-static.

o    When to Use:

§  When the inner class needs to directly access the instance members of the outer class.

§  When the inner class is conceptually a component of the outer class and has a strong "is-part-of" relationship.

§  Example: A Car class might have an Engine as a member inner class, as an engine is an integral part of a car.

o    Example Structure:

// Demonstration of Member Inner Class

public class OuterClass {

 

    // Private instance variable of the outer class

    private int outerData = 10;

 

    // Member Inner Class (non-static)

    class MemberInnerClass {

        public void display() {

            // Can access even private members of the outer class

            System.out.println("Outer data: " + outerData);

            System.out.println("This is a Member Inner Class accessing outer class data.");

        }

    }

 

    // Main method to demonstrate usage

    public static void main(String[] args) {

        // Step 1: Create an object of the outer class

        OuterClass outer = new OuterClass();

 

        // Step 2: Create an object of the inner class using the outer class instance

        OuterClass.MemberInnerClass inner = outer.new MemberInnerClass();

 

        // Step 3: Call inner class method

        inner.display();

    }

}

Anonymous Inner Class:

o    Description: An anonymous inner class is an inner class without a name . It is defined and instantiated in a single expression, often used for implementing an interface or extending a class . They are typically used when you need to create a class that will be used only once .

o    When to Use:

§  To provide a concrete implementation of an interface or an abstract class on the fly.

§  When the class is very small and used only at the point of its definition (e.g., event listeners in GUI programming, custom comparators).

§  To avoid creating a separate .java file for a small, single-use class.

o    Example Structure (implementing an interface):

// Example of Anonymous Inner Class

interface Greeting {

    void sayHello();

}

 

class MyClass {

    public void greet() {

        // Anonymous Inner Class implementing the Greeting interface

        Greeting englishGreeting = new Greeting() {

            @Override

            public void sayHello() {

                System.out.println("Hello!");

            }

        };

 

        // Calling the implemented method

        englishGreeting.sayHello();

    }

 

    public static void main(String[] args) {

        // Creating an object and invoking greet()

        new MyClass().greet();

    }

}

15. Describe the process of "Creating, Accessing, and Using Packages" in Java. Explain the role of the package keyword and the import statement. Provide an example of how you would structure a simple project with two packages.

Answer:
Creating, Accessing, and Using Packages in Java:
Packages in Java are a mechanism to organize classes, interfaces, and sub-packages into logical units, providing a way to prevent naming conflicts and to control access to elements . They are essentially directories in the file system.

Process:

1.     Creation:

o    To create a package, you declare it at the top of a Java source file using the package keyword, followed by the package name.

o    The package name usually follows a reverse domain name convention (e.g., com.example.myapp).

o    The .java file containing the class must reside in a directory structure that matches the package name (e.g., com/example/myapp/MyClass.java).

2.     Accessing/Using:

o    Classes within the same package can access each other directly using their names.

o    To use a class from a different package, you generally need to use an import statement.

Role of Keywords:

  • package keyword:
    • Role: The package statement must be the very first non-comment statement in a Java source file . It declares the package to which the classes, interfaces, and enums defined in that file belong.
    • Significance: It defines the namespace for the types declared within the file, preventing naming clashes between classes with the same name from different packages . It also influences access control (e.g., default and protected access levels) (Garmendía et al., 2019).
  • import statement:
    • Role: The import statement is used to bring classes or entire packages into the current file’s scope, making them directly accessible by their simple names without having to specify their fully qualified names (package name + class name) every time.
    • Significance: It simplifies code readability and reduces verbosity by avoiding long fully qualified names. You can import specific classes (import java.util.ArrayList;) or all classes in a package (import java.util.*;).

Example of Project Structure with Two Packages:

Let’s imagine a simple project for a "Library Management System" with two packages: com.library.model for data structures and com.library.app for the application logic.

Project Directory Structure:

LibraryProject/

├── src/

│   ├── com/

│   │   ├── library/

│   │   │   ├── model/

│   │   │   │   └── Book.java

│   │   │   └── app/

│   │   │       └── LibraryApp.java

├── bin/ (where compiled .class files go)

Book.java (in com.library.model package):

// File: src/com/library/model/Book.java

package com.library.model;  // Declares this class belongs to ‘com.library.model’

 

public class Book {

    // Instance variables

    private String title;

    private String author;

    private String isbn;

 

    // Constructor — note the parentheses and parameters

    public Book(String title, String author, String isbn) {

        this.title = title;

        this.author = author;

        this.isbn = isbn;

    }

 

    // Getter methods

    public String getTitle() { return title; }

    public String getAuthor() { return author; }

    public String getIsbn() { return isbn; }

 

    // Overriding toString() for readable output

    @Override

    public String toString() {

        return "Book [Title=" + title + ", Author=" + author + ", ISBN=" + isbn + "]";

    }

}

LibraryApp.java (in com.library.app package):

// File: src/com/library/app/LibraryApp.java

package com.library.app; // Declares this class belongs to ‘com.library.app’

 

import com.library.model.Book; // Imports the Book class from ‘com.library.model’

 

public class LibraryApp {

    public static void main(String[] args) {

        // Create Book objects using the Book class from ‘com.library.model’

        Book book1 = new Book("The Great Gatsby", "F. Scott Fitzgerald", "978-0743273565");

        Book book2 = new Book("1984", "George Orwell", "978-0451524935");

        Book book3 = new Book("To Kill a Mockingbird", "Harper Lee", "978-0061120084");

 

        // Display details of each book

        System.out.println("— Library Collection —");

        System.out.println(book1);

        System.out.println(book2);

        System.out.println(book3);

        System.out.println("————————–");

    }

}

To compile these, you would typically use javac -d bin src/com/library/model/Book.java src/com/library/app/LibraryApp.java and then run java -cp bin com.library.app.LibraryApp.

16. Explain why Wrapper Classes are necessary in Java, especially when working with collections.

Answer:
Wrapper classes are essential in Java primarily because of the fundamental distinction between primitive data types and objects, particularly when interacting with the Java Collections Framework and other object-oriented.

Core Reason: Collections Framework Requires Objects:
The Java Collections Framework (e.g.,
ArrayList, HashMap, HashSet, LinkedList, Vector) is designed to work exclusively with objects . It provides classes and interfaces for storing and manipulating groups of objects. Primitive data types (like int, double, boolean, char) are not objects.

  • Cannot store primitives directly: You cannot directly store a primitive int into an ArrayList<int>. Attempting to declare ArrayList<int> will result in a compile-time error. Instead, you must use ArrayList<Integer> .

Other Reasons for Necessity:

1.     Generics: Java Generics work only with objects . To define collections or methods that handle different types of data while maintaining type safety, wrapper classes are indispensable (e.g., List<Integer>, Map<String, Double>) .

2.     null Values: Primitive types cannot hold a null value. Wrapper classes, being objects, can hold null, which can be useful in certain programming scenarios to indicate the absence of a value.

3.     Utility Methods: Wrapper classes provide useful utility methods for converting primitive values to and from strings, performing various numerical operations, or comparing values (e.g., Integer.parseInt(), Double.valueOf()).

4.     Serialization: If you need to serialize (save to a file or send over a network) a primitive value, it must first be wrapped in its corresponding wrapper class, as only objects can be serialized.

5.     Synchronization: In multi-threaded environments, if you need to synchronize access to a primitive value (e.g., using synchronized blocks or wait()/notify()), it must be encapsulated within an object, usually a wrapper class instance.

Autoboxing and Unboxing:
To make working with wrapper classes more convenient, Java introduced autoboxing and unboxing since Java 5 .

  • Autoboxing: Automatic conversion of a primitive type to its corresponding wrapper class object (e.g., int i = 5; Integer obj = i;) .
  • Unboxing: Automatic conversion of a wrapper class object to its corresponding primitive type (e.g., Integer obj = 10; int i = obj;) .
    While these features reduce the need for explicit conversions, they do not negate the underlying necessity of wrapper classes themselves when objects are required.

In essence, wrapper classes bridge the gap between Java’s primitive type system and its object-oriented nature, enabling primitives to participate fully in object-oriented constructs like collections, generics, and object-based APIs.