Home Blog Page 99

Object-Oriented Programming – Basics and Concepts

0
java spring boot course
java spring boot course

Table of Contents

  1. Introduction to Object-Oriented Programming (OOP)
  2. Core Principles of OOP
  3. Classes and Objects
  4. Constructors
  5. The this Keyword
  6. Encapsulation
  7. Inheritance
  8. Polymorphism
  9. Abstraction
  10. Summary and Best Practices

1. Introduction to Object-Oriented Programming (OOP)

Object-Oriented Programming (OOP) is a programming paradigm that organizes software design around data, or objects, rather than functions and logic. Java is a fully object-oriented language (with minor exceptions like primitive types) and leverages OOP principles to create reusable, scalable, and maintainable applications.

OOP enables you to model real-world systems more naturally, where everything is treated as an object with properties (fields) and behaviors (methods).


2. Core Principles of OOP

There are four fundamental principles of OOP:

  1. Encapsulation
  2. Inheritance
  3. Polymorphism
  4. Abstraction

These principles work together to provide a flexible and powerful design structure.


3. Classes and Objects

Class

A class is a blueprint for creating objects. It defines the properties and behaviors of the objects.

class Car {
String brand;
int speed;

void drive() {
System.out.println("Driving at " + speed + " km/h");
}
}

Object

An object is an instance of a class.

public class Main {
public static void main(String[] args) {
Car myCar = new Car();
myCar.brand = "Toyota";
myCar.speed = 120;
myCar.drive(); // Outputs: Driving at 120 km/h
}
}

Each object created from the same class has its own set of variables and can perform methods defined in the class.


4. Constructors

A constructor is a special method that is called when an object is instantiated. Its name is the same as the class name and it has no return type.

Example:

class Car {
String brand;

Car(String brandName) {
brand = brandName;
}
}

You can also have default constructors (no parameters) or parameterized constructors.

Java supports constructor overloading, where multiple constructors with different parameter lists are defined in the same class.


5. The this Keyword

The this keyword is a reference to the current object. It is used to distinguish class fields from parameters with the same name.

class Car {
String brand;

Car(String brand) {
this.brand = brand; // Refers to class field, not constructor parameter
}
}

It can also be used to call other constructors within the same class using this() and to pass the current object as an argument.


6. Encapsulation

Encapsulation is the process of bundling data (fields) and methods that operate on that data into a single unit, i.e., a class. It also involves restricting direct access to some of an object’s components, which is usually done using access modifiers like private, public, and protected.

Example:

class Account {
private double balance;

public void deposit(double amount) {
if (amount > 0) {
balance += amount;
}
}

public double getBalance() {
return balance;
}
}

Here, the balance field is private and only accessible through public methods, enforcing controlled access.


7. Inheritance

Inheritance allows a class to inherit fields and methods from another class. The class that inherits is called the subclass, and the class being inherited from is the superclass.

Example:

class Vehicle {
void start() {
System.out.println("Vehicle starting...");
}
}

class Car extends Vehicle {
void honk() {
System.out.println("Car honking...");
}
}

Now Car has both start() and honk() methods.

Java supports single inheritance but not multiple inheritance through classes (it supports it via interfaces).


8. Polymorphism

Polymorphism allows objects to be treated as instances of their parent class rather than their actual class.

Compile-Time Polymorphism (Method Overloading)

We already saw this in the Methods module—same method name, different parameters.

Run-Time Polymorphism (Method Overriding)

Occurs when a subclass provides a specific implementation of a method already defined in its superclass.

class Animal {
void sound() {
System.out.println("Animal makes sound");
}
}

class Dog extends Animal {
@Override
void sound() {
System.out.println("Dog barks");
}
}
Animal obj = new Dog();
obj.sound(); // Outputs: Dog barks

The method that gets called is determined at runtime, not compile time.


9. Abstraction

Abstraction is the process of hiding the internal details and showing only the essential features.

Java supports abstraction through:

  • Abstract classes – cannot be instantiated and can contain abstract methods
  • Interfaces – fully abstract types in earlier versions of Java, but since Java 8, interfaces can have default and static methods too

Abstract class example:

abstract class Shape {
abstract void draw();
}

class Circle extends Shape {
void draw() {
System.out.println("Drawing Circle");
}
}

You cannot create an object of Shape, but you can of Circle, which implements the abstract method.


10. Summary and Best Practices

In this module, we explored:

  • The foundation of Object-Oriented Programming in Java
  • How classes and objects model real-world entities
  • The use of constructors and this keyword
  • Encapsulation for data hiding
  • Inheritance for code reusability
  • Polymorphism for flexible method behavior
  • Abstraction for hiding implementation complexity

Best Practices:

  • Favor encapsulation to protect internal state.
  • Use inheritance judiciously; prefer composition when inheritance isn’t appropriate.
  • Override methods responsibly and always use @Override.
  • Make classes and methods only as accessible as necessary (private by default).
  • Use interfaces to define contracts for unrelated classes.

Methods, Overloading, and Recursion in Java

0
java spring boot course
java spring boot course

Table of Contents

  1. Introduction to Methods in Java
  2. Declaring and Calling Methods
  3. Method Parameters and Return Types
  4. Method Overloading
  5. Recursion in Java
  6. Advantages and Use Cases of Recursion
  7. Stack Memory and Recursive Calls
  8. When to Avoid Recursion
  9. Summary and Best Practices
  10. What’s Next

1. Introduction to Methods in Java

Methods in Java are blocks of code designed to perform specific tasks. They enable developers to organize and reuse code, leading to cleaner, modular, and more manageable programs. Every Java program must have at least one method—the main() method—where execution begins.

Methods can be called multiple times from different parts of a program, improving reusability and reducing redundancy.


2. Declaring and Calling Methods

A method is defined with a specific syntax:

returnType methodName(parameterList) {
// method body
}

Example:

public static void greet() {
System.out.println("Hello, welcome to Java!");
}

To call this method:

greet();

Types of Methods:

  • Static Methods – Belong to the class, can be called without creating an object.
  • Instance Methods – Require an object of the class to be invoked.

3. Method Parameters and Return Types

Methods can take parameters and return values.

Example with Parameters:

public static void displaySum(int a, int b) {
System.out.println("Sum: " + (a + b));
}

Method with Return Type:

public static int add(int a, int b) {
return a + b;
}
int result = add(5, 3); // result = 8

You can use different return types like int, double, boolean, String, or even custom objects.


4. Method Overloading

Java supports method overloading, which allows multiple methods in the same class with the same name but different parameter lists. This enables you to define methods for different data types or number of arguments while keeping the method name consistent.

Example:

public static int multiply(int a, int b) {
return a * b;
}

public static double multiply(double a, double b) {
return a * b;
}

public static int multiply(int a, int b, int c) {
return a * b * c;
}

The Java compiler determines which version to call based on the arguments passed.

Overloading increases code readability and reduces the cognitive load of remembering different method names for similar operations.


5. Recursion in Java

Recursion is a programming technique where a method calls itself to solve smaller instances of a problem. It is often used for problems that can be broken down into similar sub-problems, such as factorial calculation, Fibonacci series, tree traversal, and more.

Example – Factorial:

public static int factorial(int n) {
if (n == 0)
return 1;
return n * factorial(n - 1);
}

In this example, the method calls itself with a smaller value of n, and the recursion stops when n == 0.


6. Advantages and Use Cases of Recursion

Advantages:

  • Reduces the need for complex loops.
  • Code is often shorter and more elegant for problems involving hierarchical or tree structures.
  • Helps in solving problems naturally expressed in recursive terms (e.g., permutations, combinations, backtracking).

Use Cases:

  • Tree traversal
  • Graph traversal (DFS)
  • Searching and sorting (quick sort, merge sort)
  • Dynamic programming problems
  • Mathematical series (factorial, Fibonacci, etc.)

7. Stack Memory and Recursive Calls

Every recursive call adds a new frame to the call stack. Each frame holds the method’s parameters and local variables.

If the recursion does not terminate, it leads to StackOverflowError. Therefore, every recursive method must have a well-defined base case that stops the recursion.

Example:

public static void infiniteRecursion() {
infiniteRecursion(); // StackOverflowError after too many calls
}

8. When to Avoid Recursion

While recursion is elegant, it is not always the best solution. Consider avoiding recursion when:

  • The problem size is large, and memory is a concern.
  • Iterative solutions are more performant.
  • The method lacks a clear or safe base case.
  • The recursive depth is too high (e.g., 10,000+ calls).

In such cases, iterative solutions are generally more efficient and safer.


9. Summary and Best Practices

In this module, you learned:

  • What methods are and why they are used
  • How to define and invoke methods
  • The concept and implementation of method overloading
  • The idea behind recursion and its use cases
  • How stack memory is used in recursion
  • When to prefer iteration over recursion

Best Practices:

  • Always define a clear base case in recursion.
  • Avoid deep recursion in performance-critical code.
  • Use method overloading to handle similar operations more cleanly.
  • Prefer small, single-purpose methods to improve readability and testability.

Strings in Java – String Class, Immutable Nature, StringBuilder and StringBuffer

0
java spring boot course
java spring boot course

Table of Contents

  1. Introduction to Strings in Java
  2. The String Class
  3. String Declaration and Initialization
  4. String Immutability
  5. Common String Methods
  6. String Comparison
  7. String Concatenation and Performance
  8. StringBuilder vs StringBuffer
  9. Real-world Use Cases
  10. Summary and What’s Next

1. Introduction to Strings in Java

In Java, strings are objects that represent sequences of characters. The String class in Java is widely used for text manipulation, storing user input, file data, and more. String handling is a fundamental part of programming, and Java provides a rich set of tools to work with them effectively.

Unlike primitive types, strings in Java are objects and are part of the java.lang package, which is automatically imported.


2. The String Class

The String class in Java is final, meaning it cannot be inherited. It represents immutable character sequences, and once a String object is created, its value cannot be changed.

Internally, Java strings are backed by a character array and stored in a special area called the string constant pool, which helps in memory optimization.


3. String Declaration and Initialization

Using string literals

String name = "John";

When using string literals, Java first checks if the string already exists in the constant pool. If it does, it reuses the reference.

Using new keyword

String name = new String("John");

This creates a new object in the heap, even if the same string exists in the pool.


4. String Immutability

Java strings are immutable, meaning once created, their values cannot be modified.

Example:

String str = "Hello";
str.concat(" World");
System.out.println(str); // Outputs: Hello

Although concat is called, the original string remains unchanged. This behavior improves security and caching but can lead to performance overhead in certain scenarios.

Immutability is one reason strings are safe to use in multithreaded environments without synchronization.


5. Common String Methods

Java provides numerous methods in the String class for various operations:

  • length(): Returns the number of characters
  • charAt(int index): Returns the character at a specified index
  • substring(int beginIndex, int endIndex): Extracts a portion of the string
  • toLowerCase(), toUpperCase(): Changes case
  • trim(): Removes leading and trailing whitespaces
  • equals(), equalsIgnoreCase(): Compares two strings
  • indexOf(), lastIndexOf(): Searches for characters or substrings
  • replace(): Replaces characters or substrings

Example:

String str = "  Java Programming  ";
System.out.println(str.trim().toUpperCase()); // Output: JAVA PROGRAMMING

6. String Comparison

Using ==

Compares reference, not actual content.

String a = "Java";
String b = "Java";
System.out.println(a == b); // true, same reference from pool

String c = new String("Java");
System.out.println(a == c); // false, different objects

Using equals()

Compares content.

System.out.println(a.equals(c)); // true

Using compareTo()

Lexicographically compares two strings.

System.out.println("apple".compareTo("banana")); // Negative value

7. String Concatenation and Performance

Strings can be concatenated using + or concat().

String result = "Hello " + "World";

However, since strings are immutable, repeated concatenation creates multiple intermediate objects, which can degrade performance in large loops.

Inefficient example:

String result = "";
for (int i = 0; i < 1000; i++) {
result += i;
}

Each + creates a new string, leading to O(n^2) complexity.


8. StringBuilder vs StringBuffer

To avoid inefficiencies of immutable strings in repetitive operations, Java provides:

StringBuilder

  • Mutable, not thread-safe
  • Better for single-threaded scenarios
StringBuilder sb = new StringBuilder("Hello");
sb.append(" World");
System.out.println(sb.toString()); // Output: Hello World

StringBuffer

  • Mutable, thread-safe (synchronized)
  • Better for multithreaded environments
StringBuffer sbf = new StringBuffer("Java");
sbf.append(" Rocks");
System.out.println(sbf); // Output: Java Rocks
FeatureStringStringBuilderStringBuffer
MutabilityImmutableMutableMutable
Thread-safeYesNoYes
PerformanceSlow for loopsFastSlower than SB

9. Real-world Use Cases

Parsing user input

Scanner sc = new Scanner(System.in);
String input = sc.nextLine().trim();
if (input.equalsIgnoreCase("yes")) {
System.out.println("Confirmed");
}

Constructing a URL

StringBuilder url = new StringBuilder("https://example.com/");
url.append("user/").append("123");
System.out.println(url.toString());

Logging

Strings are often used to log system output or build dynamic messages.

String msg = String.format("User %s has logged in at %s", username, loginTime);

10. Summary and What’s Next

In this module, we covered:

  • How strings work in Java and their immutable nature
  • How to declare, initialize, and manipulate strings
  • Efficient string handling using StringBuilder and StringBuffer
  • Key methods for comparing, transforming, and parsing strings
  • Use cases and performance considerations

Mastering strings is vital because they appear in nearly every real-world Java application, whether you’re handling input, processing text, or working with APIs.

Arrays in Java – Single & Multi-dimensional Arrays, Array Operations

0
java spring boot course
java spring boot course

Table of Contents

  1. What Are Arrays?
  2. Advantages of Using Arrays
  3. Declaring and Initializing Arrays
  4. Accessing and Modifying Elements
  5. Iterating Through Arrays
  6. Multi-dimensional Arrays
  7. Common Array Operations
  8. Arrays vs ArrayList
  9. Real-world Examples
  10. Summary and What’s Next

1. What Are Arrays?

In Java, an array is a data structure that allows you to store multiple values of the same data type in a single variable. Arrays are fixed in size and indexed, meaning that each element can be accessed using its position (or index), starting from 0.

Arrays are one of the most basic and essential constructs in programming, used in countless applications from mathematical operations to organizing large datasets.


2. Advantages of Using Arrays

  • Efficiency: Arrays allow you to group related data together, making storage and manipulation more efficient.
  • Indexed Access: You can directly access any element in constant time using its index.
  • Ease of Iteration: Arrays can easily be looped through, especially with constructs like the enhanced for-loop.
  • Memory Management: Java arrays are stored in contiguous memory locations, improving data locality and access speed.

3. Declaring and Initializing Arrays

Declaration

int[] numbers;
String[] names;

Initialization with size

int[] numbers = new int[5];  // Array of 5 integers

Initialization with values

int[] numbers = {10, 20, 30, 40, 50};

Assigning elements manually

numbers[0] = 10;
numbers[1] = 20;

Arrays in Java are objects, so when declared, memory is allocated on the heap.


4. Accessing and Modifying Elements

Each element in an array is accessed using its index:

System.out.println(numbers[2]); // prints 30
numbers[2] = 35; // modifies the third element

If you try to access an index outside the array bounds, Java throws an ArrayIndexOutOfBoundsException.


5. Iterating Through Arrays

Using a traditional for loop:

for (int i = 0; i < numbers.length; i++) {
System.out.println(numbers[i]);
}

Using an enhanced for-each loop:

for (int number : numbers) {
System.out.println(number);
}

The enhanced loop is simpler but doesn’t give access to indices. Use it when you just need values.


6. Multi-dimensional Arrays

Java also supports arrays of arrays, often used for matrices and tables.

Declaration and Initialization

int[][] matrix = {
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
};

Accessing Elements

System.out.println(matrix[1][2]); // prints 6

Iterating

for (int i = 0; i < matrix.length; i++) {
for (int j = 0; j < matrix[i].length; j++) {
System.out.print(matrix[i][j] + " ");
}
System.out.println();
}

Multi-dimensional arrays are arrays of arrays in Java, not flat 2D structures like in some other languages.


7. Common Array Operations

Finding Maximum or Minimum

int max = numbers[0];
for (int i = 1; i < numbers.length; i++) {
if (numbers[i] > max) {
max = numbers[i];
}
}

Reversing an Array

for (int i = 0; i < numbers.length / 2; i++) {
int temp = numbers[i];
numbers[i] = numbers[numbers.length - 1 - i];
numbers[numbers.length - 1 - i] = temp;
}

Copying Arrays

int[] copy = Arrays.copyOf(numbers, numbers.length);

Java provides utility classes like Arrays to assist with common array operations like sorting, searching, and copying.


8. Arrays vs ArrayList

FeatureArrayArrayList
SizeFixedDynamic
Type SafetyPrimitive & ObjectsObjects only
PerformanceSlightly fasterMore flexible
MethodsNo built-inRich API

When working with dynamic or frequently resized collections, consider using ArrayList from the java.util package instead of arrays.


9. Real-world Examples

Example 1: Storing student scores

int[] scores = new int[5];
Scanner sc = new Scanner(System.in);
for (int i = 0; i < scores.length; i++) {
System.out.print("Enter score " + (i + 1) + ": ");
scores[i] = sc.nextInt();
}

Example 2: Basic Matrix Multiplication (2×2)

int[][] A = {{1, 2}, {3, 4}};
int[][] B = {{5, 6}, {7, 8}};
int[][] C = new int[2][2];

for (int i = 0; i < 2; i++) {
for (int j = 0; j < 2; j++) {
for (int k = 0; k < 2; k++) {
C[i][j] += A[i][k] * B[k][j];
}
}
}

This example demonstrates the power of multi-dimensional arrays in mathematical computation.


10. Summary and What’s Next

In this module, we covered:

  • The basics of arrays in Java, including declaration, initialization, and iteration
  • Working with both single and multi-dimensional arrays
  • Performing key operations like searching, reversing, and copying
  • Understanding differences between arrays and ArrayList

Arrays form the foundation of many data structures and are critical to efficient memory and data management in Java.

Loops in Java – for, while, do-while, break and continue

0
java spring boot course
java spring boot course

Table of Contents

  1. Introduction to Loops
  2. The for Loop
  3. The while Loop
  4. The do-while Loop
  5. Loop Control Statements: break and continue
  6. Infinite Loops
  7. Nested Loops
  8. Real-World Examples
  9. Summary and What’s Next

1. Introduction to Loops

Loops are used in programming to execute a block of code repeatedly until a certain condition is met. Java supports three main types of loops:

  • for loop
  • while loop
  • do-while loop

Each loop type has its specific use case, but all can be used to achieve similar outcomes. Loops help reduce redundancy, automate repetitive tasks, and improve code readability.


2. The for Loop

The for loop is best when you know in advance how many times you want to iterate.

Syntax:

for (initialization; condition; update) {
// code block to be executed
}

Example:

for (int i = 1; i <= 5; i++) {
System.out.println("Iteration: " + i);
}

Explanation:

  • Initialization: Runs once at the beginning, e.g., int i = 1.
  • Condition: Checked before each iteration; loop runs if it’s true.
  • Update: Executed after each iteration, e.g., i++.

3. The while Loop

The while loop is used when the number of iterations is not known in advance. It checks the condition before the loop body.

Syntax:

while (condition) {
// code block to be executed
}

Example:

int i = 1;
while (i <= 5) {
System.out.println("Count: " + i);
i++;
}

The loop continues as long as i <= 5 is true.


4. The do-while Loop

The do-while loop is similar to the while loop, but it guarantees at least one execution of the loop body, since the condition is evaluated after the loop body.

Syntax:

do {
// code block to be executed
} while (condition);

Example:

int i = 1;
do {
System.out.println("Running: " + i);
i++;
} while (i <= 5);

This loop runs at least once, even if the condition is initially false.


5. Loop Control Statements: break and continue

The break Statement

Used to exit the loop prematurely when a certain condition is met.

for (int i = 1; i <= 10; i++) {
if (i == 5) {
break;
}
System.out.println(i);
}

This loop prints numbers 1 to 4 and then exits when i becomes 5.

The continue Statement

Skips the current iteration and jumps to the next one.

for (int i = 1; i <= 5; i++) {
if (i == 3) {
continue;
}
System.out.println(i);
}

This loop prints 1, 2, 4, 5 (skips 3).


6. Infinite Loops

An infinite loop keeps running forever unless forcibly terminated. Can be useful in event-driven or server applications.

Example:

while (true) {
// keep listening for connections
}

Use infinite loops with care, ensuring there’s a break condition or manual stop mechanism.


7. Nested Loops

You can place a loop inside another loop to perform complex iterations like matrix processing or pattern printing.

Example:

for (int i = 1; i <= 3; i++) {
for (int j = 1; j <= 2; j++) {
System.out.println("i = " + i + ", j = " + j);
}
}

8. Real-World Examples

Printing a Table of a Number

int number = 7;
for (int i = 1; i <= 10; i++) {
System.out.println(number + " * " + i + " = " + (number * i));
}

Counting User Inputs Until a Sentinel Value

Scanner scanner = new Scanner(System.in);
int input;
do {
System.out.print("Enter number (0 to quit): ");
input = scanner.nextInt();
} while (input != 0);

Searching for an Element

int[] arr = {3, 5, 7, 9};
int target = 7;
boolean found = false;

for (int i = 0; i < arr.length; i++) {
if (arr[i] == target) {
found = true;
break;
}
}
System.out.println("Element found: " + found);

9. Summary and What’s Next

In this module, we learned:

  • The structure and use cases of for, while, and do-while loops
  • How to control loop flow using break and continue
  • Common looping patterns including nested loops and infinite loops

Understanding loops is essential to solving repetitive tasks and optimizing code efficiency.