B. Tech. Third Semester (Information Technology), Rashtrasant Tukadoji Maharaj University, Nagpur
Subject Code: BIT3T10
Syllabus
UNIT 1: Object Oriented Programming Fundamentals Object Oriented Programming features: Object Oriented Programming features: objects and classes, Abstraction, Encapsulation, Inheritance, Polymorphism, Characteristics of Java, Java Source File Structure – Compilation. Fundamental Programming Structures in Java, features of Java, Introduction of JDK, JRE and JVM, Operators and Data Types.
UNIT 2: Control Statements, String Handling & Arrays Control Statements: Selection statement, Looping/Iterative statements, Jump/ Transfer statements. Arrays: Declaration and initialization of an array, One Dimensional Array, Two-Dimensional Array. String Handling: String constructors, toString methods, Methods for String Comparison, Searching String and Modifying String. Command line arguments, static modifier, this keyword, Garbage collection, Method overloading.
UNIT 3: Inheritance and Package Inheritance: Inheritance fundamentals, Types of inheritance, Advantages and disadvantages of inheritance. Use of abstract modifiers, Method Overriding, super keyword, final modifier Packages: Package Fundamental, Types of Packages, importing packages.
UNIT 4: Interface and Exception Handling Interface: Concept of interface, advantages of interface, relationship between classes and interface, Exception Handling: Fundamental Exception type: Checked, Unchecked Exceptions, throw and throws keywords, creating user defined exceptions, Built-in Exceptions.
UNIT 5: Multithreading and Collection Fundamentals Threads and Multithreading: Fundamentals, Thread Life Cycle, Ways of creating threads, Thread priorities, Interthread Communication. Collection Framework: Difference between Array and Collection, List interface and its classes, Set interface and its classes, Map interface and its classes.
UNIT 1 – Object-Oriented Programming Fundamentals
Welcome to the foundational unit of Object-Oriented Programming (OOP) with Java. This unit introduces the core concepts of OOP and the basic building blocks of the Java programming language.
1. Object-Oriented Programming (OOP) Features
Object-Oriented Programming is a programming paradigm based on the concept of “objects,” which can contain data in the form of fields1 (often known as attributes or properties) and code in the form of procedures (often known2 as methods).
Objects and Classes
- Class: A class is a blueprint or template for creating objects. It defines a set of attributes and methods that the3 objects of that class will have. For example, a Car class could define properties like color and brand, and methods like startEngine() and accelerate().
- Object: An object is an instance of a class. It is a real-world entity that has a state and behavior. If Car is the class, then a specific red Toyota Corolla is an object of that class.
Example Code:
// A simple class definition for a Car
class Car {
// Fields (attributes)
String color;
String brand;
// Methods (behaviors)
void startEngine() {
System.out.println("The " + brand + " engine has started.");
}
void accelerate() {
System.out.println("The " + color + " car is accelerating.");
}
}
// A class to create and use Car objects
public class Garage {
public static void main(String[] args) {
// Create an object (instance) of the Car class
Car myCar = new Car();
myCar.brand = "Toyota";
myCar.color = "Red";
// Call methods on the object
myCar.startEngine(); // Output: The Toyota engine has started.
myCar.accelerate(); // Output: The Red car is accelerating.
}
}
Abstraction
Abstraction means hiding complex implementation details and showing only the essential features of the object. It helps in managing complexity. For instance, you know how to drive a car without needing to know the inner workings of the combustion engine.
Encapsulation
Encapsulation is the bundling of data (attributes) and the methods that operate on that data into a single unit,4 i.e., a class. It also involves restricting direct access to some of an object’s components, which is a key principle for data protection. This is typically achieved using private access modifiers.
Example Code:
class Student {
// Private fields - cannot be accessed directly from outside the class
private String name;
private int age;
// Public getter method for name
public String getName() {
return name;
}
// Public setter method for name
public void setName(String name) {
this.name = name;
}
// Public getter for age
public int getAge() {
return age;
}
// Public setter for age with validation
public void setAge(int age) {
if (age > 0) { // Simple validation
this.age = age;
}
}
}
public class School {
public static void main(String[] args) {
Student s1 = new Student();
s1.setName("Alice");
s1.setAge(21);
System.out.println("Student Name: " + s1.getName());
System.out.println("Student Age: " + s1.getAge());
}
}
Inheritance
Inheritance is a mechanism where a new class (subclass or child class) derives attributes and methods from an existing class (superclass or parent class). This promotes code reusability. The extends keyword is used to achieve inheritance in Java.
Example Code:
// Superclass (Parent)
class Vehicle {
String brand;
void honk() {
System.out.println("Honk, Honk!");
}
}
// Subclass (Child) - inherits from Vehicle
class Motorcycle extends Vehicle {
String model;
void display() {
System.out.println("Brand: " + brand + ", Model: " + model);
}
}
public class Main {
public static void main(String[] args) {
Motorcycle myMotorcycle = new Motorcycle();
myMotorcycle.brand = "Yamaha"; // Inherited from Vehicle
myMotorcycle.model = "R15";
myMotorcycle.honk(); // Inherited method
myMotorcycle.display();
}
}
Polymorphism
Polymorphism (from Greek, meaning “many forms”) is the ability of an object to take on many forms. In Java, it often refers to method overriding (runtime polymorphism), where a subclass provides a specific implementation of a method that is already provided by its superclass.5
Example Code:
// Superclass
class Animal {
public void makeSound() {
System.out.println("Some generic animal sound");
}
}
// Subclass 1
class Dog extends Animal {
@Override // Annotation indicating method override
public void makeSound() {
System.out.println("Woof Woof");
}
}
// Subclass 2
class Cat extends Animal {
@Override
public void makeSound() {
System.out.println("Meow");
}
}
public class Farm {
public static void main(String[] args) {
Animal myDog = new Dog(); // A Dog object is treated as an Animal
Animal myCat = new Cat(); // A Cat object is treated as an Animal
myDog.makeSound(); // Calls the Dog's version of makeSound() -> Woof Woof
myCat.makeSound(); // Calls the Cat's version of makeSound() -> Meow
}
}
2. Java Fundamentals
Characteristics of Java
- Platform Independent: Java’s “Write Once, Run Anywhere” (WORA) philosophy is possible due to the Java Virtual Machine (JVM). Java code is compiled into platform-independent bytecode that can run on any machine with a JVM.
- Object-Oriented: As we’ve seen, Java is fundamentally an object-oriented language.
- Simple: Java was designed to be easy to learn, with a syntax similar to C++ but simplified to remove complex features like pointers and multiple inheritance.
- Robust: Java has features like automatic memory management (garbage collection) and exception handling, which make it a reliable language.
- Secure: Java’s security features are built into the language and the runtime system, including a bytecode verifier and a security manager.
Java Source File Structure and Compilation
A Java source file (with a .java extension) has the following structure:
- Package Declaration (Optional): package com.example;
- Import Statements (Optional): import java.util.List;
- Class Definition: public class MyClass { … }
Compilation Process:
- You write your code in a .java file (e.g., MyClass.java).
- You use the Java compiler (javac) to compile the source file: javac MyClass.java.
- If there are no errors, the compiler produces a .class file (e.g., MyClass.class). This file contains bytecode, which is the machine language for the JVM.
- You can then run the program using the java command, which starts the JVM: java MyClass.
Introduction to JDK, JRE, and JVM
These three components are crucial to the Java ecosystem.
- JVM (Java Virtual Machine): The JVM is an abstract machine. It’s a specification that provides a runtime environment in which Java bytecode can be executed. It is what makes Java platform-independent.
- JRE (Java Runtime Environment): The JRE is the software package that contains what is required to run a Java program. It includes the JVM, core classes, and supporting files. If you only want to run Java applications, you only need the JRE.
- JDK (Java Development Kit): The JDK is a software development kit used to develop Java applications. It includes the JRE, a compiler (javac), a debugger, and other development tools. You need the JDK to write and compile Java code.
In short: JDK = JRE + Development Tools, and JRE = JVM + Core Libraries.
3. Fundamental Programming Structures in Java
Data Types
Java has two categories of data types:
1. Primitive Data Types: These are the most basic data types. There are eight of them:
- byte: 8-bit integer.
- short: 16-bit integer.
- int: 32-bit integer (most commonly used for integer values).
- long: 64-bit integer.
- float: 32-bit floating-point number.
- double: 64-bit floating-point number (most commonly used for decimal values).
- char: 16-bit Unicode character.
- boolean: Represents two values: true or false.
2. Reference/Object Data Types: These refer to objects.
- Classes, Interfaces, Arrays, and Strings are reference data types. They are created using defined classes or arrays.
Operators
Operators are special symbols that perform specific operations on one, two, or three operands, and then return a6 result.
- Arithmetic: + (addition), – (subtraction), * (multiplication), / (division), % (modulus/remainder).
- Assignment: = (assignment), +=, -=, *=, /=.
- Relational: == (equal to), != (not equal to), > (greater than), < (less than), >= (greater than or equal to), <= (less than or equal to).
- Logical: && (logical AND), || (logical OR), ! (logical NOT).
Unary: + (unary plus), – (unary minus), ++ (increment), — (decrement).
Example Code:
public class DataTypesAndOperators {
public static void main(String[] args) {
// --- Data Types ---
int age = 25;
double salary = 65000.50;
char initial = 'J';
boolean isEmployed = true;
String name = "John Doe"; // String is a reference type
System.out.println("Name: " + name);
System.out.println("Age: " + age);
// --- Operators ---
int a = 10;
int b = 3;
// Arithmetic
System.out.println("a + b = " + (a + b)); // 13
System.out.println("a % b = " + (a % b)); // 1 (remainder of 10/3)
// Relational
System.out.println("Is a > b? " + (a > b)); // true
// Logical
boolean condition1 = true;
boolean condition2 = false;
System.out.println("condition1 && condition2: " + (condition1 && condition2)); // false
// Increment
a++; // a is now 11
System.out.println("New value of a: " + a);
}
}
Sources:
- https://github.com/ShreyanshJoshi/CS-F213—OOP
- https://leportella.com/scala-iii/
- https://github.com/Hira990/Hira990
- https://www.scribd.com/document/794483636/kasi-puneeth-ram-report-6
- https://androiddevhub.com/java-encapsulation/
- https://www.simplilearn.com/tutorials/java-tutorial/java-encapsulation
- https://bscit.great-site.net/core-java/assignment-2-6/
- http://www.studiestoday.com/concept-informatics-practices-cbse-class-xi-informatics-practices-introduction-programming-concepts
UNIT 2 – Control Statements, String Handling & Arrays
This unit explores the fundamental structures that control the flow of execution in a Java program, how to manage collections of data using arrays, and how to work with text using Java’s String class.
1. Control Statements 📝
Control statements are the backbone of any program, allowing you to dictate the execution path based on certain conditions or to repeat a block of code.
Selection Statements
These statements select or ignore a block of code based on a condition.
- if, if-else, if-else-if: The if statement executes a block of code if a condition is true. The if-else statement executes one block if the condition is true and another1 if it’s false. The if-else-if ladder allows for checking multiple conditions.
Example Code:public class GradeChecker {
public static void main(String[] args) {
int score = 75;
char grade;
if (score >= 90) {
grade = 'A';
} else if (score >= 80) {
grade = 'B';
} else if (score >= 70) {
grade = 'C';
} else {
grade = 'D';
}
System.out.println("Your grade is: " + grade); // Output: Your grade is: C
}
} - switch: The switch statement provides a clean way to handle multi-way branching based on the value of a variable (byte, short, char, int, String, enum).
Example Code:public class DayOfWeek {
public static void main(String[] args) {
int day = 4;
String dayString;
switch (day) {
case 1: dayString = "Monday"; break;
case 2: dayString = "Tuesday"; break;
case 3: dayString = "Wednesday"; break;
case 4: dayString = "Thursday"; break;
// ... other cases
default: dayString = "Invalid day"; break;
}
System.out.println(dayString); // Output: Thursday
}
}
Looping / Iterative Statements
Loops are used to execute a block of code repeatedly.
- for loop: Ideal when you know the number of iterations in advance.
- while loop: Used when a loop needs to continue as long as a condition is true. The condition is checked before the loop body is executed.
- do-while loop: Similar to a while loop, but the condition is checked after the loop body. This guarantees the loop body is executed at least once.
Example Code:
public class LoopExamples {
public static void main(String[] args) {
// for loop: Print numbers 1 to 5
System.out.println("For Loop:");
for (int i = 1; i <= 5; i++) {
System.out.print(i + " ");
}
System.out.println(); // Newline
// while loop:
System.out.println("While Loop:");
int count = 1;
while (count <= 5) {
System.out.print(count + " ");
count++;
}
}
}
Jump / Transfer Statements
These statements transfer control to another part of the program.
- break: Terminates the loop or switch statement immediately.
- continue: Skips the current iteration of a loop and proceeds to the next one.
- return: Exits from the current method and returns control to the caller.
Example Code:
public class JumpStatements {
public static void main(String[] args) {
System.out.println("Using break and continue:");
for (int i = 1; i <= 10; i++) {
if (i % 2 == 0) {
continue; // Skip even numbers
}
if (i == 7) {
break; // Exit the loop if i is 7
}
System.out.print(i + " "); // Prints 1 3 5
}
}
}
2. Arrays 🔢
An array is a container object that holds a fixed number of values of a single type.
Declaration and Initialization
You declare an array by specifying its type, followed by square brackets [], and its name. You initialize it using the new keyword to allocate memory.
Java
// Declaration
int[] numbers;
// Initialization (allocating memory for 5 integers)
numbers = new int[5];
// Declaration and Initialization in one line
String[] names = new String[3];
// Declaration, initialization, and assignment
double[] values = {10.5, 20.0, 33.1};
One-Dimensional Array
A simple, linear array.
Java
public class OneDArray {
public static void main(String[] args) {
// Declare and initialize an array of integers
int[] scores = {98, 87, 92, 78, 85};
System.out.println("Element at index 2: " + scores[2]); // 92
// Iterate through the array using an enhanced for-loop
System.out.print("All scores: ");
for (int score : scores) {
System.out.print(score + " ");
}
}
}
Two-Dimensional Array
An array of arrays, useful for representing grids or matrices.
Example Code:
public class TwoDArray {
public static void main(String[] args) {
// Declare and initialize a 2x3 integer matrix
int[][] matrix = { {1, 2, 3}, {4, 5, 6} };
// Access an element
System.out.println("Element at row 1, column 2: " + matrix[1][2]); // 6
// Iterate through the 2D array using nested loops
for (int i = 0; i < matrix.length; i++) { // Iterate over rows
for (int j = 0; j < matrix[i].length; j++) { // Iterate over columns
System.out.print(matrix[i][j] + " ");
}
System.out.println(); // Newline after each row
}
}
}
3. String Handling 🔡
In Java, String is an object that represents a sequence of characters. Strings are immutable, meaning once a String object is created, it cannot be changed.
String Constructors & toString()
- Constructors: String objects can be created using a string literal (most common) or the new keyword. String s1 = “Hello”; // Literal String s2 = new String(“World”); // Using constructor
- toString() method: This method returns the string representation of an object. It’s often overridden in custom classes to provide meaningful output.
Common String Methods
- Comparison:
- equals(Object anObject): Compares two strings for equality (case-sensitive).
- equalsIgnoreCase(String anotherString): Compares two strings, ignoring case.
- Searching:
- indexOf(int ch): Returns the index of the first occurrence of a character.
- contains(CharSequence s): Returns true if the string contains the specified sequence.
- Modifying (these methods return a new string):
- substring(int beginIndex, int endIndex): Extracts a part of the string.
- toLowerCase() / toUpperCase(): Converts the string to lower or upper case.
- trim(): Removes leading and trailing whitespace.
- replace(char oldChar, char newChar): Replaces all occurrences of a character.
Example Code:
public class StringMethodsDemo {
public static void main(String[] args) {
String greeting = " Hello, World! ";
System.out.println("Original: '" + greeting + "'");
System.out.println("Length: " + greeting.length());
System.out.println("Uppercase: " + greeting.toUpperCase());
System.out.println("Trimmed: '" + greeting.trim() + "'");
System.out.println("Substring (7-12): " + greeting.trim().substring(7, 12)); // "World"
System.out.println("Contains 'World': " + greeting.contains("World")); // true
System.out.println("Replaced 'l' with 'z': " + greeting.replace('l', 'z'));
}
}
4. Other Key Concepts 🚀
Command-Line Arguments
These are arguments passed to the program when it’s run from the command line. They are stored in the String[] args array of the main method.
Example Code:
// Save as CommandLine.java
// Compile: javac CommandLine.java
// Run: java CommandLine arg1 arg2
public class CommandLine {
public static void main(String[] args) {
if (args.length > 0) {
System.out.println("You provided " + args.length + " arguments:");
for (String arg : args) {
System.out.println(arg);
}
} else {
System.out.println("No arguments were provided.");
}
}
}
static Modifier
The static keyword is used for members that belong to the class itself, rather than to an instance of the class.
- Static variable: Shared by all instances of the class.
Static method: Can be called without creating an instance of the class (ClassName.methodName()).
Example Code:
class Thing {
public String name;
public static int count = 0; // Static variable
public Thing(String name) {
this.name = name;
count++; // Increment the static counter
}
public static void showCount() { // Static method
System.out.println("Total things created: " + count);
}
}
// Usage:
// Thing t1 = new Thing("A");
// Thing t2 = new Thing("B");
// Thing.showCount(); // Output: Total things created: 2
this Keyword
The this keyword is a reference to the current object. It is used to:
- Disambiguate between instance variables and parameters with the same name.
- Call another constructor in the same class (constructor chaining).
Example Code:
class Employee {
private String name;
private int id;
// Use 'this' to distinguish instance variable from parameter
public Employee(String name, int id) {
this.name = name;
this.id = id;
}
}
Garbage Collection
Garbage collection is Java’s automatic process of finding and deleting objects that can no longer be reached (referenced). This prevents memory leaks and means developers don’t have to manually deallocate memory. It runs in the background on the JVM.
Method Overloading
Method overloading is a feature that allows a class to have more than one method with the same name, as long as their parameter lists are different2 (i.e., different number of parameters, different types of parameters, or both).
Example Code:
class Calculator {
// Overloaded add method
public int add(int a, int b) {
return a + b;
}
public double add(double a, double b) {
return a + b;
}
public int add(int a, int b, int c) {
return a + b + c;
}
}
public class OverloadingDemo {
public static void main(String[] args) {
Calculator calc = new Calculator();
System.out.println(calc.add(5, 10)); // Calls the first method
System.out.println(calc.add(3.5, 2.2)); // Calls the second method
System.out.println(calc.add(1, 2, 3)); // Calls the third method
}
}
Sources
- https://www.scribd.com/document/505418138/conditional-statement
- https://github.com/alexanderxablaza/javastudy
- http://npochina.com/hd/84.html
- https://github.com/AnkitAg2803/java-program
- https://brainly.com/question/39189441
- https://velog.io/@rowehnn/Java-%ED%95%A8%EC%88%98-%EC%98%A4%EB%B2%84%EB%A1%9C%EB%94%A9overloading
- https://felixrante.com/mastering-java-object-oriented-programming/
UNIT 3 – Inheritance and Packages
This unit delves deeper into one of the core pillars of OOP—Inheritance. We will explore its mechanisms, keywords, and types. We will also learn how to organize and manage our code using Packages.
1. Inheritance 🧬
Inheritance is a fundamental mechanism in OOP that allows a new class (subclass) to acquire the properties (fields) and behaviors (methods) of an existing class (superclass). It represents an “is-a” relationship. For example, a Dog is an Animal.
Inheritance Fundamentals:
- The subclass is also called the child class or derived class.
- The superclass is also called the parent class or base class.
- The extends keyword is used to establish the inheritance relationship.
Example Code:
// Superclass
class Animal {
void eat() {
System.out.println("This animal eats food.");
}
}
// Subclass
// Dog inherits the eat() method from Animal
class Dog extends Animal {
void bark() {
System.out.println("The dog barks.");
}
}
Types of Inheritance
Java supports the following types of inheritance:
- Single Inheritance: A subclass inherits from only one superclass. (e.g., Dog extends Animal).
- Multilevel Inheritance: A class inherits from a class, which in turn inherits from another class. (e.g., Puppy extends Dog, and Dog extends Animal).
- Hierarchical Inheritance: Multiple subclasses inherit from a single superclass. (e.g., Dog extends Animal, and Cat extends Animal).
Note: Java does not support Multiple Inheritance (a class extending more than one class directly) to avoid complexity and ambiguity (the “Diamond Problem”). This capability is achieved using interfaces.
Advantages and Disadvantages of Inheritance
Advantages:
- Code Reusability: A child class can reuse the fields and methods of the parent class.
- Method Overriding: Allows for runtime polymorphism, where a subclass can provide a specific implementation for an inherited method.
- Logical Structure: Promotes a clean, hierarchical organization of code.
Disadvantages:Tight Coupling: The subclass is tightly coupled to the superclass. Changes in the superclass can unintentionally break the functionality of the subclass.
2. Key Concepts in Inheritance
Use of abstract Modifier
The abstract keyword is used to create classes and methods that are incomplete and are meant to be extended.
- Abstract Class: An abstract class cannot be instantiated (you cannot create an object of it). It serves as a template for subclasses.
- Abstract Method: An abstract method is a method declared without an implementation (no body, just a signature). Any non-abstract subclass must provide an implementation for all abstract methods of its superclass.
Example Code:
// Abstract class
abstract class Shape {
// Abstract method (no body)
abstract void draw();
// Regular method
void display() {
System.out.println("This is a shape.");
}
}
class Circle extends Shape {
// Must provide implementation for the abstract method
@Override
void draw() {
System.out.println("Drawing a circle.");
}
}
Method Overriding
Method overriding occurs when a subclass provides a specific implementation for a method that is already defined in its superclass.1
Rules for Overriding:
- The method name must be the same.
- The parameter list must be the same.
- The return type must be the same (or a subtype, known as a covariant return type). The @Override annotation is not mandatory but is highly recommended to ensure you are correctly overriding a method.
super Keyword
The super keyword is a reference variable used to refer to the immediate parent class object.
- To call the superclass constructor: super() can be used to call the constructor of the parent class. It must be the first statement in the subclass constructor.
- To access superclass members: super.methodName() or super.fieldName can be used to access methods or fields of the parent class, especially when the subclass has a member with the same name.
Example Code:
class Person {
String name;
Person(String name) {
this.name = name;
System.out.println("Person constructor called.");
}
void greet() {
System.out.println("Hello, I am a person.");
}
}
class Employee extends Person {
Employee(String name) {
// 1. Calling the superclass constructor
super(name);
System.out.println("Employee constructor called.");
}
@Override
void greet() {
// 2. Accessing the superclass method
super.greet();
System.out.println("Specifically, I am an employee named " + name);
}
}
final Modifier
The final keyword is used to apply restrictions.
- final variable: Creates a constant. Its value cannot be changed once assigned.
- final method: Prevents the method from being overridden by a subclass.
- final class: Prevents the class from being inherited (subclassed). String is a good example of a final class in Java.
Example Code:
// final class cannot be extended
final class SuperComputer {
final double PI = 3.14159; // final variable (constant)
// final method cannot be overridden
final void bootSequence() {
System.out.println("Secure boot sequence initiated.");
}
}
3. Packages 📦
A package in Java is a mechanism for organizing related classes and interfaces into a namespace. They help in preventing naming conflicts and controlling access to code.
Package Fundamentals:
- Packages correspond to the directory structure of your file system. A package com.example.project would be located in a project folder, inside an example folder, inside a com folder.
- The package statement must be the first line in a Java source file.
Types of Packages
- Built-in Packages (from the Java API): These are the libraries included with the JDK. Examples include:
- java.lang: Contains fundamental classes like Object, String, System. This package is automatically imported into every Java program.
- java.util: Contains utility classes like Scanner, List, Map.
- java.io: For input and output operations.
- User-defined Packages: Packages created by developers to organize their own application code.
Importing Packages
The import statement is used to bring a class or an entire package into the scope of the current file, allowing you to use them without referring to their full, qualified name.
- Importing a specific class: import java.util.Scanner;
Importing all classes in a package: import java.util.*; (Using the wildcard *). This is less specific but convenient.
Example Code:
// Declaring the file belongs to this package
package com.mycompany.app;
// Importing the Scanner class from the java.util package
import java.util.Scanner;
public class UserInputReader {
public static void main(String[] args) {
// We can now use Scanner without writing java.util.Scanner
Scanner scanner = new Scanner(System.in);
System.out.print("Enter your name: ");
String name = scanner.nextLine();
System.out.println("Hello, " + name + "!");
scanner.close();
}
}
Sources:
- https://leetcode.com/discuss/interview-question/3828150/oops-cheatsheet-for-interviews-30-questions
- https://www.toutiao.com/article/7270069728390218280/
- https://docs.pingcode.com/baike/403381
UNIT 4 – Interface and Exception Handling
This unit introduces two powerful concepts in Java: interfaces, which are key to achieving full abstraction and flexible design, and exception handling, which provides a structured way to manage errors that occur during program execution.
1. Interface 📝
An interface in Java is a reference type, similar to a class, that can contain only constants, method signatures, default methods, static methods,1 and nested types. It is a blueprint of a class that defines a2 “contract” of what a class can do, without specifying how it does it.
Concept of Interface
- An interface is implicitly abstract. You cannot create an instance of an interface.
- Methods in an interface are implicitly public and abstract.
- Variables declared in an interface are implicitly public, static, and final (i.e., they are constants).
- A class uses the implements keyword to “sign the contract” with an interface.
Example Code:
// Defining an interface
interface Drivable {
// A constant (public static final by default)
int MAX_SPEED = 120;
// Abstract methods (public abstract by default)
void start();
void stop();
void steer(String direction);
}
Advantages of Interface
- Achieve 100% Abstraction: Interfaces define methods without any implementation, providing pure abstraction.
- Enable Multiple Inheritance: A class can implement multiple interfaces, allowing it to inherit the abstract methods of all of them. This is how Java resolves the “diamond problem” of multiple class-based inheritance.
- Support Loose Coupling: By programming to an interface rather than a specific implementation class, you can easily swap out the underlying implementation without changing the code that uses it.
Relationship Between Classes and Interface
A class that implements an interface must provide a concrete implementation for all the abstract methods declared in that interface.
Example Code:
// Interface defining a contract for any "drawable" object
interface Drawable {
void draw(); // Abstract method
}
// Class implementing the interface
class Circle implements Drawable {
// Providing the implementation for the draw method
@Override
public void draw() {
System.out.println("Drawing a circle.");
}
}
// Another class implementing the same interface
class Rectangle implements Drawable {
@Override
public void draw() {
System.out.println("Drawing a rectangle.");
}
}
public class ArtShow {
public static void main(String[] args) {
// Programming to the interface
Drawable myDrawing = new Circle();
myDrawing.draw(); // Output: Drawing a circle.
myDrawing = new Rectangle();
myDrawing.draw(); // Output: Drawing a rectangle.
}
}
2. Exception Handling 🛡️
Exception handling is a powerful mechanism that handles runtime errors in a controlled manner, so that the normal flow of the application is not disrupted. The core idea is to “try” a block of code, “catch” any exceptions that occur, and optionally run cleanup code in a “finally” block.
Fundamental Exception Types
Exceptions in Java are objects that inherit from the Throwable class. The two main types are:
- Checked Exceptions: These are exceptions that are checked at compile-time. The compiler forces you to handle them using a try-catch block or by declaring the method with the throws keyword. They typically represent recoverable, external errors.
- Examples: IOException, FileNotFoundException, SQLException.
- Unchecked Exceptions (Runtime Exceptions): These are exceptions that are not checked at compile-time. They usually occur due to programming errors.
- Examples: NullPointerException, ArrayIndexOutOfBoundsException, ArithmeticException.
Example Code (Handling a Built-in Exception)
public class ExceptionDemo {
public static void main(String[] args) {
try {
// This code might cause an ArithmeticException
int result = 10 / 0;
System.out.println("Result: " + result);
} catch (ArithmeticException e) {
// This block executes if the exception occurs
System.err.println("Error: Cannot divide by zero.");
} finally {
// This block always executes, whether an exception occurred or not
System.out.println("This is the finally block.");
}
System.out.println("Program continues...");
}
}
throw and throws Keywords
- throw: The throw keyword is used to manually throw an exception object from within a method or block of code. It’s used to signal an error condition.
throws: The throws keyword is used in a method signature to declare that the method might throw one or more specified exceptions. It delegates the responsibility of handling the exception to the method that calls it.
Example Code:
public class BankAccount {
// The method signature declares that it can throw an exception
public static void validateAge(int age) throws IllegalArgumentException {
if (age < 18) {
// Manually throwing an exception object
throw new IllegalArgumentException("Applicant is not old enough.");
} else {
System.out.println("Age is valid. Account can be created.");
}
}
public static void main(String[] args) {
try {
validateAge(16);
} catch (IllegalArgumentException e) {
System.err.println("Account creation failed: " + e.getMessage());
}
}
}
Creating User-Defined Exceptions
You can create your own custom exceptions to handle application-specific errors. You do this by creating a class that extends Exception (for a checked exception) or RuntimeException (for an unchecked exception).
Example Code:
// 1. Create a custom exception class
class InsufficientFundsException extends Exception {
public InsufficientFundsException(String message) {
super(message); // Pass the message to the Exception superclass
}
}
// 2. Use the custom exception in your application
class CheckingAccount {
private double balance = 500.00;
public void withdraw(double amount) throws InsufficientFundsException {
if (amount > balance) {
throw new InsufficientFundsException("Withdrawal amount exceeds balance.");
}
balance -= amount;
System.out.println("Withdrawal successful. New balance: " + balance);
}
}
// 3. Handle the custom exception
public class Bank {
public static void main(String[] args) {
CheckingAccount acc = new CheckingAccount();
try {
acc.withdraw(600.00);
} catch (InsufficientFundsException e) {
System.err.println("Transaction failed: " + e.getMessage());
}
}
}
Sources:
- https://www.geeksforgeeks.org/difference-between-abstract-class-and-interface-in-java/
- https://www.programmerpulse.com/articles/interfaces-default-methods-mro/
- https://github.com/dinexh/Java_Files
- https://www.scribd.com/document/706991579/Eroju-Java-Anadu-Repu-Bava-Antadu
Unit 5: Multithreading and Collection Framework
1. Fundamentals of Threads and Multithreading
Multithreading in Java allows multiple threads to execute concurrently within a single program, enabling tasks to run in parallel. A thread is the smallest unit of execution, and multithreading optimizes resource usage, especially on multi-core CPUs. It enhances application responsiveness (e.g., keeping a UI active while processing data) but requires careful management to avoid issues like race conditions or deadlocks.
Key Benefits:
- Improved performance via parallel execution.
- Efficient resource utilization.
- Enhanced user experience with responsive applications.
Challenges:
- Synchronization to prevent data inconsistencies.
- Avoiding deadlocks and race conditions.
Sample Code: Identifying the Main Thread
public class MainThreadExample {
public static void main(String[] args) {
Thread currentThread = Thread.currentThread();
System.out.println("Current thread: " + currentThread.getName());
}
}
Explanation: This code retrieves and prints the name of the main thread (typically “main”), demonstrating how every Java program runs in a thread by default.
2. Thread Life Cycle
A thread in Java transitions through several states during its execution, defined by the Thread.State enum in the Java API (Thread.State):
- NEW: Thread created but not started.
- RUNNABLE: Thread is running or ready to run, awaiting CPU time.
- BLOCKED: Thread is waiting for a monitor lock to enter a synchronized block/method.
- WAITING: Thread waits indefinitely for another thread’s action (e.g., via wait() or join()).
- TIMED_WAITING: Thread waits for a specified time (e.g., via sleep() or wait(timeout)).
- TERMINATED: Thread has completed execution.
Sample Code: Observing Thread States
public class ThreadStateExample {
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(() -> {
try {
Thread.sleep(2000); // Enters TIMED_WAITING state
} catch (InterruptedException e) {
e.printStackTrace();
}
});
System.out.println("State after creation: " + thread.getState()); // NEW
thread.start();
System.out.println("State after start: " + thread.getState()); // RUNNABLE
Thread.sleep(100); // Allow thread to enter sleep
System.out.println("State while sleeping: " + thread.getState()); // TIMED_WAITING
thread.join(); // Wait for thread to finish
System.out.println("State after completion: " + thread.getState()); // TERMINATED
}
}
Explanation: This code creates a thread, starts it, makes it sleep, and checks its state at various points, illustrating transitions between NEW, RUNNABLE, TIMED_WAITING, and TERMINATED states.
3. Ways of Creating Threads
Java provides two primary ways to create threads (Java Multithreading):
- Extending the Thread Class:
- Create a subclass of Thread.
- Override the run() method.
- Instantiate and call start().
- Implementing the Runnable Interface:
- Implement Runnable and define run().
- Pass the instance to a Thread constructor and call start().
- Preferred due to flexibility and support for single inheritance.
Java 8+ also allows using lambda expressions for concise thread creation.
Sample Code:
// Extending Thread
class MyThread extends Thread {
public void run() {
System.out.println("Thread via extending Thread");
}
}
// Implementing Runnable
class MyRunnable implements Runnable {
public void run() {
System.out.println("Thread via implementing Runnable");
}
}
public class ThreadCreationExample {
public static void main(String[] args) {
// Using Thread subclass
MyThread thread1 = new MyThread();
thread1.start();
// Using Runnable
Thread thread2 = new Thread(new MyRunnable());
thread2.start();
// Using lambda (Java 8+)
Thread thread3 = new Thread(() -> System.out.println("Thread via lambda"));
thread3.start();
}
}
Explanation: This code demonstrates three ways to create threads, showing output from each thread. The Runnable approach is more flexible as it avoids tying the class to the Thread hierarchy.
4. Thread Priorities
Threads in Java have priorities ranging from 1 (Thread.MIN_PRIORITY) to 10 (Thread.MAX_PRIORITY), with 5 (Thread.NORM_PRIORITY) as the default. Priorities influence thread scheduling, but the actual execution order depends on the operating system’s scheduler.
Sample Code: Setting Thread Priorities
public class ThreadPriorityExample {
public static void main(String[] args) {
Thread thread1 = new Thread(() -> {
System.out.println("Thread 1 priority: " + Thread.currentThread().getPriority());
});
thread1.setPriority(Thread.MIN_PRIORITY); // 1
Thread thread2 = new Thread(() -> {
System.out.println("Thread 2 priority: " + Thread.currentThread().getPriority());
});
thread2.setPriority(Thread.MAX_PRIORITY); // 10
thread1.start();
thread2.start();
}
}
Explanation: This code sets different priorities for two threads and prints them. Note that execution order may vary due to OS scheduling.
5. Interthread Communication
Threads communicate using wait(), notify(), and notifyAll() methods on shared objects within synchronized blocks. This is crucial for coordinating tasks, such as in the producer-consumer problem, where one thread produces data and another consumes it.
Sample Code: Producer-Consumer
import java.util.LinkedList;
import java.util.Queue;
public class ProducerConsumerExample {
public static void main(String[] args) {
Buffer buffer = new Buffer(5);
Thread producer = new Thread(() -> {
for (int i = 0; i < 10; i++) {
try {
buffer.produce(i);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
Thread consumer = new Thread(() -> {
for (int i = 0; i < 10; i++) {
try {
buffer.consume();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
producer.start();
consumer.start();
}
}
class Buffer {
private Queue < Integer > queue = new LinkedList < > ();
private int capacity;
public Buffer(int capacity) {
this.capacity = capacity;
}
public synchronized void produce(int item) throws InterruptedException {
while (queue.size() == capacity) {
wait(); // Wait if buffer is full
}
queue.add(item);
System.out.println("Produced: " + item);
notify(); // Notify consumer
}
public synchronized void consume() throws InterruptedException {
while (queue.isEmpty()) {
wait(); // Wait if buffer is empty
}
int item = queue.poll();
System.out.println("Consumed: " + item);
notify(); // Notify producer
}
}
Explanation: This code implements a producer-consumer scenario using a fixed-size buffer. The producer adds items, and the consumer removes them, with wait() and notify() ensuring proper coordination.
6. Collection Framework
The Java Collection Framework provides a standardized architecture for storing and manipulating groups of objects, offering more flexibility than arrays (Java Collections).
Difference between Array and Collection
Feature | Array | Collection |
Size | Fixed at creation | Dynamic, can grow/shrink |
Type | Primitives and objects | Objects only (autoboxing for primitives) |
Functionality | Basic operations | Rich methods (add, remove, etc.) |
Performance | Faster for primitives | Overhead due to object wrapping |
Sample Code: Array vs Collection
import java.util.ArrayList;
import java.util.List;
public class ArrayVsCollection {
public static void main(String[] args) {
// Array
int[] array = new int[5];
array[0] = 1;
array[1] = 2;
// Collection
List < Integer > list = new ArrayList < > ();
list.add(1);
list.add(2);
list.add(3);
System.out.println("Array: " + java.util.Arrays.toString(array));
System.out.println("List: " + list);
}
}
Explanation: This code shows arrays’ fixed size versus the dynamic nature of an ArrayList, which can grow as needed.
List Interface and Its Classes
The List interface supports ordered collections with duplicates. Key implementations:
- ArrayList: Dynamic array, fast for random access, slower for insertions/deletions.
- LinkedList: Doubly-linked list, fast for insertions/deletions, slower for random access.
- Vector: Synchronized ArrayList, thread-safe but slower, less used in modern Java.
Sample Code: Using ArrayList
import java.util.ArrayList;
import java.util.List;
public class ArrayListExample {
public static void main(String[] args) {
List < String > list = new ArrayList < > ();
list.add("Apple");
list.add("Banana");
list.add("Cherry");
System.out.println("List: " + list);
System.out.println("Element at index 1: " + list.get(1));
list.remove(1);
System.out.println("After removing index 1: " + list);
}
}
Explanation: This code demonstrates adding, accessing, and removing elements in an ArrayList, showcasing its dynamic nature.
Set Interface and Its Classes
The Set interface ensures unique elements. Key implementations:
- HashSet: Unordered, fast operations using a hash table.
- LinkedHashSet: Maintains insertion order.
- TreeSet: Maintains sorted order using a red-black tree.
Sample Code: Using HashSet
import java.util.HashSet;
import java.util.Set;
public class HashSetExample {
public static void main(String[] args) {
Set < String > set = new HashSet < > ();
set.add("Apple");
set.add("Banana");
set.add("Apple"); // Duplicate ignored
System.out.println("Set: " + set);
System.out.println("Contains 'Banana': " + set.contains("Banana"));
set.remove("Apple");
System.out.println("After removing 'Apple': " + set);
}
}
Explanation: This code shows that HashSet prevents duplicates and supports fast operations like add, contains, and remove.
Map Interface and Its Classes
The Map interface stores key-value pairs with unique keys. Key implementations:
- HashMap: Unordered, fast operations.
- LinkedHashMap: Maintains insertion or access order.
- TreeMap: Keys sorted, slower operations.
Sample Code: Using HashMap
import java.util.HashMap;
import java.util.Map;
public class HashMapExample {
public static void main(String[] args) {
Map < String, Integer > map = new HashMap < > ();
map.put("Apple", 1);
map.put("Banana", 2);
map.put("Cherry", 3);
System.out.println("Map: " + map);
System.out.println("Value for 'Banana': " + map.get("Banana"));
map.remove("Apple");
System.out.println("After removing 'Apple': " + map);
}
}
Explanation: This code demonstrates storing, retrieving, and removing key-value pairs in a HashMap, highlighting its efficiency for key-based access.
Question Bank: Object Oriented Programming using Java
Unit 1: Object-Oriented Programming Fundamentals
- What are the four main features of object-oriented programming (OOP)? Explain each with respect to Java.
- Differentiate between a class and an object in Java. Provide an example of each.
- Explain the role of abstraction in OOP. Write a Java program to demonstrate abstraction using an abstract class.
- How does encapsulation enhance security in Java programs? Provide a code example with private fields and public methods.
- What is polymorphism in Java? Describe the two types of polymorphism with examples.
- Explain the roles of JDK, JRE, and JVM in Java program execution.
- Write a Java program to demonstrate the use of arithmetic and logical operators with appropriate data types.
- What are the characteristics of Java that make it platform-independent? Explain with reference to bytecode.
- Describe the structure of a Java source file. Write a sample Java program and explain its compilation process.
- Write a Java program to create a
Person
class with fields for name and age, and demonstrate object creation and data access.
Unit 2: Control Statements, String Handling, and Arrays
- What are the differences between
if-else
andswitch
statements in Java? Provide scenarios where each is preferred. - Write a Java program to print the first 10 Fibonacci numbers using a
for
loop. - Explain the
break
andcontinue
statements. Write a program to demonstrate their use in awhile
loop. - Write a Java program to declare and initialize a two-dimensional array to store a 3×3 matrix and print its elements.
- What is the purpose of the
toString()
method in theString
class? Write a program to compare two strings usingequals()
. - Write a Java program to search for a substring in a given string using
indexOf()
and modify it usingreplace()
. - Explain the
static
modifier. Write a program to demonstrate a static method and variable in a class. - What is the role of the
this
keyword in Java? Provide a code example to resolve variable shadowing. - Write a Java program to accept command-line arguments and print them in reverse order.
- Explain method overloading. Write a program with an overloaded method to calculate the area of a circle and rectangle.
Unit 3: Inheritance and Packages
- What is inheritance in Java? List two advantages and one disadvantage of using inheritance.
- Write a Java program to demonstrate multilevel inheritance with three classes:
Animal
,Mammal
, andDog
. - Explain the
super
keyword in Java. Write a program to call a superclass constructor usingsuper
. - What is the purpose of the
final
modifier? Provide examples of its use with a variable, method, and class. - Write a Java program to create an abstract class
Shape
with an abstract methoddraw()
, implemented by subclassesCircle
andRectangle
. - What are packages in Java? Explain the difference between built-in and user-defined packages.
- Write a Java program to create a class
Calculator
in a packagemath.utils
and access it from another class. - Explain method overriding with an example. How does it differ from method overloading?
- Write a Java program to demonstrate the use of
protected
access modifier in an inheritance hierarchy. - What are the types of inheritance supported in Java? Write a program to demonstrate single inheritance.
Unit 4: Interfaces and Exception Handling
- What is an interface in Java? List two advantages of using interfaces over abstract classes.
- Write a Java program to create an interface
Vehicle
with a methodstart()
, implemented by classesCar
andBike
. - Explain the difference between checked and unchecked exceptions in Java. Provide one example of each.
- Write a Java program to handle an
ArrayIndexOutOfBoundsException
using a try-catch block. - What is the purpose of the
throws
keyword? Write a program that declares a method throwing anIOException
. - Write a Java program to create a custom exception
InvalidAgeException
and use it to validate an age input. - Explain the role of the
throw
keyword. Write a program to throw aNullPointerException
explicitly. - What is the purpose of the
finally
block? Write a program to demonstrate its execution regardless of an exception. - List three built-in exceptions in Java and their causes. Write a program to catch one of them.
- Write a Java program to demonstrate multiple catch clauses for handling different types of exceptions in a single try block.
Unit 5: Multithreading and Collection Framework
- What is multithreading in Java? Explain how it improves application performance.
- Describe the thread life cycle in Java, briefly explaining each state.
- Write a Java program to create a thread using the
Runnable
interface to print numbers from 1 to 10. - Explain thread priorities in Java. Write a program to create two threads with different priorities and display their priorities.
- Write a Java program to implement a producer-consumer scenario using
wait()
andnotify()
for interthread communication. - What is the difference between an array and a collection in Java? List two advantages of collections.
- Write a Java program to create an
ArrayList
, add elements, remove an element, and iterate using an Iterator. - Explain the
Set
interface and its implementations. Write a program to demonstrateHashSet
preventing duplicates. - Write a Java program to create a
HashMap
, store student names with roll numbers, and retrieve a name by roll number. - What are the differences between
List
,Set
, andMap
interfaces? Write a program to demonstrate one operation for each.
Leave a Reply