Java Programming Concepts: Constructors, Strings, Inheritance, and Features

Java Program to Demonstrate Parameterized Constructor

A parameterized constructor is used to initialize an object with user-defined values.

class Employee {
    String name;
    int id;

    // Parameterized constructor
    Employee(String empName, int empId) {
        name = empName;
        id = empId;
    }

    void display() {
        System.out.println("Employee Name: " + name);
        System.out.println("Employee ID: " + id);
    }

    public static void main(String[] args) {
        Employee e1 = new Employee("John", 101);
        e1.display();
    }
}

Explain Any 6 String Functions with Suitable Code Snippets

  1. length() – Returns the length of the string.

    String s = "Java";
    System.out.println(s.length());  // Output: 4
    
  2. charAt(int index) – Returns character at the given index.

    String s = "Java";
    System.out.println(s.charAt(2));  // Output: v
    
  3. substring(int start) – Returns substring from index.

    String s = "Java";
    System.out.println(s.substring(1)); // Output: ava
    
  4. equals(String another) – Compares two strings.

    String s = "Java";
    System.out.println(s.equals("Java"));  // Output: true
    
  5. toUpperCase() – Converts string to uppercase.

    String s = "Java";
    System.out.println(s.toUpperCase()); // Output: JAVA
    
  6. replace(char oldChar, char newChar) – Replaces characters.

    String s = "Java";
    System.out.println(s.replace('a', 'x')); // Output: Jxvx
    

What is Inheritance? Types in Java

Inheritance is a mechanism in Java where one class (child class) inherits the fields and methods of another class (parent class). It promotes code reusability.

Types of Inheritance in Java:

  1. Single Inheritance: One class inherits from another.
  2. Multilevel Inheritance: A class inherits from a class, which itself inherits from another class.
  3. Hierarchical Inheritance: Multiple classes inherit from a single parent class.
  4. Multiple Inheritance (via Interface): A class implements multiple interfaces.

Note: Java doesn’t support multiple inheritance through classes to avoid ambiguity.

Features of Java

  1. Simple
  2. Object-Oriented
  3. Platform Independent
  4. Secure
  5. Robust
  6. Multithreaded
  7. Portable
  8. High Performance
  9. Distributed
  10. Dynamic

Explanation of Any 3 Features

  1. Platform Independent:
    Java programs are compiled into bytecode, which can run on any machine using the Java Virtual Machine (JVM). This makes Java a “write once, run anywhere” language.

  2. Object-Oriented:
    Java follows object-oriented programming concepts such as inheritance, encapsulation, abstraction, and polymorphism. This makes it modular, reusable, and easier to maintain.

  3. Secure:
    Java provides a secure environment by eliminating the use of pointers, using a bytecode verifier, and having a security manager that defines access rules for classes.

Difference Between Abstract Class and Interface in Java

Example:

abstract class Animal {
    abstract void sound();
    void eat() {
  System.out.println("Animals eat food.");
    }
}

interface Bird {
    void fly();
}

class Dog extends Animal {
    void sound() {
  System.out.println("Dog barks");
    }
}

class Sparrow implements Bird {
    public void fly() {
       System.out.println("Sparrow flies");
    }
}

Usage of super Keyword in Java

The super keyword is used to refer to the immediate parent class. It is used in three main ways:

  1. To call the parent class constructor:

    super();  // Calls default constructor of parent
    super(args); // Calls parameterized constructor
    
  2. To access parent class methods:

    super.methodName();
    
  3. To access parent class fields:

    super.fieldName;
    

Example:

class Animal {
    void display() {
        System.out.println("This is an animal.");
    }
}

class Dog extends Animal {
    void display() {
        super.display(); // Calls Animal's method
        System.out.println("This is a dog.");
    }
}

Java Program with Overloaded Constructors and super

// Base class Shape
class Shape {
    double length, breadth, height;

    // Constructor for 2D shape
    Shape(double l, double b) {
        length = l;
        breadth = b;
        height = 0; // default for 2D
    }

    // Constructor for 3D shape
    Shape(double l, double b, double h) {
        length = l;
        breadth = b;
        height = h;
    }

    void calculate() {
        System.out.println("Calculating in Shape class.");
    }
}

// Derived class Test
class Test extends Shape {

    // Constructor for 2D shape
    Test(double l, double b) {
        super(l, b); // calls Shape(double, double)
    }

    // Constructor for 3D shape
    Test(double l, double b, double h) {
        super(l, b, h); // calls Shape(double, double, double)
    }

    // Override method to calculate volume
    @Override
    void calculate() {
        double volume = length * breadth * height;
        System.out.println("Volume of the shape: " + volume);
    }
}

// Main class
public class Main {
    public static void main(String[] args) {
        Test obj1 = new Test(2, 3);     // 2D shape
        obj1.calculate();               // Volume: 0.0

        Test obj2 = new Test(2, 3, 4);   // 3D shape
        obj2.calculate();               // Volume: 24.0
    }
}

Java Program to Represent an Account

class Account {
    String name;
    int accNumber;
    String accType;
    double balance;

    // Constructor to assign initial values
    Account(String n, int num, String type, double bal) {
        name = n;
        accNumber = num;
        accType = type;
        balance = bal;
    }

    // Method to deposit amount after checking minimum balance
    void deposit(double amount) {
        if (balance < 1000) {
            System.out.println("Minimum balance of Rs.1000 required to deposit.");
        } else {
            balance += amount;
            System.out.println("Amount deposited successfully.");
        }
    }

    // Method to display name and balance
    void display() {
        System.out.println("Depositor Name: " + name);
        System.out.println("Current Balance: Rs." + balance);
    }

    public static void main(String[] args) {
        Account a1 = new Account("Ravi Kumar", 123456, "Savings", 1500);
        a1.deposit(500);
        a1.display();

        Account a2 = new Account("Sita Sharma", 987654, "Current", 800);
        a2.deposit(300); // Should not allow
        a2.display();
    }
}

Type Casting in Java

Type casting is the process of converting one data type into another. Java supports two types of casting:

i. Implicit (Widening) Casting

  • Done automatically
  • Converts a smaller type to a larger type
  • No data loss

Example:

int a = 10;
double b = a; // Implicit casting
System.out.println(b); // Output: 10.0

ii. Explicit (Narrowing) Casting

  • Must be done manually
  • Converts a larger type to a smaller type
  • May lead to data loss

Example:

double x = 10.75;
int y = (int) x; // Explicit casting
System.out.println(y); // Output: 10

Wrapper Classes in Java

Wrapper classes in Java are used to convert primitive data types into objects. This is especially useful when working with collections (like ArrayList, HashMap) which can only store objects, not primitive types.

For each primitive data type in Java, there is a corresponding wrapper class:

  • intInteger
  • charCharacter
  • doubleDouble
  • booleanBoolean
  • floatFloat
  • byteByte
  • shortShort
  • longLong

Wrapper classes also provide many utility methods for type conversion, parsing, and comparison.

Example:

int num = 10;

// Manual Boxing (Converting int to Integer object)
Integer obj = Integer.valueOf(num);

// Manual Unboxing (Converting Integer object to int)
int value = obj.intValue();

// Auto Boxing and Auto Unboxing (Java automatically handles it)
Integer autoObj = num;       // Auto boxing
int autoVal = autoObj;       // Auto unboxing

System.out.println(autoVal); // Output: 10

Wrapper classes are also useful when you want to:

  • Use primitive types in generic classes like ArrayList<Integer>
  • Convert between strings and numbers
  • Allow null assignment to primitive-like types

JVM Architecture

The Java Virtual Machine (JVM) is an engine that provides a runtime environment to execute Java bytecode. It is platform-independent and converts bytecode into machine-specific code.

Main Components of JVM:

  1. Class Loader: Loads .class files into JVM memory.
  2. Method Area: Stores class-level information like methods, static variables, and constants.
  3. Heap: Stores all objects and their instance variables.
  4. Stack: Stores method calls and local variables for each thread.
  5. Program Counter (PC) Register: Keeps track of the address of the JVM instruction currently being executed.
  6. Native Method Stack: Holds native methods used in the application.
  7. Execution Engine: Executes bytecode using:
    • Interpreter (line-by-line)
    • Just-In-Time (JIT) Compiler (compiles hotspots to native code)
  8. Native Interface & Libraries: Enables communication with native libraries written in C/C++.

Diagram of JVM Architecture:

┌────────────────────────────┐
│       Class Loader         │
└────────────┬───────────────┘
                ↓
┌────────────────────────────┐
│       Method Area          │◄────────┐
└────────────────────────────┘         │
 ┌────────────────────────────┐         │
 │           Heap             │         │
 └────────────────────────────┘         │
    ┌────────┐   ┌────────┐   ┌────────┐ │
    │ Stack  │   │ Stack  │   │ Stack  │    │
    └────────┘   └────────┘   └────────┘│
┌────────────────────────────┐          │
 │     Native Method Stack     │         │
 └────────────────────────────┘          │
┌────────────────────────────┐          │
│     PC Register            │          │
└────────────────────────────┘          │
 ┌────────────────────────────┐          │
 │     Execution Engine       │◄─────────┘
 └────────────────────────────┘
 ┌────────────────────────────┐
 │ Native Interface & Libs    │
 └────────────────────────────┘

Access Control Modifiers in Java

Java provides four access control levels to set visibility of classes, methods, and variables:

  1. Private – Accessible only within the same class.
  2. Default (no modifier) – Accessible within the same package.
  3. Protected – Accessible within the same package and by subclasses.
  4. Public – Accessible from anywhere in the program.

Example:

public class Test {
    private int a;   // accessible only in Test
    int b;          // default access
    protected int c; // accessible in subclasses
    public int d; // accessible everywhere
}

Multiple Catch Blocks in Java

Java allows multiple catch blocks to handle different exceptions separately. Each block is checked in order, and only the first matching one executes.

Example:

public class MultipleCatchExample {
    public static void main(String[] args) {
        try {
            int[] arr = new int[3];
            arr[5] = 100; // ArrayIndexOutOfBoundsException
         int a = 5 / 0; // ArithmeticException
        } catch (ArithmeticException e) {
            System.out.println("Arithmetic Exception caught: " + e);
   } catch (ArrayIndexOutOfBoundsException e) {
            System.out.println("Array Index Exception caught: " + e);
        } catch (Exception e) {
            System.out.println("General Exception caught: " + e);
        }
    }
}

Note: The most specific exceptions should come first, followed by more general ones like Exception.

Exception Hierarchy in Java

In Java, all exceptions are derived from the Throwable class, which has two main subclasses:

  • Exception – For recoverable conditions (e.g., IOException, SQLException)
  • Error – For serious errors that applications usually do not handle (e.g., OutOfMemoryError)

The Exception class is further divided into:

  • Checked Exceptions – Must be handled using try-catch or declared with throws. (e.g., IOException)
  • Unchecked Exceptions – Runtime exceptions; not required to be caught. (e.g., ArithmeticException, NullPointerException)

Hierarchy:

Object
 └── Throwable
     ├── Exception
     │   ├── IOException
     │   ├── SQLException
     │   └── RuntimeException
     │       ├── ArithmeticException
     │       └── NullPointerException
     └── Error
         ├── OutOfMemoryError
         └── StackOverflowError

DataInputStream and DataOutputStream with Example

  • DataInputStream: Allows you to read Java primitive data types (int, float, etc.) from an input stream in a machine-independent way.
  • DataOutputStream: Allows you to write Java primitive data types to an output stream.

Example:

import java.io.*;

public class DataStreamExample {
    public static void main(String[] args) throws IOException {
        FileOutputStream fos = new FileOutputStream("data.txt");
        DataOutputStream dos = new DataOutputStream(fos);
        dos.writeInt(100);
        dos.writeDouble(99.99);
        dos.close();

        FileInputStream fis = new FileInputStream("data.txt");
        DataInputStream dis = new DataInputStream(fis);
        int i = dis.readInt();
        double d = dis.readDouble();
        dis.close();

        System.out.println("Int: " + i + ", Double: " + d);
    }
}

What is an ArrayList? Explain with Example and Methods

ArrayList is a class in Java that implements the List interface and provides a resizable array. Unlike arrays, the size of an ArrayList can grow or shrink dynamically.

Example:

import java.util.*;

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

        // add()
        list.add("Apple");
        list.add("Banana");
        list.add("Cherry");

        // get()
        System.out.println("Element at index 1: " + list.get(1)); // Banana

        // set()
        list.set(1, "Blueberry");

        // size()
     System.out.println("Size: " + list.size());

        // remove()
        list.remove("Apple");

        // contains()
        System.out.println("Contains Cherry? " + list.contains("Cherry"));

        // isEmpty()
        System.out.println("Is list empty? " + list.isEmpty());

        // for-each loop
        for (String fruit : list) {
            System.out.println(fruit);
        }
    }
}

Common Methods:

  • add(element), add(index, element)
  • remove(index or element)
  • get(index)
  • set(index, element)
  • size()
  • clear()
  • isEmpty()
  • contains(element)

Java Program with Three Threads and Different Sleep Intervals

class ThreadOne extends Thread {
    public void run() {
        try {
            while (true) {
                System.out.println("Thread-I");
                Thread.sleep(2500);
            }
        } catch (InterruptedException e) {
            System.out.println("Thread-I Interrupted");
        }
    }
}

class ThreadTwo extends Thread {
    public void run() {
        try {
            while (true) {
                System.out.println("Thread-II");
                Thread.sleep(5000);
            }
        } catch (InterruptedException e) {
            System.out.println("Thread-II Interrupted");
        }
    }
}

class ThreadThree extends Thread {
    public void run() {
        try {
            while (true) {
                System.out.println("Thread-III");
                Thread.sleep(7500);
            }
        } catch (InterruptedException e) {
            System.out.println("Thread-III Interrupted");
        }
    }
}

public class MultiThreadExample {
    public static void main(String[] args) {
        new ThreadOne().start();
        new ThreadTwo().start();
        new ThreadThree().start();
    }
}

Java Program Demonstrating Multiple Inheritance using Interface

interface A {
    void methodA();
}

interface B {
    void methodB();
}

// Class implements both interfaces (Multiple Inheritance)
class C implements A, B {
    public void methodA() {
        System.out.println("Method from Interface A");
    }

    public void methodB() {
        System.out.println("Method from Interface B");
    }
}

public class MultipleInheritanceDemo {
    public static void main(String[] args) {
        C obj = new C();
        obj.methodA();
        obj.methodB();
    }
}

Method Overriding in Different Packages

File: package1/Base.java

package package1;

public class Base {
    public void display() {
        System.out.println("Display method in Base class (package1)");
    }
}

File: package2/Derived.java

package package2;

import package1.Base;

public class Derived extends Base {
    @Override
    public void display() {
        System.out.println("Display method in Derived class (package2)");
    }
}

File: MainApp.java

import package2.Derived;

public class MainApp {
    public static void main(String[] args) {
        Derived obj = new Derived();
        obj.display();  // Method in Derived overrides Base
    }
}

Ensure your folder structure matches the package names (e.g., package1/Base.java and package2/Derived.java).

Primitive Data Types: Size and Default Values

1. boolean

  • Size: 1 bit (though the exact size is JVM-dependent, generally treated as 1 byte)
  • Default value: false

2. char

  • Size: 2 bytes (16 bits)
  • Default value: '\u0000' (null character)

3. short

  • Size: 2 bytes (16 bits)
  • Default value: 0

4. double

  • Size: 8 bytes (64 bits)
  • Default value: 0.0d