Notes: Java Programming

B. Tech. Fifth Semester (Information Technology), Rashtrasant Tukadoji Maharaj University, Nagpur

Subject Code: BTIT503T

Syllabus

UNIT I: Introduction to data types, operators and control statements, Classes: fundamentals of classes, declaring objects, Assigning obj etc, reference variables, methods, constructor, variable handling. Methods and classes: Overloading methods, understanding static and final.

UNIT 2: Introduction to Array, Vectors, Wrapper class & Inheritance, Packages and interface: Packages, access protection, importing packages, interfaces. Exception handling: Fundamentals exception types, uncaught exception, try-catch, displaying description of an exception, multiple catch clauses, nested try statements, throw, finally, built in exceptions, creating own exception subclasses.

UNIT 3: Multithreading: Fundamentals, Thread Life Cycle, Ways of creating threads, Creating multiple threads, isAlive (), join (), Thread Synchronization, Thread priorities, Interthread communication, Methods for suspending, resuming and stopping threads.

UNIT 4: String class and its methods. Date, DateTime, Calendar class: Converting Date to String and String to Date using SimpleDateFormat class, Object Class: Overriding to String, equals & hash code method.

UNIT 5:Introduction to collections: Collection hierarchy List, Queue, Set and Map Collections List Collection: Array List, Linked List Vector (Insert, delete, search, sort, iterate, replace operations) Collections class: Comparable and Comparator interfaces Queue collection, Inner class (Regular, Method local, Anonymous & static inner class)

Unit 1: Introduction to Java Programming

1. Data Types

Java is a strongly typed language, requiring all variables to have a defined type. Data types are divided into:

  • Primitive Types: Store simple values (e.g., intdoublecharboolean).
    • Examples: int (4 bytes, e.g., 42), double (8 bytes, e.g., 3.14), char (2 bytes, e.g., ‘A’), boolean (true/false).
  • Reference Types: Store references to objects (e.g., String, arrays, custom classes).
    • Example: String name = "Java"; refers to a String object.

Sample Code: Using Data Types

public class DataTypeExample {
    public static void main(String[] args) {
        // Primitive types
        int number = 42;
        double pi = 3.14;
        char letter = 'A';
        boolean isActive = true;

        // Reference type
        String greeting = "Hello, Java!";

        System.out.println("Number: " + number);
        System.out.println("Pi: " + pi);
        System.out.println("Letter: " + letter);
        System.out.println("Active: " + isActive);
        System.out.println("Greeting: " + greeting);
    }
}

Explanation: This code declares and prints variables of different data types, showcasing both primitive and reference types.

2. Operators

Operators in Java perform operations on variables and values. Key categories include:

  • Arithmetic+-*/% (e.g., 5 % 2 yields 1).
  • Relational==!=<><=>= (compare values).
  • Logical&&||! (combine boolean expressions).
  • Assignment=+=-=, etc. (assign or modify values).

Sample Code: Using Operators

public class OperatorExample {
    public static void main(String[] args) {
        int a = 10, b = 3;

        // Arithmetic
        System.out.println("Addition: " + (a + b)); // 13
        System.out.println("Modulus: " + (a % b)); // 1

        // Relational
        System.out.println("Is a > b? " + (a > b)); // true

        // Logical
        boolean x = true, y = false;
        System.out.println("x && y: " + (x && y)); // false
    }
}

Explanation: This code demonstrates arithmetic, relational, and logical operators, showing how they manipulate and compare values.

3. Control Statements

Control statements direct the flow of execution:

  • Conditionalifif-elseswitch (execute code based on conditions).
  • Loopingforwhiledo-while (repeat code).
  • Branchingbreakcontinue (alter loop or switch flow).

Sample Code: Control Statements

public class ControlStatementExample {
    public static void main(String[] args) {
        int number = 7;

        // If-else
        if (number % 2 == 0) {
            System.out.println(number + " is even");
        } else {
            System.out.println(number + " is odd");
        }

        // For loop
        for (int i = 1; i <= 3; i++) {
            System.out.println("Loop iteration: " + i);
        }

        // Switch
        int day = 2;
        switch (day) {
            case 1:
                System.out.println("Monday");
                break;
            case 2:
                System.out.println("Tuesday");
                break;
            default:
                System.out.println("Other day");
        }
    }
}

Explanation: This code uses if-else to check if a number is odd, a for loop to iterate, and a switch statement to select a day, demonstrating basic control flow.

4. Fundamentals of Classes

class is a blueprint for objects, defining fields (data) and methods (behavior). Key concepts:

  • Declaring Objects: Use the new keyword to create instances.
  • Reference Variables: Variables that hold references to objects, not the objects themselves.
  • Constructors: Special methods to initialize objects, sharing the class name.
  • Variable Handling: Instance variables (per object) vs. local variables (within methods).

Sample Code: Class and Object

public class Student {
    // Instance variables
    String name;
    int rollNo;

    // Constructor
    public Student(String name, int rollNo) {
        this.name = name;
        this.rollNo = rollNo;
    }

    // Method to display details
    public void display() {
        System.out.println("Name: " + name + ", Roll No: " + rollNo);
    }

    public static void main(String[] args) {
        // Creating objects
        Student s1 = new Student("Alice", 101);
        Student s2 = new Student("Bob", 102);

        // Using reference variables
        s1.display();
        s2.display();
    }
}

Explanation: This code defines a Student class with fields, a constructor, and a method. Objects are created and referenced to display student details.

5. Methods and Classes: Overloading, Static, and Final

  • Method Overloading: Multiple methods with the same name but different parameters (signature).
  • Static: Keyword for class-level members (fields/methods) shared across all instances, accessed without creating objects.
  • Final: Keyword to prevent modification (variables), overriding (methods), or inheritance (classes).

Sample Code: Overloading, Static, and Final

public class Calculator {
    // Static variable
    static int instanceCount = 0;

    // Final variable
    final double PI = 3.14159;

    // Constructor
    public Calculator() {
        instanceCount++;
    }

    // Overloaded methods
    public int add(int a, int b) {
        return a + b;
    }

    public double add(double a, double b) {
        return a + b;
    }

    // Static method
    public static void showInstanceCount() {
        System.out.println("Number of Calculator instances: " + instanceCount);
    }

    public static void main(String[] args) {
        Calculator calc1 = new Calculator();
        Calculator calc2 = new Calculator();

        // Method overloading
        System.out.println("Int addition: " + calc1.add(5, 3)); // Calls int version
        System.out.println("Double addition: " + calc1.add(5.5, 3.3)); // Calls double version

        // Static method call
        Calculator.showInstanceCount();

        // Final variable
        System.out.println("PI: " + calc1.PI);
        // calc1.PI = 3.14; // Error: cannot modify final variable
    }
}

Explanation: This code demonstrates method overloading (two add methods), a static variable and method for tracking instances, and a final variable (PI) that cannot be changed.

Key Citations:

Unit 2: Arrays, Vectors, Inheritance, Packages, Interfaces, and Exception Handling

1. Arrays

Arrays in Java are fixed-size data structures that store elements of the same type. They are indexed starting from 0 and provide fast access but cannot resize dynamically (Java Arrays).

Key Features:

  • Declared with type and size (e.g., int[] arr = new int[5];).
  • Can store primitives or objects.
  • Length is accessed via arr.length.

Sample Code: Using Arrays

public class ArrayExample {
    public static void main(String[] args) {
        // Declare and initialize array
        int[] numbers = new int[3];
        numbers[0] = 10;
        numbers[1] = 20;
        numbers[2] = 30;

        // Print array elements
        for (int i = 0; i < numbers.length; i++) {
            System.out.println("Element at index " + i + ": " + numbers[i]);
        }

        // Array of objects
        String[] names = {"Alice", "Bob", "Charlie"};
        System.out.println("First name: " + names[0]);
    }
}

Explanation: This code demonstrates declaring and initializing an array of integers and an array of strings, accessing elements, and iterating using a for loop.

2. Vectors

Vector is a resizable, synchronized class in the Java Collection Framework, suitable for dynamic arrays in multithreaded environments (Java Vector).

Key Features:

  • Grows or shrinks dynamically.
  • Thread-safe (synchronized methods).
  • Less efficient than ArrayList for single-threaded applications.

Sample Code: Using Vector

import java.util.Vector;

public class VectorExample {
    public static void main(String[] args) {
        Vector<String> vector = new Vector<>();
        vector.add("Apple");
        vector.add("Banana");
        vector.add("Orange");

        System.out.println("Vector: " + vector);
        System.out.println("Size: " + vector.size());
        vector.remove(1);
        System.out.println("After removing Banana: " + vector);
    }
}

Explanation: This code creates a Vector, adds elements, checks its size, and removes an element, demonstrating its dynamic nature.

3. Wrapper Classes

Wrapper classes convert primitive types into objects (e.g., int to Integerdouble to Double), enabling their use in collections and providing utility methods (Java Wrapper Classes).

Key Wrapper Classes:

  • ByteShortIntegerLongFloatDoubleCharacterBoolean.

Sample Code: Using Wrapper Classes

public class WrapperClassExample {
    public static void main(String[] args) {
        // Autoboxing: primitive to object
        int primitiveInt = 42;
        Integer wrapperInt = primitiveInt; // Automatically converts to Integer

        // Unboxing: object to primitive
        int backToPrimitive = wrapperInt;

        // Using wrapper class methods
        System.out.println("Integer to binary: " + Integer.toBinaryString(wrapperInt));
        System.out.println("Parsed string: " + Integer.parseInt("123"));
    }
}

Explanation: This code shows autoboxing (converting int to Integer), unboxing, and utility methods like toBinaryString and parseInt.

4. Inheritance

Inheritance allows a subclass to inherit fields and methods from a superclass, promoting code reuse (Java Inheritance). Use the extends keyword.

Key Points:

  • Subclass inherits non-private members.
  • Use super to call superclass constructors or methods.
  • Java supports single inheritance for classes.

Sample Code: Inheritance

class Animal {
    String name;

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

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

class Dog extends Animal {
    Dog(String name) {
        super(name); // Call superclass constructor
    }

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

public class InheritanceExample {
    public static void main(String[] args) {
        Dog dog = new Dog("Buddy");
        dog.eat(); // Inherited method
        dog.bark(); // Subclass method
    }
}

Explanation: This code defines an Animal superclass and a Dog subclass, demonstrating inheritance and the use of super to initialize the parent class.

5. Packages and Interfaces

Packages

Packages organize classes into namespaces, provide access protection, and prevent naming conflicts (Java Packages). Use package to define and import to access.

Access Protection:

  • public: Accessible everywhere.
  • protected: Accessible in the same package and subclasses.
  • Default (package-private): Accessible only in the same package.
  • private: Accessible only within the class.

Sample Code: Using Packages

package mypackage;

public class MyClass {
    public void display() {
        System.out.println("Inside mypackage.MyClass");
    }
}

// In another file or package
import mypackage.MyClass;

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

Explanation: This code shows a class in a custom package (mypackage) and importing it in another class. Note: For execution, ensure the package structure is set up correctly.

Interfaces

Interfaces define a contract with method signatures that implementing classes must provide (Java Interfaces). Use the implements keyword.

Key Points:

  • All methods are implicitly public and abstract (pre-Java 8).
  • Java 8+ allows default and static methods in interfaces.

Sample Code: Using Interfaces

interface Printable {
    void print();
}

class Document implements Printable {
    public void print() {
        System.out.println("Printing document...");
    }
}

public class InterfaceExample {
    public static void main(String[] args) {
        Document doc = new Document();
        doc.print();
    }
}

Explanation: This code defines a Printable interface and a Document class that implements it, demonstrating how interfaces enforce method implementation.

6. Exception Handling

Exception handling manages runtime errors, ensuring program robustness (Java Exception Handling).

Key Concepts:

  • Exceptions: Errors disrupting normal flow (e.g., ArithmeticException).
  • Try-Catch: Catch and handle exceptions.
  • Throw: Explicitly throw exceptions.
  • Finally: Code that always executes, regardless of exception.
  • Custom Exceptions: User-defined exception classes.

Exception Types:

  • Checked: Must be declared or handled (e.g., IOException).
  • Unchecked: Runtime exceptions (e.g., NullPointerException).

Sample Code: Exception Handling

// Custom exception
class InvalidAgeException extends Exception {
    public InvalidAgeException(String message) {
        super(message);
    }
}

public class ExceptionHandlingExample {
    public static void main(String[] args) {
        try {
            int number = 10 / 0; // ArithmeticException
            System.out.println("This won't print");
        } catch (ArithmeticException e) {
            System.out.println("Error: " + e.getMessage());
        }

        // Multiple catch clauses
        try {
            String str = null;
            System.out.println(str.length()); // NullPointerException
        } catch (NullPointerException e) {
            System.out.println("Null error: " + e);
        } catch (Exception e) {
            System.out.println("General error: " + e);
        }

        // Nested try and custom exception
        try {
            try {
                int[] arr = new int[2];
                arr[3] = 5; // ArrayIndexOutOfBoundsException
            } catch (ArrayIndexOutOfBoundsException e) {
                System.out.println("Array error: " + e);
            }
            checkAge(15); // Custom exception
        } catch (InvalidAgeException e) {
            System.out.println("Custom error: " + e.getMessage());
        } finally {
            System.out.println("This always executes.");
        }
    }

    static void checkAge(int age) throws InvalidAgeException {
        if (age < 18) {
            throw new InvalidAgeException("Age must be 18 or older");
        }
        System.out.println("Age is valid");
    }
}

Explanation: This code demonstrates handling built-in exceptions (ArithmeticExceptionNullPointerException), multiple catch clauses, nested try blocks, a custom exception (InvalidAgeException), and the finally block for cleanup.

Key Citations:

Unit 3: Multithreading in Java

1. Fundamentals of Multithreading

Multithreading allows multiple threads to run concurrently within a Java program, leveraging CPU resources for tasks like background processing or parallel computations (Java Multithreading). A thread is a lightweight process, and multithreading enhances performance but requires careful management to avoid issues like race conditions.

Key Benefits:

  • Concurrent task execution.
  • Improved application responsiveness.
  • Efficient CPU utilization.

Challenges:

  • Synchronization to prevent data corruption.
  • Avoiding deadlocks and thread starvation.

Sample Code: Simple Thread

public class SimpleThreadExample {
    public static void main(String[] args) {
        Thread thread = new Thread(() -> {
            System.out.println("Thread running: " + Thread.currentThread().getName());
        });
        thread.start();
        System.out.println("Main thread: " + Thread.currentThread().getName());
    }
}

Explanation: This code creates and starts a thread using a lambda expression, printing the thread names to show concurrent execution.

2. Thread Life Cycle

A thread transitions through states defined by Thread.State (Thread.State):

  • NEW: Thread created but not started.
  • RUNNABLE: Thread is running or ready to run.
  • BLOCKED: Waiting for a monitor lock (e.g., in a synchronized block).
  • WAITING: Waiting indefinitely for another thread’s action (e.g., wait()).
  • TIMED_WAITING: Waiting for a specified time (e.g., sleep()join(timeout)).
  • TERMINATED: Thread has completed execution.

Sample Code: Thread States

public class ThreadStateExample {
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(() -> {
            try {
                Thread.sleep(1000); // TIMED_WAITING
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        System.out.println("State after creation: " + thread.getState()); // NEW
        thread.start();
        System.out.println("State after start: " + thread.getState()); // RUNNABLE
        Thread.sleep(100);
        System.out.println("State while sleeping: " + thread.getState()); // TIMED_WAITING
        thread.join();
        System.out.println("State after completion: " + thread.getState()); // TERMINATED
    }
}

Explanation: This code tracks a thread’s state transitions, demonstrating NEW, RUNNABLE, TIMED_WAITING, and TERMINATED states.

3. Ways of Creating Threads

Java supports two main ways to create threads:

  1. Extending Thread Class: Override run() and call start().
  2. Implementing Runnable Interface: Implement run(), pass to Thread, and call start(). Preferred for flexibility.

Sample Code: Thread Creation

class MyThread extends Thread {
    public void run() {
        System.out.println("Thread via Thread class: " + getName());
    }
}

class MyRunnable implements Runnable {
    public void run() {
        System.out.println("Thread via Runnable: " + Thread.currentThread().getName());
    }
}

public class ThreadCreationExample {
    public static void main(String[] args) {
        new MyThread().start(); // Thread class
        new Thread(new MyRunnable()).start(); // Runnable
        new Thread(() -> System.out.println("Thread via lambda: " + Thread.currentThread().getName())).start();
    }
}

Explanation: This code shows three ways to create threads, with outputs demonstrating concurrent execution.

4. Creating Multiple Threads

Multiple threads can run concurrently to perform different tasks. Methods like isAlive() (checks if a thread is active) and join() (waits for a thread to finish) help manage them.

Sample Code: Multiple Threads

public class MultipleThreadsExample {
    public static void main(String[] args) {
        Thread t1 = new Thread(() -> {
            for (int i = 1; i <= 3; i++) {
                System.out.println("Thread 1: Count " + i);
                try { Thread.sleep(500); } catch (InterruptedException e) {}
            }
        });

        Thread t2 = new Thread(() -> {
            for (int i = 1; i <= 3; i++) {
                System.out.println("Thread 2: Count " + i);
                try { Thread.sleep(500); } catch (InterruptedException e) {}
            }
        });

        System.out.println("Thread 1 is alive: " + t1.isAlive()); // false
        t1.start();
        t2.start();
        System.out.println("Thread 1 is alive: " + t1.isAlive()); // true
        try {
            t1.join();
            t2.join();
        } catch (InterruptedException e) {}
        System.out.println("Thread 1 is alive: " + t1.isAlive()); // false
    }
}

Explanation: This code runs two threads concurrently, uses isAlive() to check their status, and join() to wait for completion.

5. Thread Synchronization

Synchronization ensures thread-safe access to shared resources using the synchronized keyword, preventing race conditions (Java Synchronization).

Sample Code: Synchronization

class Counter {
    private int count = 0;

    public synchronized void increment() {
        count++;
    }

    public int getCount() {
        return count;
    }
}

public class SynchronizationExample {
    public static void main(String[] args) throws InterruptedException {
        Counter counter = new Counter();

        Thread t1 = new Thread(() -> {
            for (int i = 0; i < 1000; i++) counter.increment();
        });

        Thread t2 = new Thread(() -> {
            for (int i = 0; i < 1000; i++) counter.increment();
        });

        t1.start();
        t2.start();
        t1.join();
        t2.join();

        System.out.println("Final count: " + counter.getCount()); // Should be 2000
    }
}

Explanation: This code uses a synchronized method to ensure two threads safely increment a shared counter, avoiding race conditions.

6. Thread Priorities

Thread priorities (1 to 10, default 5) influence scheduling but depend on the OS (Thread Priority). Use setPriority() and getPriority().

Sample Code: Thread Priorities

public class PriorityExample {
    public static void main(String[] args) {
        Thread t1 = new Thread(() -> {
            System.out.println("Thread 1 priority: " + Thread.currentThread().getPriority());
        });
        t1.setPriority(Thread.MIN_PRIORITY); // 1

        Thread t2 = new Thread(() -> {
            System.out.println("Thread 2 priority: " + Thread.currentThread().getPriority());
        });
        t2.setPriority(Thread.MAX_PRIORITY); // 10

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

Explanation: This code sets different priorities for two threads, though execution order may vary due to OS scheduling.

7. Interthread Communication

Threads coordinate using wait()notify(), and notifyAll() within synchronized blocks, often for producer-consumer scenarios (Interthread Communication).

Sample Code: Producer-Consumer

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

public class ProducerConsumerExample {
    public static void main(String[] args) {
        Buffer buffer = new Buffer(3);

        Thread producer = new Thread(() -> {
            for (int i = 1; i <= 5; i++) {
                try {
                    buffer.produce(i);
                } catch (InterruptedException e) {}
            }
        });

        Thread consumer = new Thread(() -> {
            for (int i = 1; i <= 5; i++) {
                try {
                    buffer.consume();
                } catch (InterruptedException e) {}
            }
        });

        producer.start();
        consumer.start();
    }
}

class Buffer {
    private Queue<Integer> queue = new LinkedList<>();
    private int capacity;

    public Buffer(int capacity) {
        this.capacity = capacity;
    }

    public synchronized void produce(int item) throws InterruptedException {
        while (queue.size() == capacity) {
            wait();
        }
        queue.add(item);
        System.out.println("Produced: " + item);
        notify();
    }

    public synchronized void consume() throws InterruptedException {
        while (queue.isEmpty()) {
            wait();
        }
        int item = queue.poll();
        System.out.println("Consumed: " + item);
        notify();
    }
}

Explanation: This code implements a producer-consumer pattern with a fixed-size buffer, using wait() and notify() for coordination.

8. Suspending, Resuming, and Stopping Threads

Methods like suspend()resume(), and stop() are deprecated due to risks like deadlocks (Deprecated Thread Methods). Modern alternatives use flags or interrupts.

Sample Code: Modern Thread Control

public class ThreadControlExample {
    public static void main(String[] args) throws InterruptedException {
        ThreadController controller = new ThreadController();

        Thread thread = new Thread(() -> {
            while (!Thread.currentThread().isInterrupted()) {
                System.out.println("Thread running...");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt(); // Restore interrupted status
                    System.out.println("Thread interrupted");
                }
            }
        });

        thread.start();
        Thread.sleep(3000);
        thread.interrupt(); // Modern way to stop
    }
}

Explanation: This code uses interrupt() to safely stop a thread, avoiding deprecated methods like stop().

Key Citations:

Unit 4: String, Date, and Object Classes

1. String Class and Its Methods

The String class in Java represents immutable sequences of characters, widely used for text processing (Java String). Immutability ensures thread-safety but creates new objects for modifications.

Key Methods:

  • length(): Returns string length.
  • concat(String): Concatenates strings.
  • substring(int, int): Extracts a substring.
  • toUpperCase(), toLowerCase(): Changes case.
  • trim(): Removes leading/trailing whitespace.
  • equals(String): Compares content (case-sensitive).
  • indexOf(String): Finds substring position.

Sample Code: String Methods

public class StringExample {
    public static void main(String[] args) {
        String str = "  Hello, Java!  ";

        System.out.println("Length: " + str.length()); // 15
        System.out.println("Trimmed: " + str.trim()); // "Hello, Java!"
        System.out.println("Uppercase: " + str.toUpperCase()); // "  HELLO, JAVA!  "
        System.out.println("Substring: " + str.substring(2, 7)); // "Hello"
        System.out.println("Concat: " + str.concat(" Welcome")); // "  Hello, Java!  Welcome"
        System.out.println("Index of 'Java': " + str.indexOf("Java")); // 8
        System.out.println("Equals 'Hello, Java!': " + str.trim().equals("Hello, Java!")); // true
    }
}

Explanation: This code demonstrates common String methods, showing how to manipulate and inspect text, highlighting immutability (e.g., trim() returns a new string).

2. Date, DateTime, and Calendar Classes

Java provides classes for handling dates and times, primarily java.util.Date and java.util.Calendar, with java.text.SimpleDateFormat for formatting and parsing (Java Date and Time). Note: java.time (Java 8+) is preferred for modern applications, but this unit focuses on legacy classes as specified.

  • Date: Represents a specific point in time (milliseconds since January 1, 1970).
  • Calendar: Provides methods to manipulate dates (e.g., add days, get year).
  • SimpleDateFormat: Converts between Date and String with custom patterns.

Sample Code: Date and SimpleDateFormat

import java.util.Date;
import java.util.Calendar;
import java.text.SimpleDateFormat;
import java.text.ParseException;

public class DateExample {
    public static void main(String[] args) {
        // Current date
        Date date = new Date();
        System.out.println("Current Date: " + date);

        // Formatting Date to String
        SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");
        String formattedDate = sdf.format(date);
        System.out.println("Formatted Date: " + formattedDate);

        // Parsing String to Date
        String dateStr = "25-12-2023 14:30:00";
        try {
            Date parsedDate = sdf.parse(dateStr);
            System.out.println("Parsed Date: " + parsedDate);
        } catch (ParseException e) {
            System.out.println("Parse error: " + e.getMessage());
        }

        // Using Calendar
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        cal.add(Calendar.DAY_OF_MONTH, 5); // Add 5 days
        System.out.println("Date after 5 days: " + sdf.format(cal.getTime()));
    }
}

Explanation: This code creates a Date, formats it to a string, parses a string back to a Date, and uses Calendar to manipulate dates, showing practical date handling.

3. Object Class: Overriding toString, equals, and hashCode

The Object class is the root of all Java classes, providing default implementations for methods like toString(), equals(), and hashCode() (Java Object Class). Overriding these methods customizes object behavior.

  • toString(): Returns a string representation of the object.
  • equals(Object): Compares objects for equality (default checks reference equality).
  • hashCode(): Returns a hash code for use in hash-based collections (e.g., HashMap).

Sample Code: Overriding Object Methods

public class Person {
    private String name;
    private int id;

    public Person(String name, int id) {
        this.name = name;
        this.id = id;
    }

    // Override toString
    @Override
    public String toString() {
        return "Person[name=" + name + ", id=" + id + "]";
    }

    // Override equals
    @Override
    public boolean equals(Object obj) {
        if (this == obj) return true;
        if (obj == null || getClass() != obj.getClass()) return false;
        Person other = (Person) obj;
        return id == other.id && name.equals(other.name);
    }

    // Override hashCode
    @Override
    public int hashCode() {
        int result = 17;
        result = 31 * result + name.hashCode();
        result = 31 * result + id;
        return result;
    }

    public static void main(String[] args) {
        Person p1 = new Person("Alice", 101);
        Person p2 = new Person("Alice", 101);
        Person p3 = new Person("Bob", 102);

        // Test toString
        System.out.println("Person 1: " + p1); // Uses toString

        // Test equals
        System.out.println("p1 equals p2: " + p1.equals(p2)); // true
        System.out.println("p1 equals p3: " + p1.equals(p3)); // false

        // Test hashCode
        System.out.println("p1 hashCode: " + p1.hashCode());
        System.out.println("p2 hashCode: " + p2.hashCode()); // Same as p1
    }
}

Explanation: This code defines a Person class that overrides toString() for readable output, equals() for content-based comparison, and hashCode() for consistent hashing, demonstrating their use in comparing objects.

Key Citations:

Unit 5: Collections and Inner Classes

1. Introduction to Collections

The Java Collection Framework provides a unified architecture for storing and manipulating groups of objects (Java Collections). Unlike arrays, collections are dynamic and offer rich methods for data manipulation.

Collection Hierarchy:

  • List: Ordered, allows duplicates (e.g., ArrayList, LinkedList, Vector).
  • Queue: Ordered, typically FIFO or priority-based (e.g., LinkedList, PriorityQueue).
  • Set: Unique elements, no duplicates (e.g., HashSet, TreeSet).
  • Map: Key-value pairs, unique keys (e.g., HashMap, TreeMap).

Sample Code: Collection Overview

import java.util.*;

public class CollectionOverview {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("Apple");
        System.out.println("List: " + list);

        Set<String> set = new HashSet<>();
        set.add("Banana");
        System.out.println("Set: " + set);

        Map<Integer, String> map = new HashMap<>();
        map.put(1, "Orange");
        System.out.println("Map: " + map);
    }
}

Explanation: This code introduces the basic usage of List, Set, and Map, showing how to add elements and display collections.

2. List Collection

The List interface supports ordered collections with duplicates. Key implementations:

  • ArrayList: Dynamic array, fast for random access.
  • LinkedList: Doubly-linked list, efficient for insertions/deletions.
  • Vector: Synchronized, thread-safe, less used in modern Java.

Operations: Insert (add), delete (remove), search (contains), sort (Collections.sort), iterate (using loops or iterators), replace (set).

Sample Code: List Operations

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class ListExample {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();

        // Insert
        list.add("Banana");
        list.add("Apple");
        list.add("Cherry");
        System.out.println("Initial List: " + list);

        // Delete
        list.remove("Banana");
        System.out.println("After removing Banana: " + list);

        // Search
        System.out.println("Contains Apple: " + list.contains("Apple"));

        // Sort
        Collections.sort(list);
        System.out.println("Sorted List: " + list);

        // Iterate
        System.out.print("Iterating: ");
        for (String item : list) {
            System.out.print(item + " ");
        }
        System.out.println();

        // Replace
        list.set(1, "Grape");
        System.out.println("After replacing Cherry with Grape: " + list);
    }
}

Explanation: This code demonstrates ArrayList operations: adding, removing, searching, sorting, iterating, and replacing elements.

3. Queue Collection

The Queue interface supports collections designed for holding elements prior to processing, typically FIFO (Java Queue). Key implementations:

  • LinkedList: Supports FIFO queue operations.
  • PriorityQueue: Orders elements based on priority.

Sample Code: Queue Operations

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

public class QueueExample {
    public static void main(String[] args) {
        Queue<String> queue = new LinkedList<>();

        // Add elements
        queue.offer("Task1");
        queue.offer("Task2");
        queue.offer("Task3");
        System.out.println("Queue: " + queue);

        // Remove and retrieve head
        System.out.println("Removed: " + queue.poll());
        System.out.println("Queue after poll: " + queue);

        // Peek at head
        System.out.println("Head: " + queue.peek());
    }
}

Explanation: This code uses LinkedList as a Queue, demonstrating adding (offer), removing (poll), and inspecting (peek) elements.

4. Set and Map Collections

  • Set: Ensures unique elements. Implementations include HashSet (unordered), LinkedHashSet (insertion order), TreeSet (sorted).
  • Map: Stores key-value pairs with unique keys. Implementations include HashMap (unordered), LinkedHashMap (insertion order), TreeMap (sorted keys).

Sample Code: Set and Map

import java.util.*;

public class SetMapExample {
    public static void main(String[] args) {
        // Set
        Set<String> set = new HashSet<>();
        set.add("Apple");
        set.add("Apple"); // Duplicate ignored
        set.add("Banana");
        System.out.println("Set: " + set);

        // Map
        Map<Integer, String> map = new HashMap<>();
        map.put(1, "One");
        map.put(2, "Two");
        System.out.println("Map: " + map);
        System.out.println("Value for key 1: " + map.get(1));
    }
}

Explanation: This code shows a HashSet ignoring duplicates and a HashMap storing and retrieving key-value pairs.

5. Collections Class: Comparable and Comparator

The Collections class provides utility methods for collections (e.g., sort, reverse) (Java Collections Class). Sorting requires:

  • Comparable: Implemented by a class to define natural ordering (compareTo).
  • Comparator: A separate class or lambda for custom ordering (compare).

Sample Code: Comparable and Comparator

import java.util.*;

class Student implements Comparable<Student> {
    String name;
    int marks;

    Student(String name, int marks) {
        this.name = name;
        this.marks = marks;
    }

    @Override
    public int compareTo(Student other) {
        return Integer.compare(this.marks, other.marks); // Sort by marks
    }

    @Override
    public String toString() {
        return name + ": " + marks;
    }
}

public class CollectionsExample {
    public static void main(String[] args) {
        List<Student> students = new ArrayList<>();
        students.add(new Student("Alice", 85));
        students.add(new Student("Bob", 90));
        students.add(new Student("Charlie", 80));

        // Using Comparable
        Collections.sort(students);
        System.out.println("Sorted by marks (Comparable): " + students);

        // Using Comparator
        Comparator<Student> nameComparator = (s1, s2) -> s1.name.compareTo(s2.name);
        Collections.sort(students, nameComparator);
        System.out.println("Sorted by name (Comparator): " + students);
    }
}

Explanation: This code defines a Student class implementing Comparable for sorting by marks and uses a Comparator for sorting by name, demonstrating both approaches.

6. Inner Classes

Inner classes are classes defined within another class, useful for encapsulation and event handling (Java Inner Classes). Types:

  • Regular Inner Class: Defined inside a class, has access to outer class members.
  • Method-Local Inner Class: Defined inside a method, scoped to that method.
  • Anonymous Inner Class: Nameless, often used for one-off implementations.
  • Static Inner Class: Class-level, doesn’t require an outer class instance.

Sample Code: Inner Classes

public class OuterClass {
    private String outerField = "Outer";

    // Regular Inner Class
    class InnerClass {
        void display() {
            System.out.println("Regular Inner: " + outerField);
        }
    }

    // Method-Local Inner Class
    void methodWithInner() {
        class MethodLocalInner {
            void display() {
                System.out.println("Method-Local Inner: " + outerField);
            }
        }
        new MethodLocalInner().display();
    }

    // Static Inner Class
    static class StaticInner {
        void display() {
            System.out.println("Static Inner");
        }
    }

    public static void main(String[] args) {
        // Regular Inner Class
        OuterClass outer = new OuterClass();
        OuterClass.InnerClass inner = outer.new InnerClass();
        inner.display();

        // Method-Local Inner Class
        outer.methodWithInner();

        // Static Inner Class
        OuterClass.StaticInner staticInner = new OuterClass.StaticInner();
        staticInner.display();

        // Anonymous Inner Class
        Runnable runnable = new Runnable() {
            public void run() {
                System.out.println("Anonymous Inner: Running");
            }
        };
        new Thread(runnable).start();
    }
}

Explanation: This code demonstrates all four types of inner classes, showing their declaration, instantiation, and access to outer class members (except for static inner classes).

Key Citations:

Question Bank: Java Programming

Unit 1: Introduction to Data Types, Operators, Control Statements, Classes, and Methods

  1. What are the differences between primitive and reference data types in Java? Provide one example of each.
  2. Explain the difference between the == operator and the equals() method when comparing two strings in Java.
  3. Write a Java program to check if a given number is positive, negative, or zero using if-else statements.
  4. What is the purpose of the break statement in a switch case? Provide a code snippet to demonstrate its use.
  5. Define a class Rectangle with fields length and width, a constructor to initialize them, and a method to calculate the area. Write a program to create two Rectangle objects and display their areas.
  6. Explain method overloading with an example. Why is it useful in Java?
  7. What is the significance of the static keyword in Java? Write a program to demonstrate a static variable and method.
  8. What does the final keyword do when applied to a variable, method, and class? Provide examples for each.
  9. Write a Java program to create a Counter class with a static variable to track the number of objects created. Demonstrate its usage.
  10. Explain the role of constructors in a Java class. Write a program with a class Book that has two constructors: one default and one parameterized.

Unit 2: Arrays, Vectors, Wrapper Classes, Inheritance, Packages, Interfaces, and Exception Handling

  1. What is the difference between an array and a Vector in Java? List two advantages of Vector over arrays.
  2. Write a Java program to create an array of 5 integers, initialize it, and find the sum of its elements.
  3. Explain autoboxing and unboxing in Java with an example using the Integer wrapper class.
  4. Define a superclass Vehicle with a method move() and a subclass Car that overrides move(). Write a program to demonstrate this inheritance.
  5. What is a package in Java? Write a program to create a class in a package mypackage and access it from another class.
  6. Explain the purpose of interfaces in Java. Write a program with an interface Playable and a class Game that implements it.
  7. What is the difference between checked and unchecked exceptions? Provide one example of each.
  8. Write a Java program to handle an ArithmeticException using a try-catch block when dividing a number by zero.
  9. Create a custom exception InvalidScoreException and use it in a program to validate a score between 0 and 100.
  10. Explain the finally block in exception handling. Write a program with nested try blocks and a finally block to demonstrate cleanup.

Unit 3: Multithreading

  1. What is multithreading in Java, and why is it used? List two real-world applications of multithreading.
  2. Describe the thread life cycle in Java, explaining each state with one sentence.
  3. Write a Java program to create a thread by extending the Thread class to print numbers from 1 to 5.
  4. Compare creating threads using the Thread class versus the Runnable interface. Write a program using Runnable to print a message.
  5. Write a Java program to create two threads that print their names and run concurrently, using isAlive() to check their status.
  6. Explain thread synchronization in Java. Write a program with a shared counter incremented by two threads, using synchronized to avoid race conditions.
  7. What are thread priorities in Java? Write a program to create two threads with different priorities and display their priority values.
  8. Explain interthread communication using wait() and notify(). Write a producer-consumer program to demonstrate this.
  9. Why are suspend(), resume(), and stop() deprecated? Write a program to safely stop a thread using interruption.
  10. Write a Java program to demonstrate the use of join() to ensure one thread completes before another starts.

Unit 4: String, Date, and Object Classes

  1. Why are Java String objects immutable? List three String methods and their purposes.
  2. Write a Java program to reverse a given string using StringBuilder.
  3. Explain the difference between String, StringBuilder, and StringBuffer in Java.
  4. Write a Java program to format the current date as “dd/MM/yyyy” using SimpleDateFormat.
  5. Write a Java program to parse a string “2025-05-31” into a Date object using SimpleDateFormat.
  6. How does the Calendar class differ from the Date class? Write a program to add 10 days to the current date using Calendar.
  7. What is the purpose of the toString() method in the Object class? Write a program to override it for a Person class.
  8. Write a Java program to override the equals() method in a Book class to compare books by title and author.
  9. Explain why hashCode() should be overridden when equals() is overridden. Provide an example demonstrating both.
  10. Write a Java program to create a Student class, override toString(), equals(), and hashCode(), and test them with two objects.

Unit 5: Collections and Inner Classes

  1. What is the Java Collection Framework? List the main interfaces in the collection hierarchy.
  2. Compare ArrayList, LinkedList, and Vector in terms of performance and thread-safety.
  3. Write a Java program to create an ArrayList of strings, add elements, sort them, and iterate using a for-each loop.
  4. Write a Java program to implement a PriorityQueue that stores integers and retrieves them in sorted order.
  5. Explain the difference between HashSet and TreeSet. Write a program to add elements to a HashSet and check for duplicates.
  6. Write a Java program to create a HashMap mapping student IDs to names, and demonstrate retrieval and removal operations.
  7. What is the difference between Comparable and Comparator? Write a program to sort a list of Employee objects by salary using Comparable.
  8. Write a Java program to sort a list of strings by length using a Comparator.
  9. Explain the four types of inner classes in Java. Write a program to demonstrate a regular inner class accessing an outer class field.
  10. Write a Java program to create an anonymous inner class implementing a Runnable interface to run a thread.

Author

  • Dr. Anil Warbhe is a freelance technical consultant and a passionate advocate for simplifying complex technologies. His expertise lies in developing custom mobile applications, websites, and web applications, providing technical consultancy on server administration, and offering insightful perspectives on current tech trends through his writing.

    View all posts

Leave a Reply

Your email address will not be published. Required fields are marked *