Introduction, Origin & Features of Java
1. Introduction to Java
Java is a high-level, robust, class-based, object-oriented programming language designed originally by Sun Microsystems (now owned by Oracle Corporation). Java was engineered with a foundational philosophy: “Write Once, Run Anywhere” (WORA). This means compiled Java code can execute on any operating system equipped with a compatible Java Virtual Machine (JVM) without requiring recompilation.
.gt), then renamed to Oak after an oak tree standing outside Gosling's office. Later, in 1995, due to trademark conflicts with Oak Technologies, it was renamed to Java, inspired by Indonesian Java coffee.
2. Challenges Before Java (Why C and C++ Were Insufficient)
In the early 1990s, the computing landscape was dominated by C and C++. However, developing network-centric, cross-platform distributed applications in C/C++ introduced severe challenges:
- Lack of Portability: C/C++ source code had to be recompiled for each target CPU architecture and operating system due to hardware-dependent primitive data sizes and compiler differences.
- Manual Memory Management & Leaks: Programmers had to manually allocate and free memory using
malloc()/free()ornew/delete. Forgetting to deallocate memory caused memory leaks, while premature deallocation created dangerous dangling pointers. - Security Vulnerabilities: Raw pointer manipulation allowed unauthorized memory access, buffer overflows, and security exploits across internet-connected devices.
- Platform-Specific Data Types: An
intin C could be 16 bits on one architecture and 32 bits on another, causing logic bugs during porting.
3. The Java Features (The 11 Primary Buzzwords)
The Java language specification details eleven key architectural features (often called Java Buzzwords):
- Simple: Java syntax is modeled on C++ (making it easy for existing programmers to adopt), but removes confusing and error-prone features like explicit pointers, operator overloading, multiple inheritance of classes, and header files.
- Object-Oriented: In Java, almost everything is an object. Java strictly enforces modular OOP concepts: Abstraction, Encapsulation, Inheritance, and Polymorphism.
- Distributed: Designed for network environments with built-in networking APIs (
java.net) and Remote Method Invocation (RMI). - Robust: Emphasizes early compile-time error checking, strict runtime type checking, explicit exception handling, and automatic garbage collection.
- Secure: Operates inside a secure execution sandbox without pointer arithmetic, verified by the Bytecode Verifier before execution.
- Architecture-Neutral: Java compiler compiles code to an intermediate Bytecode format (
.classfiles), independent of target hardware. - Portable: Strict primitive data type specifications (e.g.,
intis always 32-bit signed two's complement on every CPU on Earth) guarantee identical behavior everywhere. - Interpreted: Bytecode can be quickly executed by any JVM interpreter or translated into native machine instructions on the fly.
- High Performance: Through the modern Just-In-Time (JIT) compiler, hot bytecode methods are compiled into native machine code during execution for near-C++ speed.
- Multithreaded: Java provides native language-level and library support for concurrent execution through the
Threadclass andsynchronizedkeyword. - Dynamic: Java programs can dynamically load classes, libraries, and new types at runtime across a local disk or over a network.
4. Testing Java Architecture: Java System Properties
Below is a working Java program that inspects your runtime environment and verifies JVM architecture-neutral properties:
public class SystemPropertiesCheck { public static void main(String[] args) { System.out.println("=== Java Runtime Environment Verification ==="); System.out.println("Java Version: " + System.getProperty("java.version")); System.out.println("JVM Name: " + System.getProperty("java.vm.name")); System.out.println("OS Architecture: " + System.getProperty("os.arch")); System.out.println("OS Name: " + System.getProperty("os.name")); System.out.println("File Separator: " + System.getProperty("file.separator")); } }
Compile and run SystemPropertiesCheck.java. Modify the program to query and print java.vendor and user.home. Observe how Java abstracts OS-level differences behind uniform property keys.
Java Program Development & OOP Foundations
1. The Java Program Development Lifecycle
A Java program moves through several well-defined phases from initial source code creation to machine execution:
- Editing: Writing source code in a text file saved with the
.javaextension (e.g.,StudentGrade.java). - Compiling: Invoking the Java compiler (
javac StudentGrade.java). The compiler parses the code and produces an intermediate binary file known as Bytecode (StudentGrade.class). - Loading: When executing (
java StudentGrade), the ClassLoader loads necessary.classfiles into JVM memory. - Bytecode Verification: The Bytecode Verifier scans the bytecode to ensure it adheres to JVM security rules and does not perform illegal operations like stack overflows or type violations.
- Execution: The JVM execution engine executes the bytecode using an interpreter, dynamically converting frequently executed code paths into native CPU machine code using the Just-In-Time (JIT) Compiler.
- JVM (Java Virtual Machine): The abstract computing machine that executes bytecode. It is platform-dependent (different JVMs exist for Windows, Linux, macOS).
- JRE (Java Runtime Environment): Contains the JVM plus core class libraries (
rt.jar) required to run Java programs. - JDK (Java Development Kit): The complete developer software kit containing JRE + development tools (
javac,java,javadoc,jar,jdb).
2. Foundations of Object-Oriented Programming (OOP)
Java is an object-oriented language built around six fundamental concepts:
- Class: A user-defined template or blueprint from which individual objects are created. It encapsulates data fields and method definitions.
- Object: A runtime instance of a class having a distinct state (values of fields), behavior (methods), and identity.
- Abstraction: Hiding internal implementation details and exposing only essential functional interfaces to users.
- Encapsulation: Bundling data and methods operating on that data inside a single unit (class) while restricting direct access using access modifiers (data hiding).
- Inheritance: The mechanism where a child class acquires the properties and methods of an existing parent class, promoting code reuse.
- Polymorphism: The ability of an entity (method, operator, or object) to take multiple forms (Compile-time overloading vs Runtime overriding).
3. Anatomical Breakdown of a Java Program
Let us analyze every single keyword in a canonical Java application:
public class FirstProgram { public static void main(String[] args) { System.out.println("Mastering Java BCA Curriculum"); } }
public: An access specifier that makes the class accessible from anywhere.class: Keyword used to declare a class.FirstProgram: Identifier defining the class name. If declared public, the file must be namedFirstProgram.java.public static void main(String[] args):public: Callable by the JVM from outside the class package.static: Allows the JVM to invoke the method without creating an instance of the class first.void: The entry-point method does not return any value.main: The exact method signature identifier looked up by the JVM execution engine.String[] args: An array ofStringobjects representing command-line arguments.
System.out.println():Systemis a final class injava.lang,outis a staticPrintStreamobject, andprintln()is a method that prints text followed by a newline.
Write a program GreetingApp.java that checks if args.length > 0. If a name is passed via command-line (e.g. java GreetingApp Alice), print Hello, Alice!; otherwise print Hello, Student!.
Elements of Java Program & Java API
1. Elements of a Java Program
Every Java source file is parsed into foundational lexical tokens:
- White Space: Spaces, tabs, and newlines that separate tokens. Java compiler ignores superfluous whitespace.
- Identifiers: User-defined names for classes, methods, variables, and labels.
- Must start with a letter (A-Z, a-z), underscore (
_), or currency symbol ($). - Cannot contain spaces or special symbols like
@,#,%. - Cannot be a reserved Java keyword.
- Java is case-sensitive:
Total,total, andTOTALare distinct identifiers.
- Must start with a letter (A-Z, a-z), underscore (
- Keywords: 50+ reserved words that have predefined meanings to the compiler (e.g.
class,public,static,void,if,else,while,try,catch). - Literals: Constant values assigned directly to variables (e.g.
100,3.14,'A',"Java",true). - Separators: Punctuation marks used to structure code:
- Parentheses
(): Delimit parameter lists and expression precedence. - Braces
{}: Delimit blocks of code, classes, and method bodies. - Brackets
[]: Declare array types and index array elements. - Semicolon
;: Terminates statements. - Comma
,: Separates declarations and arguments. - Period
.: Selects package components or class/object members.
- Parentheses
2. Overview of Java API (Application Programming Interface)
The Java API is a comprehensive collection of pre-written packages and classes included in the standard Java Development Kit. Key foundational packages include:
| Package Name | Core Purpose | Auto-Imported? |
|---|---|---|
java.lang |
Fundamental language classes (String, Math, System, Thread, Object, primitive wrappers) |
Yes (Automatically by default) |
java.util |
Collection framework, date/time, scanner, random numbers, tokenizers | No (Requires import java.util.*;) |
java.io |
Input/Output stream processing for files and byte/character streams | No (Requires import java.io.*;) |
java.net |
Networking operations, sockets, URLs, HTTP connections | No (Requires import java.net.*;) |
java.awt |
Abstract Window Toolkit for GUI rendering and events | No (Requires import java.awt.*;) |
3. Types of Comments in Java
Java supports three distinct styles of comments:
/** * The Calculator class performs arithmetic operations. * <p>This is a <b>Documentation Comment</b> used by the Javadoc utility * to generate standard HTML documentation.</p> * * @author BCA Student * @version 1.0 */ public class CommentsAndJavadocDemo { // 1. Single-line comment: ignores text from // to the end of the line /** * Calculates the sum of two integers. * @param a first operand * @param b second operand * @return sum of a and b */ public static int add(int a, int b) { /* 2. Multi-line comment: Can span across several lines enclosed between forward-slash asterisk and asterisk forward-slash. */ return a + b; } public static void main(String[] args) { int result = add(15, 25); System.out.println("Sum: " + result); } }
Run javadoc CommentsAndJavadocDemo.java in your command prompt. Open the generated index.html in a browser and observe how Java transforms Javadoc comments into official API documentation.
Variables, Literals, Constants & Primitive Data Types
1. Variables and Constants
A variable is a named storage location in memory capable of holding data that can change during program execution. A variable has three attributes: a type, a name (identifier), and a value.
- Declaration:
int studentAge; - Initialization:
studentAge = 20; - Dynamic Initialization: Variables can be initialized dynamically using expressions at runtime:
double hypotenuse = Math.sqrt(a * a + b * b); - Constants: A constant is declared using the
finalmodifier. Once initialized, its value cannot be modified:final double PI = 3.14159265359;
2. The 8 Primitive Data Types in Java
Java is strictly typed. All primitive types have guaranteed, architecture-independent sizes:
| Type | Category | Size (Bits) | Range / Values | Default |
|---|---|---|---|---|
byte | Integer | 8 bits | -128 to 127 | 0 |
short | Integer | 16 bits | -32,768 to 32,767 | 0 |
int | Integer | 32 bits | -2,147,483,648 to 2,147,483,647 | 0 |
long | Integer | 64 bits | -9 quintillion to 9 quintillion (Suffix L) | 0L |
float | Floating-point | 32 bits | ~±3.40282347E+38F (Suffix F) | 0.0f |
double | Floating-point | 64 bits | ~±1.7976931348623157E+308 | 0.0d |
char | Character | 16 bits (Unicode) | '\u0000' (0) to '\uffff' (65,535) | '\u0000' |
boolean | Logical | 1 bit (logical) | true or false | false |
3. Literals in Java
Literals are constant values assigned directly to variables:
- Integer Literals:
- Decimal (base 10):
100 - Hexadecimal (base 16, prefix
0xor0X):0x2A(value 42) - Octal (base 8, prefix
0):012(value 10) - Binary (base 2, prefix
0bor0B, Java 7+):0b1010(value 10)
- Decimal (base 10):
- Floating-point Literals: Default is double. Float requires
Fsuffix:float f = 12.5f;. Scientific notation:1.5e-3. - Character Literals: Enclosed in single quotes:
'A','\n'(newline),'\t'(tab),'\u0041'. - Boolean Literals: Only
trueandfalse(Java does not treat 0 or 1 as boolean).
4. Type Conversion and Casting
Java supports two categories of type conversion:
- Widening (Implicit / Automatic Casting): Occurs automatically when converting a smaller type to a larger compatible type without precision loss:
byte → short → int → long → float → double - Narrowing (Explicit Casting): Required when converting a larger type to a smaller type or when precision loss can occur. Syntax:
(target-type) value.
public class TypeCastingDemo { public static void main(String[] args) { // Widening Conversion (Automatic) int num = 100; double d = num; System.out.println("Widened double value: " + d); // prints 100.0 // Narrowing Conversion (Explicit) double pi = 3.14159; int truncatedPi = (int) pi; System.out.println("Narrowed int value: " + truncatedPi); // prints 3 // Byte overflow demonstration int largeVal = 130; byte b = (byte) largeVal; System.out.println("Byte truncated (130 -> byte): " + b); // prints -126 due to wrap-around } }
Declare variables for a student's roll number (int), grade point average (double), initial (char), and attendance status (boolean). Print all values with descriptive labels.
The String Class & Operators
1. Introduction to the String Class
Unlike C where strings are null-terminated character arrays, in Java a string is an object of the built-in java.lang.String class. Key characteristics include:
- Immutability: Once a
Stringobject is created in memory, its character sequence cannot be altered. Any operation that appears to modify a string actually creates a brand-newStringobject. - String Constant Pool (SCP): To conserve heap memory, the JVM maintains a special pool for string literals. If two variables share the same literal string, both point to the identical memory address in the pool.
public class StringCreationDemo { public static void main(String[] args) { String s1 = "Java"; // Created in String Constant Pool String s2 = "Java"; // Reuses same instance from Pool String s3 = new String("Java"); // Forces new instance in regular Heap System.out.println(s1 == s2); // true (points to identical memory address) System.out.println(s1 == s3); // false (different memory addresses) System.out.println(s1.equals(s3)); // true (compares actual content characters) } }
2. Operators in Java
Java provides a rich set of operators categorized by function:
- Arithmetic Operators:
+(addition or string concatenation),-(subtraction),*(multiplication),/(division),%(modulus/remainder),++(increment),--(decrement). - Relational Operators:
==,!=,>,<,>=,<=(always return a boolean valuetrueorfalse). - Logical Operators: Short-circuit AND (
&&), Short-circuit OR (||), Logical NOT (!). - Bitwise Operators:
&(AND),|(OR),^(XOR),~(Bitwise unary inversion),<<(Signed left shift),>>(Signed right shift),>>>(Unsigned right shift). - Assignment Operators:
=,+=,-=,*=,/=,%=. - Conditional (Ternary) Operator:
variable = (condition) ? value_if_true : value_if_false;
3. Complete Operator Evaluation Example
public class OperatorsCheck { public static void main(String[] args) { int a = 10, b = 20; // Ternary operator int max = (a > b) ? a : b; System.out.println("Max: " + max); // Bitwise shift int val = 8; // binary 00001000 System.out.println("8 << 1 (8 * 2): " + (val << 1)); // prints 16 System.out.println("8 >> 1 (8 / 2): " + (val >> 1)); // prints 4 } }
Write an expression using the conditional ternary operator that takes three integer variables x, y, z and finds the largest of the three in a single line.
Scope of Variables & Blocks
1. Blocks in Java
A block in Java is any group of zero or more statements enclosed within curly braces { ... }. A block can be used wherever a single statement is allowed. Blocks can be nested inside other blocks and define lexical scopes for variables.
2. Scope and Lifetime of Variables
The scope of a variable determines where the variable can be accessed in program source code. The lifetime determines when the variable is allocated memory and when that memory is released:
- Class/Instance Scope (Member Variables): Declared inside a class but outside methods. Instance variables live as long as the containing object exists on the heap.
- Method Scope (Parameters & Local Variables): Declared inside a method. Parameters are initialized with argument values when the method is invoked and destroyed when the method returns.
- Block Scope (Local Block Variables): Declared inside an inner block (such as an
ifstatement orforloop). They are created when the block is entered and destroyed immediately when the closing brace}is reached.
public class ScopeDemo { // Class instance variable (accessible by all non-static methods in this class) int instanceVar = 500; public void demonstrateScope(int methodParam) { // Method local variable int x = 10; if (x == 10) { // Inner block variable int y = 20; System.out.println("x and y: " + x + " " + y); x = y * 2; // Outer variable x is visible inside inner block } // y = 100; // COMPILATION ERROR! y is unknown here because its scope ended above System.out.println("x is now: " + x); } public static void main(String[] args) { ScopeDemo demo = new ScopeDemo(); demo.demonstrateScope(42); } }
Analyze this snippet: Can a variable declared in a for (int i = 0; i < 5; i++) header be accessed after the loop terminates? Test and explain your findings using variable block scope rules.
Decision Making Statements
1. Overview of Decision Making in Java
Decision making statements evaluate boolean conditions and alter the sequential flow of program execution based on whether the condition evaluates to true or false.
2. If, If-Else, Nested If, and Else-If Ladder
- Simple
if: Executes a block of code only if the boolean expression is true. if-else: Provides an alternate execution path when the condition evaluates to false.- Nested
if: Anifstatement nested inside the body of anotheriforelseblock. else-ifLadder: A chain of mutually exclusive conditions evaluated from top to bottom.
3. The Switch Statement
The switch statement tests an expression against a list of constant case values. In Java, switch expressions support: byte, short, char, int, enum types, and String (Java 7+).
public class DecisionStatementsDemo { public static void main(String[] args) { int score = 85; char grade; // 1. Else-If Ladder if (score >= 90) { grade = 'A'; } else if (score >= 80) { grade = 'B'; } else if (score >= 70) { grade = 'C'; } else { grade = 'F'; } System.out.println("Student Grade: " + grade); // 2. Switch Statement with Strings String day = "WEDNESDAY"; switch (day) { case "MONDAY": System.out.println("Start of the academic week."); break; case "WEDNESDAY": case "THURSDAY": System.out.println("Midweek lecture sessions."); break; case "FRIDAY": System.out.println("Lab practical day."); break; default: System.out.println("Weekend!"); break; } } }
break statement at the end of each case block, execution continues into the subsequent case regardless of whether its test value matches. While sometimes used intentionally to group cases, forgetting break is one of the most common beginner errors in Java exams.
Implement a simple calculator program using a switch statement that takes two doubles and an operator character ('+', '-', '*', '/') and handles division by zero safely.
Looping & Jumping Statements
1. Looping Statements in Java
Loops allow repeated execution of a block of code as long as a test condition remains true:
whileLoop (Entry-Controlled): Evaluates the condition before each iteration. If false initially, the body never executes:while (condition) { /* body */ }do-whileLoop (Exit-Controlled): Evaluates the condition after each iteration. Guarantees that the body executes at least once:do { /* body */ } while (condition);forLoop (Count-Controlled): Combines initialization, condition test, and step increment in a compact header:for (init; condition; update) { /* body */ }
2. Jumping Statements: Break and Continue
Jumping statements transfer control to another part of the program immediately:
break: Exits the enclosing loop or switch immediately.continue: Skips the remainder of the current iteration and jumps to the next cycle.- Labeled
break&continue: Java does not have agotostatement. Instead, it provides labeled breaks to exit out of multiple nested loops in a single statement!
public class LoopingAndJumpingDemo { public static void main(String[] args) { // Labeled break demonstration in nested loops System.out.println("=== Searching in Matrix using Labeled Break ==="); int[][] matrix = { {1, 2, 3}, {4, 99, 6}, {7, 8, 9} }; int target = 99; boolean found = false; outerLoop: for (int row = 0; row < matrix.length; row++) { for (int col = 0; col < matrix[row].length; col++) { if (matrix[row][col] == target) { System.out.println("Found " + target + " at row " + row + ", col " + col); found = true; break outerLoop; // Exits both loops directly! } } } } }
Using nested loops, write a program that prints a Floyd's triangle of numbers up to 5 rows.
Classes, Objects & Modifiers
1. Basic Concepts of OOPS: Class and Object
A class is a user-defined template or blueprint that defines the structure and behavior of objects. An object is an actual runtime instance created from that class using the new operator.
2. Modifiers in Java
Modifiers are keywords added to declarations to modify their accessibility or behavioral characteristics:
- Access Modifiers:
public: Accessible anywhere across all packages.protected: Accessible within the same package and by subclasses in other packages.default(no keyword): Package-private; accessible only within the same package.private: Accessible only within the declaring class itself (foundation of encapsulation).
- Non-Access Modifiers:
static(belongs to class, not instances),final(cannot be modified/extended),abstract(requires implementation by subclass).
3. Passing Arguments in Java: Pass-by-Value
- For Primitive Types: An independent copy of the value is passed. Changes made inside the method do not affect the caller's variable.
- For Objects / References: A copy of the reference address is passed. Both caller and method point to the same object on the heap. Mutating the object's fields affects the caller's object, but reassigning the reference variable itself inside the method has no effect on the caller's reference.
public class StudentAccount { // Encapsulated private fields private int studentId; private String studentName; private double gpa; // Constructor public StudentAccount(int id, String name, double gpa) { this.studentId = id; this.studentName = name; this.gpa = gpa; } // Getter and Setter methods public double getGpa() { return gpa; } public void setGpa(double gpa) { if (gpa >= 0.0 && gpa <= 10.0) { this.gpa = gpa; } } public void displayDetails() { System.out.println("ID: " + studentId + " | Name: " + studentName + " | GPA: " + gpa); } public static void main(String[] args) { StudentAccount s1 = new StudentAccount(101, "Gurpreet Singh", 8.7); s1.displayDetails(); s1.setGpa(9.2); s1.displayDetails(); } }
Create an Employee class with encapsulated private fields (empId, empName, basicSalary). Add methods to calculate gross salary with 20% HRA and 10% DA.
Constructors, Static Members & GC
1. Constructors in Java
A constructor is a special member method invoked automatically during object creation to initialize instance variables. It has the exact same name as the enclosing class and does not have any return type (not even void).
- Default Constructor: If a class provides no constructors, the compiler automatically inserts an invisible, no-argument default constructor.
- Parameterized Constructor: Takes parameters to initialize custom values for each object.
- Constructor Overloading: Defining multiple constructors with different parameter signatures in the same class.
- Constructor Chaining with
this(...): Calling one constructor from another constructor within the same class (must be the very first statement in the constructor body).
2. Note on Overloaded Operators in Java
+ for matrix or complex number addition). Java deliberately does NOT support user-defined operator overloading to avoid unnecessary complexity and maintain clean, unambiguous syntax. In Java, only the + operator is internally overloaded by the JVM to concatenate strings.
3. Static Class Members
The static keyword declares members that belong to the class itself rather than to individual object instances:
- Static Variables (Class Variables): Only a single copy exists in memory, shared across all instances of the class.
- Static Methods: Can be invoked directly via class name (e.g.
Math.sqrt()) without instantiating an object. They can only access static members directly. - Static Initialization Block: Executed once when the class is first loaded into memory by the ClassLoader.
4. Garbage Collection
Java features Automatic Garbage Collection. When an object on the heap has no live reference variables pointing to it, it becomes eligible for garbage collection. The JVM's background Garbage Collector automatically reclaims the allocated memory, eliminating memory leaks.
public class StaticAndConstructorDemo { // Static class variable to count active objects private static int objectCount = 0; private int id; // Default constructor chaining to parameterized constructor public StaticAndConstructorDemo() { this(1000 + objectCount); // calls overloaded constructor } // Parameterized constructor public StaticAndConstructorDemo(int customId) { this.id = customId; objectCount++; } public static int getTotalCreated() { return objectCount; } public static void main(String[] args) { StaticAndConstructorDemo obj1 = new StaticAndConstructorDemo(); StaticAndConstructorDemo obj2 = new StaticAndConstructorDemo(5001); System.out.println("Total Objects Created: " + StaticAndConstructorDemo.getTotalCreated()); // Dereference obj1 so it becomes eligible for Garbage Collection obj1 = null; System.gc(); // Request JVM to run garbage collector } }
Write a class BankCustomer with constructors that accept different combinations of parameters (name only, or name + initial deposit). Use this(...) constructor chaining.
Inheritance Basics & Method Overriding
1. Basics of Inheritance
Inheritance is the mechanism by which one class (the subclass or derived class) inherits the fields and methods of another class (the superclass or base class) using the extends keyword. It represents an IS-A relationship and maximizes code reuse.
Java supports:
- Single Inheritance: Class B extends Class A.
- Multilevel Inheritance: Class C extends Class B, and Class B extends Class A.
- Hierarchical Inheritance: Class B and Class C both extend Class A.
class C extends A, B is a compilation error). This avoids the notorious Diamond Problem where duplicate inherited method implementations cause ambiguity. Java solves multiple inheritance cleanly through Interfaces (covered in Unit-III).
2. Inheriting and Overriding Superclass Methods
When a subclass provides its own specific implementation of a method already defined in its superclass, it is called Method Overriding:
- The method in the subclass must have the exact same method signature (name, parameter list, and return type or covariant subtype).
- The access modifier cannot be more restrictive than the superclass method.
- The
@Overrideannotation instructs the compiler to verify overriding validity.
3. The Super Keyword
The super keyword provides a reference to the direct superclass:
super(...): Invokes the constructor of the superclass (must be the first line of the subclass constructor).super.methodName(): Calls the overridden version of a method in the superclass.super.variableName: Accesses a superclass field hidden by a subclass field.
// Superclass class Person { protected String name; protected int age; public Person(String name, int age) { this.name = name; this.age = age; } public void displayInfo() { System.out.println("Name: " + name + ", Age: " + age); } } // Subclass class CollegeStudent extends Person { private String course; private int rollNumber; public CollegeStudent(String name, int age, String course, int roll) { super(name, age); // Calling superclass constructor this.course = course; this.rollNumber = roll; } @Override public void displayInfo() { super.displayInfo(); // Reusing superclass method logic System.out.println("Roll No: " + rollNumber + ", Course: " + course); } } public class InheritanceSuperDemo { public static void main(String[] args) { CollegeStudent st = new CollegeStudent("Aman Deep", 21, "BCA", 108); st.displayInfo(); } }
Create a superclass Vehicle with speed and fuel capacity. Create a derived class Car with seating capacity and air-conditioner status. Override a showDetails() method calling super.showDetails().
Polymorphism, Abstract & Final Classes
1. Polymorphism and Dynamic Method Dispatch
Polymorphism is the ability for a call to behave differently based on the runtime type of the object invoked. Java achieves runtime polymorphism through Dynamic Method Dispatch:
When an overridden method is called through a superclass reference variable, Java resolves which version of the method to execute at runtime based on the actual object being referenced, not the type of the reference variable.
2. Abstract Classes and Methods
An abstract class is a class declared with the abstract modifier:
- It cannot be directly instantiated using
new. - It can contain both abstract methods (methods with no body, ending in a semicolon) and concrete methods (fully implemented methods).
- Any non-abstract subclass extending it must provide concrete implementations for all inherited abstract methods.
3. The Final Keyword
The final keyword enforces immutability and finality across three levels:
- Final Variable: Value cannot be modified after assignment (creates a constant).
- Final Method: Cannot be overridden by any subclass (prevents altering core logic).
- Final Class: Cannot be subclassed or inherited (e.g.
java.lang.String,java.lang.Math).
// Abstract base class abstract class Shape { protected String shapeName; public Shape(String name) { this.shapeName = name; } // Abstract method (must be implemented by concrete subclasses) public abstract double calculateArea(); // Final concrete method (cannot be overridden by subclasses) public final void printShapeType() { System.out.println("Shape Type: " + shapeName); } } class Circle extends Shape { private double radius; public Circle(double r) { super("Circle"); this.radius = r; } @Override public double calculateArea() { return Math.PI * radius * radius; } } class Rectangle extends Shape { private double width, height; public Rectangle(double w, double h) { super("Rectangle"); this.width = w; this.height = h; } @Override public double calculateArea() { return width * height; } } public class PolymorphismAbstractDemo { public static void main(String[] args) { // Dynamic Method Dispatch using superclass reference Shape s1 = new Circle(5.0); Shape s2 = new Rectangle(4.0, 6.0); s1.printShapeType(); System.out.println("Area: " + s1.calculateArea()); s2.printShapeType(); System.out.println("Area: " + s2.calculateArea()); } }
Create an abstract class BankAccount with an abstract method calculateInterest(). Extend it with SavingsAccount (returns 4% interest) and CurrentAccount (returns 0% interest). Demonstrate polymorphism using an array of BankAccount references.
Arrays in Java (1D, 2D & Multidimensional)
1. Introduction to Arrays in Java
An array is a fixed-size, dynamically allocated collection of homogeneous elements stored in contiguous memory locations. In Java, arrays are objects instantiated on the heap.
- Declaration:
int[] numbers;(preferred) orint numbers[]; - Instantiation:
numbers = new int[5];(allocates heap memory, initialized to default zeros) - Direct Initialization:
int[] scores = {95, 88, 72, 90, 85}; - Length Property:
scores.lengthreturns the number of elements (it is a field, not a method).
2. Processing Array Contents & Method Passing
Arrays can be processed sequentially, passed as arguments to methods by reference value, and returned from methods:
public class ArrayOperations { // Passing array as argument public static int findMaximum(int[] arr) { int max = arr[0]; for (int val : arr) { if (val > max) { max = val; } } return max; } // Returning array from method public static int[] reverseArray(int[] arr) { int[] rev = new int[arr.length]; for (int i = 0; i < arr.length; i++) { rev[i] = arr[arr.length - 1 - i]; } return rev; } public static void main(String[] args) { int[] data = {14, 78, 32, 99, 45}; System.out.println("Maximum element: " + findMaximum(data)); } }
3. 2D Arrays, Multidimensional & Jagged Arrays
A two-dimensional array in Java is implemented as an array of arrays. Because of this, rows can have unequal lengths, forming Jagged (or Ragged) arrays:
public class JaggedArrayDemo { public static void main(String[] args) { // Declare 2D array with 3 rows but variable columns int[][] jagged = new int[3][]; jagged[0] = new int[2]; // Row 0 has 2 columns jagged[1] = new int[4]; // Row 1 has 4 columns jagged[2] = new int[3]; // Row 2 has 3 columns System.out.println("Row 0 length: " + jagged[0].length); System.out.println("Row 1 length: " + jagged[1].length); } }
Write a program that multiplies two 3x3 matrices and prints the resulting product matrix.
Strings, StringBuffer & StringTokenizer
1. The String Class Operations
Java's String class provides an extensive suite of built-in methods for textual manipulation:
length(): Returns count of UTF-16 code units.charAt(int index): Returns character at specified zero-based index.substring(int begin, int end): Extracts substring from index begin to (end - 1).concat(String str): Appends str to the current string.equals()vsequalsIgnoreCase(): Compares character contents.compareTo(String anotherString): Performs lexicographical comparison.
2. Difference Between String, StringBuffer & StringBuilder
| Feature | String |
StringBuffer |
StringBuilder |
|---|---|---|---|
| Mutability | Immutable (cannot modify in place) | Mutable (modifies in place) | Mutable (modifies in place) |
| Thread Safety | Thread-safe (due to immutability) | Thread-safe (Synchronized methods) | Not thread-safe (Unsynchronized) |
| Performance | Slow during repeated concatenation | Moderate (overhead of locks) | Fastest (ideal for single thread) |
3. The StringTokenizer Class
Found in java.util, StringTokenizer breaks a string into individual tokens separated by delimiters (default delimiter is whitespace):
import java.util.StringTokenizer; public class StringTokenizerDemo { public static void main(String[] args) { // 1. StringBuffer Demonstration StringBuffer sb = new StringBuffer("BCA"); sb.append(" Punjab Technical University"); sb.reverse(); System.out.println("Reversed StringBuffer: " + sb); // 2. StringTokenizer Demonstration with CSV string String csvData = "RollNo:101,Name:Karanveer,City:Jalandhar,Marks:94"; StringTokenizer st = new StringTokenizer(csvData, ","); System.out.println("Tokens count: " + st.countTokens()); while (st.hasMoreTokens()) { System.out.println("Token: " + st.nextToken()); } } }
Write a program that takes an English sentence and uses StringTokenizer to count how many words it contains, and prints each word in reverse order using StringBuffer.
Interfaces & Multiple Inheritance
1. Basics of Interface in Java
An Interface is a reference type in Java that serves as a 100% formal contract for classes. It is declared with the interface keyword:
- All methods declared inside an interface are implicitly
public abstract(unless declareddefaultorstaticin Java 8+). - All fields declared in an interface are implicitly
public static final(constants). - A class implements an interface using the
implementskeyword and must provide concrete definitions for all methods.
2. Multiple Inheritance Using Interfaces
While Java prohibits multiple class inheritance, a class can implement multiple interfaces simultaneously (e.g. class C implements InterfaceA, InterfaceB). Because interfaces contain method specifications rather than conflicting instance field states, Java completely eliminates the Diamond Problem.
3. Multilevel Interface Inheritance
An interface can extend another interface using extends. An interface can even extend multiple super-interfaces simultaneously:
interface Printable { void print(); }
interface Showable extends Printable { void show(); }
// Interface 1 interface DatabaseEntity { void saveToDatabase(); } // Interface 2 interface Loggable { void logOperation(String msg); } // Class implementing multiple interfaces public class MultipleInterfaceDemo implements DatabaseEntity, Loggable { @Override public void saveToDatabase() { System.out.println("Saving student record to MySQL database..."); } @Override public void logOperation(String msg) { System.out.println("[AUDIT LOG]: " + msg); } public static void main(String[] args) { MultipleInterfaceDemo demo = new MultipleInterfaceDemo(); demo.logOperation("System boot complete."); demo.saveToDatabase(); } }
Define two interfaces: Printable (with print()) and Exportable (with exportToPdf()). Create a class ReportDocument that implements both interfaces.
Packages, Access Specifiers & Static Import
1. What is a Package?
A package is a grouping mechanism in Java that bundles related classes, interfaces, and sub-packages together. Packages prevent naming collisions and enforce access protection.
- Declaring a Package: Must be the first statement in the Java file:
package com.ptu.bca; - Compiling with Package Hierarchy:
javac -d . Student.java(the-d .flag directs javac to automatically create the folder directory hierarchy matching package names). - Importing Packages:
import com.ptu.bca.Student;orimport com.ptu.bca.*;
2. Static Import
Introduced in Java 5, static import allows members defined in a class as static to be used in another class without specifying the class name prefix:
import static java.lang.Math.PI; import static java.lang.Math.sqrt; import static java.lang.Math.pow; public class StaticImportDemo { public static void main(String[] args) { // Direct access without prefixing Math. double area = PI * pow(5.0, 2); double diagonal = sqrt(25.0); System.out.println("Circle Area: " + area); System.out.println("Square Root: " + diagonal); } }
3. The Comprehensive Access Specifiers Matrix
Java provides four levels of visibility:
| Access Specifier | Same Class | Same Package (Subclass / Non-subclass) | Different Package (Subclass) | Different Package (World) |
|---|---|---|---|---|
public |
Yes | Yes | Yes | Yes |
protected |
Yes | Yes | Yes (via inheritance) | No |
default (package-private) |
Yes | Yes | No | No |
private |
Yes | No | No | No |
Create a package university.department with a class Faculty containing protected double salary. In another package university.staff, create a subclass Professor that accesses salary through inheritance.
Exception Handling — Try, Catch & Throw
1. Introduction to Exception Handling
An exception is an abnormal event or error condition that occurs during program execution and disrupts the normal flow of instructions. Java represents exceptions as objects inheriting from the java.lang.Throwable hierarchy:
Error: Serious system conditions that normal applications should not attempt to catch (e.g.,OutOfMemoryError,StackOverflowError).Exception:- Checked Exceptions: Subclasses of
Exception(excludingRuntimeException). Checked at compile-time. The compiler insists that the programmer handle them usingtry-catchor declare them withthrows(e.g.IOException,SQLException). - Unchecked Exceptions: Subclasses of
RuntimeException. Checked at runtime. Usually result from programming logic flaws (e.g.NullPointerException,ArithmeticException,ArrayIndexOutOfBoundsException).
- Checked Exceptions: Subclasses of
2. Try, Catch, Multiple Catch & Nested Try
tryBlock: Encloses code that might throw an exception.catchBlock: Handles the specific exception if thrown inside the associatedtryblock.- Multiple Catch: A single
tryblock can be followed by multiplecatchblocks. Rule: Catch handlers must be arranged from most specific (subclass) to most generic (superclass). - Nested Try: A
tryblock placed inside anothertryblock. If an innertrylacks a matching catch handler, the exception bubbles up to the outertry-catch.
3. The Throw Statement
The throw keyword explicitly throws an exception instance in code:
public class ExceptionDemo { public static void validateStudentAge(int age) { if (age < 18) { // Explicitly throw an unchecked exception throw new IllegalArgumentException("Student must be at least 18 years old for admission."); } System.out.println("Admission eligibility verified for age " + age); } public static void main(String[] args) { try { // Nested try block try { int result = 50 / 0; } catch (ArithmeticException e) { System.out.println("[Inner Catch] Caught division by zero: " + e.getMessage()); } validateStudentAge(16); // throws exception } catch (IllegalArgumentException e) { System.out.println("[Outer Catch] Caught validation error: " + e.getMessage()); } catch (Exception e) { System.out.println("[Outer Generic Catch]: " + e.getMessage()); } } }
Write a program with an array of 5 integers. Read an index from the user. Use multiple catch blocks to catch both ArrayIndexOutOfBoundsException and NumberFormatException.
Finally Block & Built-In Exceptions
1. The Finally Block
The finally block creates a block of code that is guaranteed to execute, regardless of whether an exception was thrown or caught inside the try block. It is primarily used for releasing external system resources (closing file streams, database connections, socket handles).
finally block executes even if the try block contains a return statement! The only scenario where finally does not execute is if System.exit(0) is invoked, or in the catastrophic event of a fatal JVM crash / power loss.
2. Common Built-In Exceptions in Java
| Exception Class | Type | Trigger Condition |
|---|---|---|
ArithmeticException |
Unchecked | Arithmetic errors, such as integer division by zero |
ArrayIndexOutOfBoundsException |
Unchecked | Accessing an array with an illegal negative or ≥ length index |
NullPointerException |
Unchecked | Attempting to invoke a method or access a field on a null reference |
NumberFormatException |
Unchecked | Failed conversion of a string to numeric format via Integer.parseInt() |
ClassNotFoundException |
Checked | ClassLoader cannot locate the specified .class file |
IOException |
Checked | Failure during input/output stream operations (disk failure, file missing) |
3. Creating Custom / User-Defined Exceptions
A programmer can create domain-specific exceptions by extending java.lang.Exception:
// Custom Checked Exception class InsufficientBalanceException extends Exception { public InsufficientBalanceException(String message) { super(message); } } public class CustomExceptionDemo { private static double balance = 5000.00; public static void withdraw(double amount) throws InsufficientBalanceException { System.out.println("Attempting withdrawal of: Rs " + amount); if (amount > balance) { throw new InsufficientBalanceException("Deficit balance! Available: Rs " + balance); } balance -= amount; System.out.println("Withdrawal successful. Remaining: Rs " + balance); } public static void main(String[] args) { try { withdraw(6000.00); } catch (InsufficientBalanceException e) { System.err.println("Transaction Failed: " + e.getMessage()); } finally { System.out.println("[Finally] Session logging closed. Receipt printed."); } } }
Create a custom checked exception InvalidAgeForVotingException. Write a method that checks a voter's age and throws this exception if age is less than 18. Demonstrate handling with a finally block.
Multithreading — Creation & Lifecycle
1. Introduction to Multithreading
Multitasking is the ability of an operating system to execute more than one task concurrently. Java supports two forms of multitasking:
- Process-based Multitasking (Multiprocessing): Running multiple independent programs simultaneously (e.g., running Java compiler and a web browser at the same time). Processes have separate memory spaces.
- Thread-based Multitasking (Multithreading): Running multiple sub-tasks (threads) concurrently within the same application program. Threads share the same address space, resulting in minimal context-switching overhead and maximum CPU core utilization.
2. Thread Creation in Java
Java provides two primary approaches for creating threads:
Approach A: Extending the Thread Class
class MyThread extends Thread {
@Override
public void run() {
System.out.println("Child thread running via Thread class extension.");
}
}
Approach B: Implementing the Runnable Interface (Recommended)
Because Java does not permit multiple class inheritance, implementing Runnable is preferred because your class remains free to inherit from another parent class:
// Implementing Runnable interface class BackgroundWorker implements Runnable { private String taskName; public BackgroundWorker(String name) { this.taskName = name; } @Override public void run() { for (int i = 1; i <= 3; i++) { System.out.println(taskName + " executing step " + i); try { Thread.sleep(500); // Pause thread for 500 milliseconds } catch (InterruptedException e) { System.err.println(taskName + " interrupted."); } } } } public class ThreadCreationDemo { public static void main(String[] args) { // Instantiate Runnable workers Thread t1 = new Thread(new BackgroundWorker("Download-Worker")); Thread t2 = new Thread(new BackgroundWorker("Audio-Worker")); // start() triggers JVM to allocate thread stack and call run() t1.start(); t2.start(); } }
3. The Lifecycle of a Thread (Thread States)
A Java thread transitions through distinct states during its lifespan:
- New: A thread has been instantiated (
new Thread()), butstart()has not yet been invoked. - Runnable: After
start()is called, the thread is eligible for CPU execution and waits in the ready queue. - Running: The thread scheduler selects the thread from the queue and executes its
run()method on a CPU core. - Blocked / Waiting / Timed-Waiting: Temporarily inactive because it is waiting for a monitor lock, sleeping (
sleep()), or waiting on another thread (join(),wait()). - Terminated (Dead): The thread's
run()method has completed execution.
Write a program with two threads: one thread prints even numbers from 2 to 20, and the other thread prints odd numbers from 1 to 19 concurrently.
Thread Management & Synchronization
1. Joining a Thread
The join() method allows one thread to pause execution and wait until another target thread has completed its execution. This guarantees deterministic ordering of interdependent background tasks.
2. Thread Scheduler & Priorities
The Thread Scheduler in the JVM determines which runnable thread gets CPU execution time. Every Java thread has a priority represented by an integer from 1 to 10:
Thread.MIN_PRIORITY = 1Thread.NORM_PRIORITY = 5(default)Thread.MAX_PRIORITY = 10- Method:
t.setPriority(int priority);
3. Thread Synchronization: Preventing Race Conditions
When multiple threads attempt to access and modify the same shared mutable resource concurrently, data corruption occurs (known as a Race Condition). Java solves this using the synchronized keyword, which acquires an exclusive mutual-exclusion monitor lock on an object:
- Synchronized Method:
public synchronized void deposit(double amount) { ... } - Synchronized Block:
synchronized(sharedResource) { /* critical section */ }
// Shared account resource class JointAccount { private int balance = 1000; // Synchronized method prevents race condition between threads public synchronized void withdraw(String user, int amount) { if (balance >= amount) { System.out.println(user + " is preparing to withdraw " + amount); try { Thread.sleep(100); // Simulate network latency } catch (InterruptedException e) {} balance -= amount; System.out.println(user + " completed withdrawal. New Balance: " + balance); } else { System.out.println("Insufficient funds for " + user); } } } public class BankSynchronizationDemo { public static void main(String[] args) throws InterruptedException { JointAccount account = new JointAccount(); Thread t1 = new Thread(() -> account.withdraw("Simran", 700)); Thread t2 = new Thread(() -> account.withdraw("Rahul", 700)); t1.start(); t2.start(); // Wait for both threads to finish t1.join(); t2.join(); System.out.println("All transactions processed cleanly."); } }
Explain the role of wait(), notify(), and notifyAll() in inter-thread communication. Write a producer-consumer buffer example where the producer waits when the buffer is full and notifies the consumer.
Applets & Applet Life Cycle
1. Introduction to Applets
An Applet is a special type of Java program designed to be embedded within an HTML webpage and executed inside a Java-enabled web browser or via the appletviewer utility. Applets were foundational in establishing Java's early popularity on the World Wide Web.
- Standalone Applications: Have a
main()method, are started directly by the JVM, and possess unrestricted access to local system resources (file systems, network ports). - Applets: Do not have a
main()method. Execution is controlled by browser life-cycle callbacks. For security, Applets run inside a restricted Sandbox and cannot read/write arbitrary local files or execute native programs without signed permissions.
2. The Applet Class Hierarchy
The standard Applet class belongs to the package java.applet.Applet. Its inheritance chain is:
java.lang.Object
→ java.awt.Component
→ java.awt.Container
→ java.awt.Panel
→ java.applet.Applet
3. The Applet Life Cycle Methods
The JVM / Applet container manages an applet through five lifecycle methods:
public void init(): Invoked only once when the applet is first loaded into memory. Used for one-time initialization (creating GUI components, loading images, reading parameters).public void start(): Invoked afterinit(), and every time the user navigates back to the webpage. Starts or resumes execution threads.public void paint(Graphics g): Invoked automatically whenever the applet's display surface must be redrawn (e.g. after minimizing/restoring window). Used for rendering graphics, text, and geometric shapes.public void stop(): Invoked whenever the user navigates away from the webpage. Suspends active background animations or threads.public void destroy(): Invoked once before the applet is completely unloaded from memory. Cleans up non-memory system resources.
4. Embedding an Applet in HTML
import java.applet.Applet; import java.awt.Graphics; import java.awt.Color; /* <applet code="WelcomeApplet.class" width="400" height="200"> <param name="university" value="I.K. Gujral PTU"> </applet> */ public class WelcomeApplet extends Applet { private String universityName; @Override public void init() { setBackground(Color.LIGHT_GRAY); universityName = getParameter("university"); if (universityName == null) { universityName = "Punjab Technical University"; } System.out.println("Applet initialized via init()."); } @Override public void paint(Graphics g) { g.setColor(Color.BLUE); g.drawString("Welcome to BCA Java Programming!", 50, 80); g.setColor(Color.DARK_GRAY); g.drawString("Institution: " + universityName, 50, 120); } }
List the order of execution of applet lifecycle methods when an applet is loaded, minimized, restored, and closed. Run appletviewer WelcomeApplet.java to test the applet.
Graphics in Applets & Event Handling
1. The Graphics Class in Applets
Rendering in Applets is driven by the java.awt.Graphics class. The coordinate system places (0,0) at the top-left corner of the applet panel, with x increasing horizontally to the right and y increasing vertically downwards.
Common graphics drawing methods:
drawLine(int x1, int y1, int x2, int y2)drawRect(int x, int y, int width, int height)andfillRect(...)drawOval(int x, int y, int width, int height)andfillOval(...)drawRoundRect(x, y, w, h, arcWidth, arcHeight)drawString(String str, int x, int y)setColor(Color c)andsetFont(Font f)
2. The Delegation Event Model
Java's GUI event handling follows the Delegation Event Model, which consists of three key components:
- Event Source: A GUI component that generates an event when interacted with (e.g.
Button,TextField,Appletwindow). - Event Object: Encapsulates details about what occurred (e.g.
ActionEvent,MouseEvent,KeyEvent). - Event Listener: An interface defining callback methods that handle the event (e.g.
ActionListener,MouseListener). The listener is registered with the source usingsource.addActionListener(listener).
import java.applet.Applet; import java.awt.*; import java.awt.event.*; /* <applet code="InteractiveAppletDemo.class" width="400" height="300"> </applet> */ public class InteractiveAppletDemo extends Applet implements ActionListener { private Button redBtn, blueBtn; private Color currentColor = Color.WHITE; @Override public void init() { redBtn = new Button("Red Canvas"); blueBtn = new Button("Blue Canvas"); // Register this class as event listener redBtn.addActionListener(this); blueBtn.addActionListener(this); add(redBtn); add(blueBtn); } @Override public void actionPerformed(ActionEvent e) { if (e.getSource() == redBtn) { currentColor = Color.RED; } else if (e.getSource() == blueBtn) { currentColor = Color.BLUE; } repaint(); // Requests JVM to invoke paint() } @Override public void paint(Graphics g) { g.setColor(currentColor); g.fillOval(100, 80, 200, 150); g.setColor(Color.BLACK); g.drawString("Click buttons to change oval color", 80, 260); } }
Implement a MouseMotionListener in an Applet that draws coordinates (x, y) wherever the user moves the mouse cursor on the canvas.
File Class, Streams & Byte Streams
1. The Concept of Streams in Java
A Stream in Java I/O represents a continuous, ordered sequence of data flowing from a source (producer) to a destination (consumer). Java streams are unidirectional:
- Input Stream: Reads data from a source (file, memory buffer, socket).
- Output Stream: Writes data to a destination.
2. The File Class
The java.io.File class represents file and directory pathnames. It does not read or write data directly, but inspects and manipulates file metadata:
exists(): Checks if file/directory exists.isFile()/isDirectory(): Determines file type.length(): Returns file size in bytes.createNewFile(): Creates empty file on disk.delete(): Deletes file/directory.list(): Lists files in a directory as a string array.
3. Byte Streams (8-Bit Streams)
Byte Streams read and write binary data 8 bits at a time. The root abstract classes are InputStream and OutputStream.
Key Byte Stream Classes:
FileInputStream/FileOutputStream: Direct byte read/write from disk files.- Filtered Byte Streams: Wrappers that add functionality to raw streams:
BufferedInputStream/BufferedOutputStream: Buffers data in memory for high-speed I/O.DataInputStream/DataOutputStream: Reads and writes primitive Java data types (readInt(),writeDouble()) in binary format.
import java.io.*; public class ByteStreamCopyDemo { public static void copyFileBinary(File src, File dest) throws IOException { // Using try-with-resources for automatic stream closure try (BufferedInputStream in = new BufferedInputStream(new FileInputStream(src)); BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(dest))) { byte[] buffer = new byte[1024]; int bytesRead; while ((bytesRead = in.read(buffer)) != -1) { out.write(buffer, 0, bytesRead); } System.out.println("File copied successfully: " + dest.getName()); } } public static void main(String[] args) { File sourceFile = new File("sample.dat"); File destFile = new File("sample_copy.dat"); try { copyFileBinary(sourceFile, destFile); } catch (IOException e) { System.out.println("I/O Exception handled: " + e.getMessage()); } } }
Write a program that uses DataOutputStream to write five student roll numbers and percentages into a file students.bin, and reads them back with DataInputStream.
Character Streams & Random Access Files
1. Character Streams (16-Bit Unicode Streams)
While Byte Streams operate on 8-bit bytes, Character Streams are specifically designed to handle 16-bit Unicode characters. This ensures seamless internationalization and character-set encoding translation (e.g. UTF-8). The root abstract classes are Reader and Writer.
Key Character Stream Classes:
FileReader/FileWriter: Direct character reading/writing for text files.BufferedReader: Buffers characters and provides the indispensablereadLine()method.BufferedWriter: Buffers output and providesnewLine()for platform-independent line breaks.PrintWriter: Provides convenient formatted printing (print(),println(),printf()).
2. Random Access File Class
Normal stream classes can only access files sequentially from start to finish. The java.io.RandomAccessFile class permits reading and writing anywhere inside a file at arbitrary offsets (non-sequential access).
- Modes:
"r"(read-only),"rw"(read and write). - File Pointer: A cursor that tracks the current byte position in the file.
seek(long position): Moves the file pointer to the specified byte offset.getFilePointer(): Returns current byte offset.
import java.io.*; public class CharacterAndRandomAccessDemo { public static void main(String[] args) { File file = new File("bca_records.txt"); // 1. Write text using PrintWriter & FileWriter try (PrintWriter pw = new PrintWriter(new BufferedWriter(new FileWriter(file)))) { pw.println("BCA-101: Aman Kumar"); pw.println("BCA-102: Priya Sharma"); pw.println("BCA-103: Rajat Verma"); System.out.println("Records written via PrintWriter."); } catch (IOException e) { e.printStackTrace(); } // 2. Read with BufferedReader line by line try (BufferedReader br = new BufferedReader(new FileReader(file))) { String line; System.out.println("=== Reading Student Records ==="); while ((line = br.readLine()) != null) { System.out.println(line); } } catch (IOException e) { e.printStackTrace(); } // 3. RandomAccessFile Demonstration try (RandomAccessFile raf = new RandomAccessFile(file, "rw")) { raf.seek(9); // Jump to character position 9 System.out.println("Byte pointer at: " + raf.getFilePointer()); raf.writeBytes("Deepak"); // Overwrite characters in place System.out.println("Record updated in place via RandomAccessFile seek."); } catch (IOException e) { e.printStackTrace(); } } }
Write a program that uses BufferedReader to read a Java source file and prints each line with its line number prefixed (e.g. 1: public class ...).