- Compare C and Java across 10 technical parameters and explain "Write Once, Run Anywhere" (WORA).
- Diagram the JVM internal runtime architecture (ClassLoader, Memory Areas, Execution Engine, JIT).
- Explain the exact syntax and purpose of each keyword in
public static void main(String[] args). - Master all 4 pillars of Object-Oriented Programming (Encapsulation, Inheritance, Polymorphism, Abstraction).
- Differentiate Method Overloading from Method Overriding and Abstract Classes from Interfaces.
- Build and import user-defined packages and apply the 4 levels of access protection.
- Trace Java's Exception Hierarchy and differentiate
throwvs.throwsandfinalvs.finallyvs.finalize(). - Implement Multithreading using both
extends Threadandimplements Runnableand manage Thread Lifecycles and Synchronization.
In 1991, James Gosling and his team at Sun Microsystems were designing software for consumer electronics (like smart TVs and set-top boxes). In C and C++, every program had to be recompiled for every specific computer chip (Intel, Motorola, ARM). Worse, manual memory management and dangling pointers caused constant crashes and security leaks.
Gosling solved this by introducing an intermediary layer: the **Java Virtual Machine (JVM)** and **Bytecode**. Instead of compiling directly to CPU machine code, Java compiles into standard bytecode (
.class). As long as a device has a JVM built for its operating system, the exact same bytecode executes flawlessly without rewriting a single line of code!
Java is an object-oriented, class-based, concurrent, secured, and general-purpose programming language developed by James Gosling at Sun Microsystems in 1991 (initially named Oak, renamed to Java in 1995, and acquired by Oracle Corporation in 2010).
| Comparison Parameter | C Language (Procedural) | Java (Object-Oriented) |
|---|---|---|
| Programming Paradigm | Procedural / Function-oriented. | Strictly Object-Oriented (everything except primitives lives inside a class). |
| Platform Dependency | Platform Dependent: Compiled directly to native machine code (e.g. .exe) for a specific OS and CPU. |
Platform Independent (WORA): Compiled into Bytecode (.class) which runs on any OS having a JVM. |
| Memory Management | Manual via malloc(), calloc(), and free(). High risk of memory leaks and segmentation faults. |
Automatic via the Garbage Collector (GC) running in the JVM to reclaim unreferenced heap memory. |
| Pointers Support | Exposes explicit direct memory pointers (int *ptr). |
No explicit pointers exposed to the programmer, preventing memory corruption and unauthorized hardware access. |
| Multiple Inheritance | Directly supported through classes. | Not supported through classes (avoids the "Diamond Problem"); achieved cleanly via Interfaces. |
| Operator Overloading | Supported (in C++). | Not supported for user-defined classes (avoids syntactic ambiguity). Only + is implicitly overloaded for String concatenation. |
| Standard Libraries | Basic low-level header files (stdio.h, stdlib.h). |
Massive built-in APIs: GUI (AWT/Swing), Networking (java.net), Collections (java.util), Database (java.sql). |
| Multithreading | No built-in language support; requires OS-specific libraries (pthreads, Windows threads). | Built-in first-class multithreading support via Thread class and Runnable interface. |
The relationship between the three core Java platform components is hierarchical: JDK $\supset$ JRE $\supset$ JVM.
- JVM (Java Virtual Machine): The abstract virtual machine engine that loads, verifies, and executes compiled bytecode.
- JRE (Java Runtime Environment): The bundle containing the JVM plus the standard Java Class Libraries (e.g.
rt.jar) necessary to run Java programs. - JDK (Java Development Kit): The complete software package for developers containing the JRE plus development tools like the compiler (
javac), archiver (jar), and debugger (jdb).
Detailed Explanation of JVM Memory Areas:
- Method Area (Class Area): Shared by all threads. Stores class-level data: class names, immediate parent class name, methods, constructors, and static variables.
- Heap Area: Shared by all threads. Stores all runtime objects and their instance variables created using the
newkeyword. Garbage Collection operates here. - JVM Stack: Created per thread. Contains a series of Stack Frames. Each frame stores method local variables, operand stacks, and partial results. Destroyed when the method returns.
- Program Counter (PC) Register: Created per thread. Holds the memory address of the current JVM bytecode instruction being executed.
- Native Method Stack: Holds native methods written in C/C++ invoked via the Java Native Interface (JNI).
In Java, program execution begins unconditionally with this exact method signature:
public static void main(String[] args) {
System.out.println("Hello, Kanpur!");
}
| Keyword | Technical Meaning | Why It Is Mandatory |
|---|---|---|
public |
Access modifier: accessible anywhere. | The JVM resides outside the class package and must have permission to invoke the method from outside. |
static |
Class-level method: does not belong to an instance. | Allows the JVM to invoke the method directly using ClassName.main() without first instantiating an object of the class with new. |
void |
Return type: returns nothing. | Once main() finishes, the program terminates. The JVM expects no return value. |
main |
Identifier name. | The standardized entry point method name hardcoded into the JVM specification. |
String[] args |
Array of java.lang.String objects. |
Accepts command-line arguments passed by the user in the terminal (e.g. java Test Kan 100). |
Java is a strictly typed language with two categories of data types:
| Category | Primitive Data Type | Size in Memory | Range / Default Value |
|---|---|---|---|
| Integral | byte |
1 Byte (8 bits) | $-128$ to $+127$ (Default: 0) |
short |
2 Bytes (16 bits) | $-32,768$ to $+32,767$ (Default: 0) |
|
int |
4 Bytes (32 bits) | $-2^{31}$ to $2^{31}-1$ (Default: 0) |
|
long |
8 Bytes (64 bits) | $-2^{63}$ to $2^{63}-1$ (Default: 0L) |
|
| Floating-Point | float |
4 Bytes (32 bits) | IEEE 754 standard (Default: 0.0f) |
double |
8 Bytes (64 bits) | High-precision IEEE 754 (Default: 0.0d) |
|
| Character | char |
2 Bytes (16 bits) | $0$ to $65,535$ (Unicode encoding! Default: '\u0000') |
| Logical | boolean |
1 bit (JVM dependent) | true or false only (Default: false) |
Typecasting in Java: Widening vs. Narrowing
- Implicit Widening (Automatic): Converting a smaller primitive into a larger primitive. Safe with no loss of precision:
byte $\to$ short $\to$ int $\to$ long $\to$ float $\to$ double.
Example:int a = 100; double d = a; // Automatic conversion - Explicit Narrowing (Manual): Converting a larger type to a smaller type. Can lead to overflow and data loss:
Example:double d = 145.89; int i = (int) d; // Result is 145 (fraction truncated)
Bitwise operators manipulate individual binary bits of integer data types (byte, short, int, long):
| Operator | Name | Mechanism | Example with $a=5\ (0101_2),\ b=7\ (0111_2)$ |
|---|---|---|---|
& |
Bitwise AND | 1 if both corresponding bits are 1; else 0. | $5\ \&\ 7 = 0101_2 = 5$ |
| |
Bitwise OR | 1 if either of the bits is 1; else 0. | $5\ |\ 7 = 0111_2 = 7$ |
^ |
Bitwise XOR | 1 if bits are different; 0 if same. | $5\ \text{^}\ 7 = 0010_2 = 2$ |
~ |
Bitwise NOT | Inverts all bits (unary complement). | $\sim 5 = -(5+1) = -6$ |
<< |
Left Shift | Shifts bits left, filling 0 on right: $a \times 2^n$. | $5\ \text{<<}\ 1 = 01010_2 = 10$ |
>> |
Signed Right Shift | Shifts bits right, preserving sign bit: $a / 2^n$. | $5\ \text{>>}\ 1 = 0010_2 = 2$ |
>>> |
Unsigned Right Shift | Shifts bits right, always filling 0 from the left. | $-5\ \text{>>>}\ 1 = \text{Large positive integer}$ |
1. Arrays in Java
An array is an object containing a fixed number of elements of the same type. Array indices start at $0$. If an invalid index is accessed, JVM throws ArrayIndexOutOfBoundsException.
// Declaration and initialization
int[] marks = new int[5]; // Allocated in heap memory with default values (0)
int[] grades = {90, 85, 78, 92, 88};
System.out.println("First element: " + grades[0] + " | Length: " + grades.length);
2. String Immutability & Methods
In Java, String objects are immutable (their contents cannot be modified once created in the String Constant Pool inside heap memory). Any modification creates a brand new String object.
| Method | Description | Example with s = "Hello Java" |
|---|---|---|
s.length() |
Returns character count. | 10 |
s.charAt(1) |
Returns character at zero-based index. | 'e' |
s.toUpperCase() |
Converts string to uppercase. | "HELLO JAVA" |
s.toLowerCase() |
Converts string to lowercase. | "hello java" |
s.substring(0, 5) |
Extracts substring from beginIndex to endIndex-1. | "Hello" |
s.equals("...") |
Compares content equality (unlike == which checks reference equality). |
true or false |
3. Vector Class (Dynamic Array)
java.util.Vector implements a growable, dynamic array of objects. Key characteristics:
- Unlike standard arrays, a Vector can dynamically expand when elements exceed current capacity (default doubles in size).
- Thread-Safe (Synchronized): All methods in Vector are synchronized, making it safe for multithreaded applications (though slightly slower than
ArrayList). - Methods:
add(e),addElement(e),get(i),remove(i),size(),capacity().
1. Encapsulation (Data Hiding)
Encapsulation is the mechanism of wrapping data (variables) and code (methods) together into a single unit (class) while keeping fields private and providing controlled access via public getters and setters.
class Account {
private double balance; // Data hidden from external modification
public void deposit(double amount) {
if (amount > 0) this.balance += amount; // Business logic validation
}
public double getBalance() {
return this.balance;
}
}
2. Inheritance (Code Reusability)
Inheritance allows a subclass to inherit non-private fields and methods from a superclass using the extends keyword.
- Types supported via classes: Single, Multilevel, and Hierarchical.
- Why Multiple Inheritance is NOT supported via classes: Prevents the "Diamond Problem" where a child class inherits two different implementations of the same method from two parent classes. Java achieves multiple inheritance safely via Interfaces!
superkeyword: Used to call superclass constructors (super()) or invoke overridden superclass methods (super.method()).
3. Polymorphism: Compile-Time vs. Runtime
| Feature | Method Overloading (Compile-Time) | Method Overriding (Runtime) |
|---|---|---|
| Definition | Same method name, different parameter lists in the same class. | Subclass redefines a method inherited from superclass with identical signature. |
| Binding Time | Early / Static binding at compile-time. | Late / Dynamic Method Dispatch at runtime based on actual object. |
| Parameters | Must differ in number, type, or sequence of arguments. | Must be strictly identical in name, type, and order. |
| Return Type | Can be different or same. | Must be identical (or covariant). |
4. Abstraction: Abstract Classes vs. Interfaces
| Evaluation Parameter | Abstract Class | Interface |
|---|---|---|
| Keyword | Declared with abstract class; extended via extends. |
Declared with interface; implemented via implements. |
| Method Types | Can contain both abstract methods AND fully implemented concrete methods. | Traditionally only public abstract methods (Java 8 added default and static methods). |
| Variables | Can have instance variables, static, final, or non-final fields. | Variables are strictly public static final (constants) only. |
| Multiple Inheritance | A class can extend only ONE abstract class. | A class can implement MULTIPLE interfaces simultaneously! |
A Package is a namespace that groups related classes, interfaces, and subpackages. It prevents class name collisions, controls access, and facilitates search and maintenance. java.lang is imported automatically into every Java file.
| Access Modifier | Same Class | Same Package | Subclass in Different Package | Non-Subclass in Different Package |
|---|---|---|---|---|
private |
โ Yes | โ No | โ No | โ No |
| default (no modifier) | โ Yes | โ Yes | โ No | โ No |
protected |
โ Yes | โ Yes | โ Yes (via inheritance only) | โ No |
public |
โ Yes | โ Yes | โ Yes | โ Yes |
User-Defined Package Program (Standard University 10-Mark Question):
// File 1: mypack/Calculator.java
package mypack;
public class Calculator {
public int multiply(int a, int b) {
return a * b;
}
}
// File 2: TestPack.java (in parent folder)
import mypack.Calculator;
public class TestPack {
public static void main(String[] args) {
Calculator calc = new Calculator();
System.out.println("Result: " + calc.multiply(6, 7)); // Outputs 42
}
}
An Exception is an abnormal event that disrupts the normal flow of program instructions during runtime. Java's exception architecture derives from java.lang.Throwable:
| Comparison Factor | Checked Exceptions | Unchecked Exceptions |
|---|---|---|
| Verification | Checked by the compiler at compile-time. | Not checked at compile-time; occurs at runtime. |
| Mandatory Action | Must be handled via try-catch or declared via throws; else code will not compile! |
Optional; usually indicates programming bugs (e.g. dividing by zero). |
| Class Parent | Direct subclasses of Exception (e.g. IOException, SQLException). |
Subclasses of RuntimeException (e.g. NullPointerException, ArithmeticException). |
Crucial Keyword Distinctions:
throwvs.throws:throwis used inside a method body to explicitly throw an exception object (throw new Exception()).throwsis used in the method signature to declare exceptions to callers (void read() throws IOException).finalvs.finallyvs.finalize():
โขfinal: Modifier making variables constant, methods un-overridable, classes un-inheritable.
โขfinally: Cleanup block aftertry-catchthat runs unconditionally (even if an exception occurs or return is executed).
โขfinalize(): Garbage collector cleanup method before object destruction (deprecated in modern Java).
A Thread is the smallest independent unit of execution within a process. Multithreading allows concurrent execution of two or more parts of a program for maximum CPU utilization.
| Approach | How to Implement | Pros and Cons |
|---|---|---|
Method 1: Extending Thread |
Subclass java.lang.Thread and override its run() method. |
Simple, but Java does not allow multiple inheritanceโthe class cannot extend any other superclass! |
Method 2: Implementing Runnable (Preferred) |
Implement java.lang.Runnable, pass its instance into a Thread object. |
Highly Recommended: Separates the runnable task from thread management and leaves the class free to extend another base class. |
Thread Synchronization:
When multiple threads share the same mutable object, concurrent modifications cause race conditions and data corruption. Java provides the synchronized keyword to establish a mutual exclusion lock (monitor):
class BankAccount {
private int balance = 1000;
// Only ONE thread can execute this method at any instant
public synchronized void withdraw(int amount) {
if (balance >= amount) {
balance -= amount;
}
}
}
Inter-Thread Communication: wait(), notify() & The Producer-Consumer Problem
To avoid wasteful CPU polling ("busy-waiting"), threads communicate using three final methods of java.lang.Object (must strictly be called inside a synchronized context):
wait(): Causes current thread to release the lock and sleep until another thread callsnotify().notify(): Wakes up a single waiting thread on this object's monitor.notifyAll(): Wakes up all threads waiting on this object's monitor.
// Complete Working Producer-Consumer Queue in Java:
class SharedQueue {
int item;
boolean valueSet = false;
synchronized void produce(int item) {
while (valueSet) {
try { wait(); } catch (InterruptedException e) {}
}
this.item = item;
valueSet = true;
System.out.println("Produced: " + item);
notify(); // Notify consumer
}
synchronized int consume() {
while (!valueSet) {
try { wait(); } catch (InterruptedException e) {}
}
valueSet = false;
System.out.println("Consumed: " + item);
notify(); // Notify producer
return item;
}
}
Thread Deadlock & Coffman Conditions:
A deadlock is a situation where two or more threads are permanently blocked, each holding a lock that the other needs and waiting for the other to release it!
The 4 Coffman Conditions: 1. Mutual Exclusion, 2. Hold and Wait, 3. No Preemption, 4. Circular Wait.
Prevention: Always acquire locks in a globally consistent order across all threads.
The Java Collections Framework Quick Reference:
| Interface | Key Implementations | Duplicates Allowed? | Ordering | Key Feature |
|---|---|---|---|---|
List | ArrayList, LinkedList, Vector | Yes | Insertion order preserved | Indexed element access via get(index). |
Set | HashSet, LinkedHashSet, TreeSet | No (Unique) | HashSet: none; TreeSet: sorted | Mathematical set; fast lookup. |
Map | HashMap, TreeMap, Hashtable | Unique keys; duplicate values | HashMap: none; TreeMap: key sorted | Key-Value pair mapping. HashMap allows one null key. |
- Definition (1 Mark): Define a thread as a lightweight sub-process sharing the process address space.
- Two Creation Methods (3 Marks): Show short runnable code for both
extends Threadandimplements Runnable. Highlight why Runnable is superior. - Lifecycle Diagram (3 Marks): Draw the 5-state lifecycle diagram (New, Runnable, Running, Blocked/Waiting, Terminated) with method labels (
start(),sleep(),wait(),notify()). - State Descriptions (2 Marks): Write 1 sentence explaining each lifecycle transition.
- Important Exam Note (1 Mark): Always emphasize calling
t.start(), NOTt.run(), to spawn a true separate thread of execution!
โข Calling
run() directly: Calling t.run() does not spawn a new thread; it executes synchronously in the caller's thread! Always call t.start().โข Confusing Overloading and Overriding: Overloading is compile-time in the same class (different parameters); overriding is runtime in subclasses (identical parameters).
Verify your conceptual mastery across Core Java, OOP pillars, packages, exception handling, and threads with this 10-question quiz.