• Introduction to OOPs Concepts in Java

    Introduction to OOPs Concepts in Java

    Object-Oriented Programming (OOP) is a programming paradigm that uses objects and classes to model real-world entities. Java is a purely object-oriented language (except for primitive types), making it ideal for understanding OOPs concepts.

    The main principles of OOPs in Java are:

    1. Class and Object
    2. Encapsulation
    3. Inheritance
    4. Polymorphism
    5. Abstraction

    We’ll discuss each principle in detail with examples.


    1. Class and Object

    Class is a blueprint for creating objects. It defines properties (fields) and behaviors (methods) of an object.

    Object is an instance of a class. Each object has its own state and behavior.

    Example:

    // Class definition
    class Car {
        String color;
        String model;
    
        void displayDetails() {
            System.out.println("Car model: " + model + ", Color: " + color);
        }
    }
    
    // Main class
    public class Main {
        public static void main(String[] args) {
            // Object creation
            Car car1 = new Car();
            car1.color = "Red";
            car1.model = "Toyota";
    
            Car car2 = new Car();
            car2.color = "Blue";
            car2.model = "Honda";
    
            car1.displayDetails();
            car2.displayDetails();
        }
    }
    

    Explanation:

    • Car is a class.
    • car1 and car2 are objects of the Car class.
    • Each object has its own values for color and model.

    2. Encapsulation

    Encapsulation is the wrapping of data (variables) and code (methods) together as a single unit. It also restricts direct access to some of the object’s components, making the class more secure.

    • Access Modifiers like private, public, and protected control access.
    • Getters and Setters are used to access private variables.

    Example:

    class Person {
        private String name;
        private int age;
    
        // Getter for name
        public String getName() {
            return name;
        }
    
        // Setter for name
        public void setName(String name) {
            this.name = name;
        }
    
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            if(age > 0) {
                this.age = age;
            } else {
                System.out.println("Age must be positive");
            }
        }
    }
    
    public class Main {
        public static void main(String[] args) {
            Person person = new Person();
            person.setName("Alice");
            person.setAge(25);
    
            System.out.println("Name: " + person.getName());
            System.out.println("Age: " + person.getAge());
        }
    }
    

    Explanation:

    • The Person class uses private fields to restrict direct access.
    • Getters and setters allow controlled access to these fields.

    3. Inheritance

    Inheritance allows a class to inherit properties and methods from another class, promoting code reusability.

    • Super Class (Parent class) – The class whose features are inherited.
    • Sub Class (Child class) – The class that inherits features.

    Example:

    // Parent class
    class Animal {
        void eat() {
            System.out.println("This animal eats food.");
        }
    }
    
    // Child class
    class Dog extends Animal {
        void bark() {
            System.out.println("Dog barks");
        }
    }
    
    public class Main {
        public static void main(String[] args) {
            Dog dog = new Dog();
            dog.eat(); // inherited from Animal
            dog.bark(); // own method
        }
    }
    

    Explanation:

    • Dog inherits the eat() method from Animal.
    • This demonstrates code reuse.

    4. Polymorphism

    Polymorphism means β€œmany forms.” In Java, it allows objects to take multiple forms. There are two types:

    1. Compile-time polymorphism (Method Overloading)
    2. Runtime polymorphism (Method Overriding)

    Example 1: Method Overloading

    class Calculator {
        int add(int a, int b) {
            return a + b;
        }
    
        double add(double a, double b) {
            return a + b;
        }
    }
    
    public class Main {
        public static void main(String[] args) {
            Calculator calc = new Calculator();
            System.out.println(calc.add(5, 10));      // Calls int method
            System.out.println(calc.add(5.5, 10.5));  // Calls double method
        }
    }
    

    Example 2: Method Overriding

    class Animal {
        void sound() {
            System.out.println("Animal makes sound");
        }
    }
    
    class Cat extends Animal {
        @Override
        void sound() {
            System.out.println("Cat meows");
        }
    }
    
    public class Main {
        public static void main(String[] args) {
            Animal myCat = new Cat();
            myCat.sound(); // Runtime polymorphism
        }
    }
    

    Explanation:

    • Overloading – Same method name, different parameters.
    • Overriding – Child class provides its own implementation of a parent method.

    5. Abstraction

    Abstraction is the concept of hiding implementation details and showing only functionality.

    • Achieved using abstract classes or interfaces.

    Example 1: Abstract Class

    abstract class Shape {
        abstract void area(); // abstract method
    }
    
    class Circle extends Shape {
        double radius;
    
        Circle(double radius) {
            this.radius = radius;
        }
    
        void area() {
            System.out.println("Circle area: " + (3.14 * radius * radius));
        }
    }
    
    public class Main {
        public static void main(String[] args) {
            Shape shape = new Circle(5);
            shape.area();
        }
    }
    

    Example 2: Interface

    interface Vehicle {
        void run();
    }
    
    class Bike implements Vehicle {
        public void run() {
            System.out.println("Bike is running");
        }
    }
    
    public class Main {
        public static void main(String[] args) {
            Vehicle bike = new Bike();
            bike.run();
        }
    }
    

    Explanation:

    • Abstract classes and interfaces allow you to define β€œwhat” a class should do, without specifying β€œhow.”

    Other Important OOP Concepts in Java

    1. Constructors – Special methods to initialize objects.
    2. This Keyword – Refers to the current object instance.
    3. Super Keyword – Refers to the parent class object.
    4. Final Keyword – Used to declare constants, prevent inheritance or method overriding.
    5. Static Keyword – For class-level variables and methods.

    OOPs Concepts in Real World Example

    Imagine a Banking System:

    • Class: BankAccount
    • Object: account1 for John, account2 for Alice
    • Encapsulation: balance is private; access via getters/setters
    • Inheritance: SavingsAccount extends BankAccount
    • Polymorphism: Different types of accounts have different calculateInterest() methods
    • Abstraction: Interface Transaction defines deposit() and withdraw() methods

    Conclusion

    OOPs concepts in Java make programs:

    • Modular – Code is divided into classes/objects
    • Reusable – Through inheritance and polymorphism
    • Secure – Through encapsulation
    • Easy to maintain – Abstraction hides complex logic

    Understanding these principles is crucial to mastering Java and building scalable applications.

  • String Constant Pool

    βœ… 1. Introduction

    The String object is one of the most commonly used classes in the Java programming language.

    In this article, we’ll explore the String Constant Pool (or String Pool)β€” a special memory region where the JVM stores String literals to optimize memory usage and performance.

    βœ… Why String Pool Is Important
    1. ➀ Memory Efficiency
      • Prevents duplicate string objects.
      • Saves memory by reusing existing strings.
    2. ➀ Performance Optimization
      • String comparison using == works for string literals since they reference the same object.
    3. ➀ Immutable Design Enables Pooling
      • Since strings are immutable, sharing the same object across the application is safe.

    βœ… 2. String Interning

    Because Strings in Java are immutable, the JVM can save memory by storing only one copy of each string literal in a special area called the String Pool. This process is called interning.

    When we create a String variable and assign a value using a literal, the JVM first checks the String Pool to see if the same string already exists.

    • If it exists, the JVM returns a reference to the existing string without creating a new object.
    • If it doesn’t exist, the new string is added to the pool, and its reference is returned.

    Let’s see a simple example to understand how this works.

    βœ”οΈ Example:

    public class StringInterningExample {
        public static void main(String[] args) {
            String str1 = "Java Knowledge Base";
            String str2 = "Java Knowledge Base";
    
            System.out.println(str1 == str2);  // Output: true
        }
    }
    

    πŸ‘‰ Both str1 and str2 point to the same object in the String Pool.

    βœ… 3. Strings Allocated Using the Constructor

    When we create a String using the new operator, the JVM always creates a new object in the heap, separate from the String Pool.

    βœ”οΈ Example:

    public class NewStringExample {
        public static void main(String[] args) {
            String literalString = "Java Knowledge Base";
            String constructedString = new String("Java Knowledge Base");
    
            System.out.println(literalString == constructedString);  // Output: false
        }
    }
    

    πŸ‘‰ Explanation:

    • literalString points to the interned string in the pool.
    • constructedString points to a new object in heap memory.

    βœ… 4. String Literal vs String Object

    When we create a String using the new() operator, a new object is always created in heap memory. But when we use a String literal like "Java Knowledge Base", the JVM checks the String Pool first β€” if the string already exists, it reuses it; otherwise, it adds the new string to the pool for future use.

    Creation TypeLocation in MemoryReuses Existing Object?
    String LiteralString constant PoolYes
    new String()Heap MemoryNo

    βœ”οΈ Example Comparison:

    public class StringComparisonExample {
        public static void main(String[] args) {
            String first = "Java Knowledge Base";
            String second = "Java Knowledge Base";
            System.out.println(first == second);  // Output: true
    
            String third = new String("Java Knowledge Base");
            String fourth = new String("Java Knowledge Base");
            System.out.println(third == fourth);  // Output: false
    
            String fifth = "Java Knowledge Base";
            String sixth = new String("Java Knowledge Base");
            System.out.println(fifth == sixth);  // Output: false
        }
    }

    πŸ‘‰ Conclusion:
    Prefer using string literals for better performance and memory usage.

    βœ… 5. Manual Interning

    We can manually add a String to the Java String Pool by using the intern() method.

    When we intern a String, its reference is stored in the pool, and the JVM will use this reference whenever the same string is needed.

    Let’s see a simple example to understand this.

    βœ”οΈ Example:

    public class ManualInternExample {
        public static void main(String[] args) {
            String constantString = "interned Java Knowledge Base";
            String newString = new String("interned Java Knowledge Base");
    
            System.out.println(constantString == newString);  // Output: false
    
            String internedString = newString.intern();
    
            System.out.println(constantString == internedString);  // Output: true
        }
    }
    

    πŸ‘‰ Manual interning ensures the string reference points to the pool object.

    βœ… 6. Garbage Collection

    Before Java 7, the String Pool was stored in the PermGen space, which has a fixed size and cannot grow during program execution. It also could not be garbage collected.

    This meant that if we interned too many strings, we could get an OutOfMemoryError.

    From Java 7 onwards, the String Pool is stored in the Heap memory, which can be garbage collected.
    This allows unused strings to be removed, reducing the chance of running out of memor

    πŸ‘‰ Benefit:
    Reduces the risk of OutOfMemoryError when interning many strings.

    βœ… 7. Performance and Optimizations

    In Java 6, the only way to optimize the String Pool was by increasing the PermGen space using the JVM option:

    -XX:MaxPermSize=1G

    From Java 7 onwards, we have better ways to manage and view the String Pool.

    Here are two useful JVM options to see the String Pool details:

    -XX:+PrintFlagsFinal
    -XX:+PrintStringTableStatistics

    If we want to increase the pool size (number of buckets), we can use this option:

    -XX:StringTableSize=4901

    Before Java 7u40, the default pool size was 1009 buckets.
    From Java 7u40 to Java 11, the default size was 60013 buckets, and in newer versions, it increased to 65536 buckets.

    πŸ‘‰ Keep in mind:
    Increasing the pool size uses more memory but makes inserting strings into the pool faster.

    πŸ’‘ Note:

    • Until Java 8, Strings were stored as a char[] using UTF-16 encoding, where each character used 2 bytes of memory.
    • From Java 9 onwards, Java introduced Compact Strings.
      Depending on the content, it uses either byte[] or char[] internally.
    • This helps save heap memory and reduces the work of the Garbage Collector, making Java programs more efficient.

    🎯Conclusion

    • In this guide, we explored how the JVM optimizes memory for String objects using the String Pool and Interning, and why immutability is a core part of the design.
    • By leveraging string literals and the intern() method, we can improve both performance and memory efficiency in Java applications.

  • Why String Is Immutable in Java

    A String in Java is a widely used object that stores a sequence of characters.
    One of the most important properties of the String class in Java is that it is immutable.

    βœ… What Is an Immutable Object?

    An immutable object is an object whose state (data) cannot be changed after it is created.

    • Once a string is created, its content cannot be altered.
    • Any modification creates a new string object.

    βœ”οΈ Example of Immutable Behavior

    public class ImmutableStringExample {
        public static void main(String[] args) {
            String str = "Java";
            str.concat("Knowledge Base");  // This does NOT modify the original str
            
            System.out.println(str);  // Output: Java 
        }
    }

    πŸ‘‰ To get the modified string, you must explicitly assign it:

    str = str.concat("Knowledge Base");
    System.out.println(str);  // Output: Java Knowledge Base

    βœ… Why Is String Immutable in Java?

    1️⃣ String Pool Benefit

    When dealing with strings in Java, a key concept that improves performance and memory management is the String Constant Pool (or String Pool).

    βœ… What Is the String Pool?

    • The String Pool is a special memory region in the Java heap.
    • It stores unique string literals.
    • Every time a string literal is created using double quotes (" "), the JVM checks the pool first:
      • If the string already exists β†’ It reuses the same reference.
      • If the string doesn’t exist β†’ It adds the string to the pool.

    βœ… Example: String Pool Behavior (literals)

    public class StringPoolExample {
        public static void main(String[] args) {
            String str1 = "Java Knowledge Base";
            String str2 = "Java Knowledge Base";
            System.out.println(str1 == str2);  // Output: true
        }
    }

    πŸ‘‰ Explanation:

    • Both str1 and str2 point to the same object in the String Pool.
    • The == operator returns true because both variables reference the same memory address.

    βœ… Example: Using new Keyword

    public class StringPoolExample2 {
        public static void main(String[] args) {
            String str1 = "Java Knowledge Base";
            String str3 = new String("Java Knowledge Base");
    
            System.out.println(str1 == str3);  // Output: false
        }
    }

    πŸ‘‰ Explanation:

    • str1 refers to the pooled string object.
    • str3 refers to a new object in the heap memory.
    • Therefore, str1 == str3 is false.

    2️⃣ Security

    Key Use Cases Where Strings Play a Critical Role:

    • Database connection URLs
    • Usernames and passwords
    • Network connections

    If strings were mutable, any malicious code running in the same application or process could modify the string content unexpectedly, leading to potential security breaches.

    βœ… Example: Password in String (Immutable)
    public class SecurityExample {
        public static void main(String[] args) {
            String password = "SuperSecret123";  // Stored in String Constant Pool
    
            // Imagine some malicious code tries to change the password
            // Since String is immutable, the original value remains unchanged
            password.concat("MaliciousPart");  // Creates a new String object, does not alter original
    
            System.out.println("Password: " + password);  // Output: SuperSecret123
        }
    }
    

    πŸ‘‰ Explanation:

    • The call to password.concat("MaliciousPart") creates a new string but does NOT modify the original password.
    • This behavior protects sensitive data from being tampered with by malicious code.
    βœ… Contrast: Mutable Example (Hypothetical MutableString)
    class MutableString {
        String value;
    
        MutableString(String value) {
            this.value = value;
        }
    
        void setValue(String newValue) {
            this.value = newValue;
        }
    }
    
    public class MutableExample {
        public static void main(String[] args) {
            MutableString password = new MutableString("SuperSecret123");
    
            // Malicious code can change the value
            password.setValue("HackedPassword!");
    
            System.out.println("Password: " + password.value);  // Output: HackedPassword!
        }
    }
    

    πŸ‘‰ Why This Is Dangerous:

    • Sensitive data like passwords can be altered at runtime.
    • Could allow attackers to inject values or manipulate security-critical variables.

    3️⃣ Hashcode Synchronization

    One of the important reasons why Java’s String class is immutable is to ensure hashcode consistency.

    • The hashCode() method for a string is computed only once and cached for future use.
    • Immutability guarantees that the string’s hashcode remains constant throughout its lifetime, which is essential for reliably storing and retrieving strings in hash-based collections like HashMap.
    βœ… What Is hashCode()?
    • The hashCode() method returns an integer value representing the content of the object.
    • It is heavily used in hash-based collections like:
      • HashMap
      • HashSet
      • Hashtable

    βœ… Why Hashcode Consistency Matters

    • Collections like HashMap store key-value pairs in buckets based on the hashcode of the key.
    • If the content of a key (a string, in this case) were to change after being added to a map:
      • The hashcode would change.
      • The object would be stored in the wrong bucket.
      • Retrieving the key later would fail.

    Example:

    public class HashcodeExample {
        public static void main(String[] args) {
            String str = "Java";
            
            // First computation of hashcode
            int hash1 = str.hashCode();
            
            // Second computation of hashcode
            int hash2 = str.hashCode();
            
            System.out.println("Hash1: " + hash1);
            System.out.println("Hash2: " + hash2);
            System.out.println("Hashes are equal: " + (hash1 == hash2));  // Output: true
        }
    }
    

    πŸ‘‰ Why This Works:

    • Subsequent calls return the same value without recomputation.
    • The string content "Java" cannot change because of immutability.
    • The JVM computes the hashcode only once and caches it.

    4️⃣ Thread Safety

    Immutable strings are inherently thread-safe:

    • Multiple threads can share the same String object safely without the need for explicit synchronization.
    • This prevents race conditions or unexpected behavior in a multithreaded environment.
    • No risk of data inconsistency or corruption.

    5️⃣ Performance Optimization

    βœ”οΈ How Does Immutability Improve Performance?
    • Because strings are immutable, they can be safely reused from the string pool.
    • Avoids unnecessary object creation when using literals.

    βœ… Summary Table: Why Strings Are Immutable

    ReasonBenefit
    String PoolMemory optimization & reuse
    SecurityImmutable sensitive data
    Hashcode ConsistencyReliable for HashMap & HashSet
    Thread SafetySafe concurrent access
    PerformanceAvoid repeated object creation
  • String Initialization in Java

    In Java, String is a widely used class that represents a sequence of characters. Strings are immutable objects, meaning once created, their values cannot be changed.

    There are two common ways to initialize a String in Java:

    1. Using String Literal
    2. Using new Keyword

    1️⃣. String Initialization using String Literal

    When you initialize a string using a literal, Java checks the πŸ‘‰String Constant Pool first.
    If the string already exists in the pool, Java reuses it. Otherwise, a new string is created in the pool.

    βœ”οΈ Syntax:

    String str1 = "Java Knowledge Base";

    βœ”οΈ Example:

    public class StringInitializationExample {
        public static void main(String[] args) {
            String str1 = "Java Knowledge Base";
            String str2 = "Java Knowledge Base";
            
            System.out.println(str1 == str2);  // Output: true
        }
    }
    

    πŸ‘‰ Explanation:

    • Both str1 and str2 point to the same object in the String Pool.
    • The == operator returns true because they reference the same memory location.

    2️⃣. String Initialization using new Keyword

    When using the new keyword, Java creates a new String object in the heap memory, even if an identical string exists in the pool.

    βœ”οΈ Syntax:

    String str3 = new String("Java Knowledge Base");

    βœ”οΈ Example:

    public class StringInitializationExample {
        public static void main(String[] args) {
            String str1 = "Java Knowledge Base";
            String str3 = new String("Java Knowledge Base");
            
            System.out.println(str1 == str3);  // Output: false
        }
    }

    πŸ‘‰ Explanation:

    • str1 points to the String Pool object.
    • str3 points to a different object in the heap.
    • The == operator returns false because they reference different memory locations.

    ⚑ Key Differences Between Literal and new Keyword Initialization

    PropertyString Literalnew Keyword
    Memory LocationString PoolHeap
    Memory ReuseYesNo
    PerformanceFasterSlightly slower due to object creation
    Comparison (==) Resulttrue (if same content)false (different objects)

    βœ… Image Diagram

    Here is a simple diagram illustrating the two types of initialization:


    3️⃣. String Declaration

    When you declare a string variable without assigning any value, it just reserves a reference in memory but doesn’t point to any object yet.

    βœ”οΈ Syntax:

    String str;

    βœ”οΈ Example:

    public class StringDeclarationExample {
        public static void main(String[] args) {
            String str;  // Only declared, not initialized
    
            // System.out.println(str); // ❌ Compilation Error: variable str might not have been initialized
        }
    }
    

    πŸ‘‰ Important Points:

    • For local variables, Java does NOT assign a default value, so accessing str without initializing it causes a compilation error.
    • For instance (class member) variables, Java automatically assigns null by default.

    βœ… Example with Class Member:

    public class Example {
        String str;  // Class member variable
    
        public void printString() {
            System.out.println(str);  // Output: null
        }
    
        public static void main(String[] args) {
            Example example = new Example();
            example.printString();
        }
    }
    

    πŸ‘‰ Output:

    null

    4️⃣. Empty String

    An empty string is a string that contains no characters but is a valid String object in memory.
    It is explicitly initialized as "" (double quotes with no characters inside).

    βœ”οΈ Syntax:

    String emptyStr = "";
    

    βœ”οΈ Example:

    public class EmptyStringExample {
        public static void main(String[] args) {
            String emptyStr = "";  // Initialized as an empty string
    
            System.out.println("Length of emptyStr: " + emptyStr.length());  // Output: 0
            System.out.println("Empty String: '" + emptyStr + "'");          // Output: ''
        }
    }
    

    πŸ‘‰ Key Points:

    • emptyStr is a valid object.
    • Its length is 0.
    • You can safely call methods on it, like length(), isEmpty(), etc.

    5️⃣. Null Value

    A null string is a reference that does NOT point to any object in memory.
    It indicates the absence of any string object.

    βœ”οΈ Syntax:

    String nullStr = null;

    βœ”οΈ Example:

    public class NullStringExample {
        public static void main(String[] args) {
            String nullStr = null;
    
            System.out.println(nullStr);  // Output: null
    
            // The following line throws NullPointerException
            // System.out.println(nullStr.length());
        }
    }
    

    πŸ‘‰ Important Notes:

    • You can safely print a null string reference: it prints null.
    • But calling methods on it (like .length(), .isEmpty()) will throw a NullPointerException.

    βœ… Comparison Table: Empty String vs Null Value

    PropertyEmpty String ("")Null Value (null)
    Memory AllocationYes (an object in memory)No object, just a reference
    String Length0Accessing length causes NullPointerException
    Usage ExampleString s = "";String s = null;
    Method CallsSafe (e.g., s.length())Unsafe (throws NullPointerException)
    PurposeRepresents no charactersRepresents absence of object

    βœ… Best Practices

    • Use empty strings ("") when you want to represent an empty text field or no characters.
    • Use null values when the reference should be uninitialized or explicitly indicate “no object”.
    • Always perform null checks before invoking methods on a String variable to avoid exceptions.

    βœ…πŸš¨ Key Points:

    ScenarioExample Code
    Declaration onlyString str; (Must be initialized before use)
    Empty StringString emptyStr = "";
    Null ValueString nullStr = null;

    Understanding the difference helps in writing robust and error-free code.


    🎯Conclusion

    • Prefer using String literals when possible to save memory and improve performance.
    • Use the new keyword when a distinct String object is required.

  • Java Operators

    In Java, operators are special symbols or keywords used to perform operations on variables and values. They are essential in writing expressions and manipulating data in a program.

    1️⃣. Arithmetic Operators

    Arithmetic operators in Java are used to perform basic mathematical calculations(like addition, subtraction, multiplication, division, and modulus) on numeric data types like int, float, double, etc.
    These operators form the foundation of most computations in programming.

    OperatorDescriptionSyntaxExample
    +Additiona + b5 + 3 = 8
    Subtractiona - b5 - 3 = 2
    *Multiplicationa * b5 * 3 = 15
    /Divisiona / b10 / 2 = 5
    %Modulus (Remainder)a % b10 % 3 = 1

    βœ… Example:

    int a = 10, b = 3;
    System.out.println(a + b);  // Output: 13
    System.out.println(a - b);  // Output: 7
    System.out.println(a * b);  // Output: 30
    System.out.println(a / b);  // Output: 3
    System.out.println(a % b);  // Output: 1
    

    2️⃣. Relational (Comparison) Operators

    Relational operators are used to compare two values and return a result of type boolean β€” either true or false.
    They are essential when you want to make decisions in your code, such as in conditional statements (if, while, etc.).

    OperatorDescriptionSyntaxExample
    ==Equal toa == b5 == 3 β†’ false
    !=Not equal toa != b5 != 3 β†’ true
    >Greater thana > b5 > 3 β†’ true
    <Less thana < b5 < 3 β†’ false
    >=Greater or equala >= b5 >= 3 β†’ true
    <=Less or equala <= b5 <= 3 β†’ false

    βœ… Example:

    int a = 5, b = 10;
    System.out.println(a == b);  // false
    System.out.println(a != b);  // true
    System.out.println(a < b);   // true
    System.out.println(a >= b);  // false
    

    3️⃣. Logical Operators

    Logical operators are used to combine multiple boolean expressions or conditions and return a result of type boolean (true or false).
    They are especially useful when you need to make decisions based on multiple conditions in your program

    OperatorDescriptionSyntaxExample Expression
    &&Logical AND(a > b) && (b > c)true if both conditions are true
    ||Logical OR`(a > b)
    !Logical NOT!(a > b)Inverts boolean value (true β†’ false, false β†’ true)

    βœ… Example:

    int a = 5, b = 10, c = 3;
    System.out.println((a < b) && (b > c));  // true
    System.out.println((a > b) || (b > c));  // true
    System.out.println(!(a > b));            // true
    

    4️⃣. Assignment Operators

    Assignment operators are used in Java to assign values to variables. They take the value on the right-hand side and store it in the variable on the left-hand side.

    The simplest assignment operator is the = operator.

    Syntax:

    variable = value;

    Example:

    int a = 10; // assigns the value 10 to variable a

    Here, 10 is assigned to a. The expression a = 10 not only assigns the value but also returns the assigned value (10), which can be used in other expressions.

    OperatorDescriptionSyntaxExample
    =Assigna = ba = 5;
    +=Add and assigna += ba = a + b;
    -=Subtract and assigna -= ba = a - b;
    *=Multiply and assigna *= ba = a * b;
    /=Divide and assigna /= ba = a / b;
    %=Modulus and assigna %= ba = a % b;

    βœ… Example:

    int a = 5;
    a += 3;  // a = a + 3 β†’ a becomes 8
    System.out.println(a);  // Output: 8
    

    5️⃣. Unary Operators

    Unary operators are operators that operate on a single operand to produce a new value or change the state of a variable. They are typically used for incrementing, decrementing, negating, or inverting values.

    Syntax:

    operator operand;

    or

    operand operator;
    OperatorDescriptionSyntaxExample
    +Unary plus+a+5 β†’ 5
    Unary minus-a-5 β†’ -5
    ++Increment by 1a++ / ++aIncrement a
    Decrement by 1a-- / --aDecrement a
    !Logical NOT!truefalse

    βœ… Example:

    int a = 5;
    System.out.println(++a);  // Output: 6 (pre-increment)
    System.out.println(a--);  // Output: 6 (post-decrement; a becomes 5 after)
    

    6️⃣. Ternary Operator

    6.1. Ternary Operator

    The ternary operator is a shortcut for the if-else statement.
    It’s called β€œternary” because it takes three operands.

    Syntax:

    variable = (condition) ? valueIfTrue : valueIfFalse;
    
    • condition β†’ a boolean expression that evaluates to true or false.
    • valueIfTrue β†’ value assigned if the condition is true.
    • valueIfFalse β†’ value assigned if the condition is false.

    It returns a value, unlike if-else, which is a statement.

    6.2. How It Works

    1. Evaluate the condition.
    2. If the condition is true, the first value (valueIfTrue) is used.
    3. If the condition is false, the second value (valueIfFalse) is used.

    βœ… Example:

    int a = 10;
    int b = 20;
    
    int max = (a > b) ? a : b;  // check which is larger
    System.out.println("Maximum: " + max);
    

    Output:

    Maximum: 20

    Explanation:

    • (a > b) β†’ 10 > 20 β†’ false
    • So valueIfFalse (b) is assigned to max.

    6.3. Ternary Operator vs if-else

    Using if-else:

    int a = 10;
    int b = 20;
    int max;
    
    if(a > b) {
        max = a;
    } else {
        max = b;
    }
    System.out.println("Maximum: " + max);
    

    Using Ternary Operator (shorter and cleaner):

    int max = (a > b) ? a : b;

    The ternary operator is concise, making it useful for simple conditional assignments.

    6.4. Nested Ternary Operator

    You can nest ternary operators to check multiple conditions, but be carefulβ€”it can reduce readability.

    Example:

    int a = 5, b = 10, c = 7;
    
    int max = (a > b) ? a : (b > c ? b : c);
    System.out.println("Maximum: " + max);
    

    Output:

    Maximum: 10
    

    Explanation:

    1. (a > b) β†’ 5 > 10 β†’ false β†’ evaluate (b > c ? b : c)
    2. (b > c) β†’ 10 > 7 β†’ true β†’ b is chosen

    6.5. Key Points

    1. Ternary operator always returns a value.
    2. Can be used in assignments, print statements, or return statements.
    3. For multiple conditions, nest carefullyβ€”too much nesting reduces readability.
    4. Works with any data type: int, double, boolean, String, etc.

    7️⃣. Bitwise Operators

    7.1. Bitwise Operators

    Bitwise operators operate on binary representations of integers at the bit level.
    They are used to manipulate individual bits of numbers, which is very useful in low-level programming, flags, and performance optimization.

    Applicable data types: int, long, short, byte, char.

    7.2. Types of Bitwise Operators

    A. Bitwise AND (&)
    • Performs AND operation on each pair of corresponding bits.
    • Result is 1 if both bits are 1, else 0.

    Example:

    int a = 5;   // 0101 in binary
    int b = 3;   // 0011 in binary
    int c = a & b;
    System.out.println(c); // 1 (0001 in binary)
    

    Explanation:

    Bit of a0101
    Bit of b0011
    a & b0001 β†’ 1

    B. Bitwise OR (|)
    • Performs OR operation on each pair of bits.
    • Result is 1 if at least one bit is 1, else 0.
    int c = a | b;
    System.out.println(c); // 7 (0111 in binary)
    C. Bitwise XOR (^)
    • Performs XOR operation on each pair of bits.
    • Result is 1 if bits are different, else 0.
    int c = a ^ b;
    System.out.println(c); // 6 (0110 in binary)
    D. Bitwise Complement (~)
    • Inverts all bits (1 β†’ 0, 0 β†’ 1).
    • For signed integers, result = -(n+1) because of two’s complement.
    int a = 5;       // 0000 0101
    int c = ~a;      // 1111 1010 β†’ -6
    System.out.println(c); // -6
    
    E. Left Shift (<<)
    • Shifts all bits to the left by a certain number of positions.
    • Vacant bits are filled with 0.
    • Equivalent to multiplying by 2^n.
    int a = 5;       // 0101
    int c = a << 2;  // 0101 << 2 β†’ 10100 (20 in decimal)
    System.out.println(c); // 20
    
    F. Right Shift (>>)
    • Shifts all bits to the right.
    • For positive numbers, fills leftmost bits with 0.
    • For negative numbers, fills leftmost bits with 1 (sign extension).
    • Equivalent to dividing by 2^n.
    int a = 20;      // 10100
    int c = a >> 2;  // 10100 >> 2 β†’ 0101 (5)
    System.out.println(c); // 5
    
    G. Unsigned Right Shift (>>>)
    • Shifts bits to the right without considering sign.
    • Fills leftmost bits with 0.
    • Only differs from >> for negative numbers.
    int a = -20;
    int c = a >>> 2;
    System.out.println(c); // large positive number
    OperatorDescriptionSyntaxExample
    &Bitwise ANDa & b5 & 3 β†’ 1
    |Bitwise ORa | b`a
    ^Bitwise XORa ^ b5 ^ 3 β†’ 6
    ~Bitwise Complement~a~5 β†’ -6
    <<Left shifta << 25 << 2 β†’ 20
    >>Right shifta >> 25 >> 2 β†’ 1

    βœ… Example:

    int a = 5;  // 0101 in binary
    int b = 3;  // 0011 in binary
    System.out.println(a & b);  // Output: 1 (0001)
    System.out.println(a | b);  // Output: 7 (0111)
    

    🎯Summary

    Java provides a comprehensive set of operators that simplify performing calculations, comparisons, logical decisions, and bitwise manipulations.
    Understanding their syntax and proper usage is essential for writing clean, efficient, and maintainable Java code.

  • Variable in Java

    βœ… What is a Variable in Java?

    A variable is a named memory location that stores a value. Variables allow programs to store, retrieve, and manipulate data.

    ⚑ Syntax of Variable Declaration

    data_type variableName = value;

    βœ… Types of Variables in Java

    Java variables can be categorized based on where they are declared and how they behave:

    Variable TypeDescription
    Instance VariablesDeclared inside a class but outside any method. Each object has its own copy.
    Static Variables (Class Variables)Declared with the static keyword inside a class but outside methods. Shared across all instances of the class.
    Local VariablesDeclared inside a method or block. Only accessible within that method/block.
    Final Variables (Constants)Declared with the final keyword. Value cannot be changed once assigned.

    1️⃣ Instance Variables

    An instance variable is tied to a specific object. Each object created from the class has its own copy.

    Example:

    public class Car {
        String color;  // Instance variable
    
        public Car(String color) {
            this.color = color;
        }
    
        public void displayColor() {
            System.out.println("Car color: " + color);
        }
    }
    
    public class TestCar {
        public static void main(String[] args) {
            Car car1 = new Car("Red");
            Car car2 = new Car("Blue");
    
            car1.displayColor();  // Output: Car color: Red
            car2.displayColor();  // Output: Car color: Blue
        }
    }
    

    2️⃣ Static Variables (Class Variables)

    A static variable belongs to the class, not any particular object. All objects share the same static variable.

    Example:

    public class Counter {
        static int count = 0;  // Static variable
    
        public Counter() {
            count++;  // Increments shared count
        }
    
        public static void displayCount() {
            System.out.println("Total objects created: " + count);
        }
    }
    
    public class TestCounter {
        public static void main(String[] args) {
            new Counter();
            new Counter();
            Counter.displayCount();  // Output: Total objects created: 2
        }
    }
    

    3️⃣ Local Variables

    A local variable is declared inside a method and accessible only within that method.

    Example:

    public class LocalVariableExample {
        public void displaySum() {
            int a = 5;     // Local variable
            int b = 10;
            int sum = a + b;
            System.out.println("Sum is: " + sum);
        }
    
        public static void main(String[] args) {
            LocalVariableExample obj = new LocalVariableExample();
            obj.displaySum();  // Output: Sum is: 15
        }
    }
    

    πŸ‘‰ Local variables must be initialized before use.


    4️⃣ Final Variables (Constants)

    A variable declared as final cannot be modified after initialization.

    Example:

    public class FinalVariableExample {
        final int DAYS_IN_WEEK = 7;  // Final variable
    
        public void displayDays() {
            System.out.println("Days in a week: " + DAYS_IN_WEEK);
        }
    
        public static void main(String[] args) {
            FinalVariableExample obj = new FinalVariableExample();
            obj.displayDays();  // Output: Days in a week: 7
    
            // obj.DAYS_IN_WEEK = 10;  // ❌ Compilation error: Cannot assign a value to final variable
        }
    }
    

    βœ… Variable Naming Naming Conventions Rules

    Proper naming conventions help make the code readable, maintainable, and consistent with community standards

    1️⃣ Rules for Variable Names

    • Can contain letters, digits, underscores _, and dollar signs $.
    • Must not start with a digit.
    • Cannot use reserved keywords (e.g., int, class, public).
    • Should be meaningful and descriptive.

    Valid Examples:

    int age;
    double salaryAmount;
    String userName;
    boolean isAvailable;

    βœ…Recommended Naming Style (Camel Case)

    TypeExample
    Instance / Local VariableuserName, totalAmount, isAvailable
    Class Variable (Static)Usually written the same as instance variables, but constants use uppercase letters and underscores: MAX_VALUE

    βœ… Variable Scope and Lifetime

    Variable TypeScopeLifetime
    Instance VariableThroughout object lifetimeExists as long as the object exists
    Static VariableThroughout class lifetimeExists as long as the class is loaded
    Local VariableWithin method/blockTemporary – destroyed after method execution
    Final VariableSame as its type (instance, local, or static)Fixed value once initialized

    βœ… Difference Between Instance Variables and Class Variables in Java

    βž” Instance Variables

    An instance variable is a variable declared inside a class but outside any method, constructor, or block.
    Each object (instance) of the class has its own copy of the instance variable.

    βœ… Example of Instance Variables
    public class Car {
        String color;  // Instance variable
    
        public Car(String color) {
            this.color = color;
        }
    
        public void displayColor() {
            System.out.println("Car color: " + color);
        }
    }
    
    public class TestCar {
        public static void main(String[] args) {
            Car car1 = new Car("Red");
            Car car2 = new Car("Blue");
    
            car1.displayColor();  // Output: Car color: Red
            car2.displayColor();  // Output: Car color: Blue
        }
    }
    

    πŸ‘‰ Key Points:

    • Each Car object has its own color.
    • Changing car1.color does not affect car2.color.

    βž” Class Variables (Static Variables)

    A class variable is declared using the static keyword inside a class but outside any method.
    There is only one copy shared by all objects of the class.

    βœ… Example of Class Variables
    public class Counter {
        static int count = 0;  // Class (static) variable
    
        public Counter() {
            count++;  // Increment shared count
        }
    
        public static void displayCount() {
            System.out.println("Objects created: " + count);
        }
    }
    
    public class TestCounter {
        public static void main(String[] args) {
            new Counter();
            new Counter();
            new Counter();
    
            Counter.displayCount();  // Output: Objects created: 3
        }
    }
    

    πŸ‘‰ Key Points:

    • count is shared across all instances.
    • Every time a Counter object is created, the same count variable is updated.

    βœ… Comparison Table

    FeatureInstance VariableClass (Static) Variable
    Belongs toInstance of classClass itself
    Memory AllocationEach object has its own copyOne shared copy in memory
    Access ModifierAccessed via objectAccessed via class or object
    Examplecar1.colorCounter.count
    Use CaseStores object-specific propertiesTracks class-level information (e.g., object count)

    Since Java 10, you can use var instead of explicitly specifying a type, allowing the compiler to automatically infer the variable’s type based on the assigned value.

    πŸš€ Java 10 Local Variable Type Inference (var)

    Java 10 introduced an exciting new feature called Local Variable Type Inference using the var keyword. This allows the compiler to automatically infer the type of a local variable based on the value it is assigned, making the code cleaner and easier to read

    βœ… What Is var in Java 10?

    • The var keyword tells the compiler to infer the variable type automatically from the right-hand side expression.
    • It helps reduce boilerplate code by removing the need to explicitly write the type when it is obvious from the context.
    • Important Restriction: var can only be used for local variables inside methods, not for instance variables, method parameters, or return types.

    βœ… How Does var Work?

    The compiler analyzes the type of the assigned value and infers the correct type during compile-time.

    Syntax:

    var variableName = value;

    1️⃣ Simple Example:

    public class VarExample {
        public static void main(String[] args) {
            var num = 10;               // Inferred as int
            var message = "Hello Java"; // Inferred as String
            var pi = 3.14;             // Inferred as double
    
            System.out.println("Number: " + num);
            System.out.println("Message: " + message);
            System.out.println("Pi: " + pi);
        }
    }
    

    πŸ‘‰ The compiler infers:

    • num β†’ int
    • message β†’ String
    • pi β†’ double

    2️⃣ Working with Collections:

    import java.util.ArrayList;
    
    public class VarWithCollection {
        public static void main(String[] args) {
            var list = new ArrayList<String>();  // Inferred as ArrayList<String>
            list.add("Apple");
            list.add("Banana");
    
            for (var item : list) {  // Inferred as String
                System.out.println(item);
            }
        }
    }

    βœ… Why Is Type Inference Useful?

    • βœ… Reduces Boilerplate Code: No need to explicitly write repetitive types.

    Less Boilerplate Code
    Before Java 10:

    String message = "Hello, World!";
    int number = 100;
    

    With var:

    var message = "Hello, World!";
    var number = 100;
    • βœ… Improves Readability: Especially when working with complex generic types.

    Example Before Type Inference :

    HashMap<String, List<Integer>> map = new HashMap<>();

    Example With Type Inference:

    var map = new HashMap<String, List<Integer>>();
    • βœ… Keeps Type Safety: Unlike dynamically typed languages (e.g., JavaScript), Java ensures that the type is determined at compile time.

    ⚠️ Limitations of Type Inference

    LimitationReason
    Cannot be used without initializationCompiler cannot infer the type if no value is provided.
    Cannot be used for method parameters or return typesMethod signatures must be explicit for readability and clarity.
    Limited to local variablesFields and method parameters still require explicit types.

    βœ…Cannot be used without initialization

    var number; // ❌ Compilation Error – must initialize the variable

    βœ…Cannot be used for method parameters or return types:

    public var getValue() { // ❌ Invalid<br>return 10;<br>}

    βœ…Can only be used in local scope (inside methods, loops, blocks), not as fields in a class.

    public class VarExample {
        
        // int number = 10;      // Valid: Explicit type as class field
        // var number = 10;      // ❌ Compilation Error: Cannot use 'var' here
    
        public void demonstrateVar() {
            var message = "Hello, Type Inference";  // βœ… Local variable using 'var'
            var count = 100;                         // βœ… Local variable with inferred int type
    
            System.out.println(message);  // Output: Hello, Type Inference
            System.out.println(count);    // Output: 100
        }
    
        public static void main(String[] args) {
            VarExample example = new VarExample();
            example.demonstrateVar();
        }
    }

    🎯 Summary

    Variables are the building blocks of Java programs. Understanding their types, scope, lifetime, and usage helps you write clean, maintainable, and efficient code. Proper use of instance, static, local, and final variables gives flexibility while controlling data flow within your program.

  • Wrapper Class in Java

    1️⃣What is a Wrapper Class in Java?

    A Wrapper Class in Java is an object representation of primitive data types. Since Java is an object-oriented language, sometimes we need to treat primitive types like objects (e.g., when working with collections such as ArrayList).

    Primitive TypeCorresponding Wrapper Class
    byteByte
    shortShort
    intInteger
    longLong
    floatFloat
    doubleDouble
    charCharacter
    booleanBoolean

    2️⃣.Why Use Wrapper Classes?

    • Needed for working with Collections API (e.g., ArrayList<Integer>).
    • Provide utility methods (e.g., Integer.parseInt(), Double.toString()).
    • Allow converting between Strings and primitive types.
    • Offer methods for type conversions and constant values.

    3️⃣Autoboxing and Unboxing

    3.1 Autoboxing

    In Java, Autoboxing refers to the automatic conversion of a primitive type (like int, double, or boolean) into its corresponding Wrapper class object (Integer, Double, Boolean).

    This process happens automatically by the Java compiler, so you don’t need to manually wrap primitive values into objects. This is especially useful when you work with collections (like ArrayList) that can only store objects, not primitive types.

    ⚑ How Does It Work?

    Let’s say you have a primitive int value, and you want to store it in an Integer object. Instead of calling a constructor or Integer.valueOf(), Java handles this for you automatically.

    Example:

    public class AutoboxingExample {
        public static void main(String[] args) {
            int num = 50;                 // Primitive int
            Integer obj = num;           // Autoboxing happens here
    
            System.out.println("Primitive int: " + num);
            System.out.println("Wrapper Integer: " + obj);
        }
    }
    

    πŸ‘‰ Explanation :

    • num is a primitive int with value 50.
    • When assigning num to obj of type Integer, Java automatically converts the primitive num into an Integer object.

    ⚑Behind the scenes, the compiler effectively does:

    Integer obj = Integer.valueOf(num);
    βœ… Why Is Autoboxing Useful?
    • It simplifies code readability by removing the need for explicit conversions.
    • Makes it easier to work with Java Collections (like ArrayList<Integer>) that only accept objects.
    • Prevents boilerplate code, keeping programs clean and concise.

    ⚠️ Important Note

    While autoboxing is convenient, be cautious when using it in performance-critical applications, especially in loops. Unnecessary creation of objects may increase memory usage and affect performance

    πŸš€ Autoboxing makes primitive and object interaction effortless, contributing to cleaner and easier-to-read Java code

    3.2 Unboxing

    In Java, Unboxing is the automatic conversion of a Wrapper class object (like Integer, Double, Boolean) back into its corresponding primitive type (int, double, boolean).

    This happens automatically when a wrapper object is used in a context where a primitive type is expected. The compiler takes care of extracting the primitive value from the object, so you don’t have to call methods like .intValue() explicitly.

    ⚑ How Does It Work?

    Imagine you have an Integer object that holds the value 100. If you want to use this value in arithmetic calculations or any place where a primitive int is needed, Java will automatically extract the primitive value from the wrapper object.

    Example:

    public class UnboxingExample {
        public static void main(String[] args) {
            Integer obj = Integer.valueOf(100);   // Wrapper Integer object
    
            int num = obj;  // Unboxing happens here: Integer β†’ int
    
            System.out.println("Wrapper Integer: " + obj);
            System.out.println("Primitive int: " + num);
        }
    }

    πŸ‘‰ What happens here:

    • obj is an Integer object storing the value 100.
    • When we assign obj to num, Java automatically performs unboxing, converting the object into the primitive int value.

    ⚑ Behind the scenes, the compiler effectively does:

    int num = obj.intValue();
    βœ… Why Is Unboxing Useful?
    • Simplifies code readability by avoiding explicit method calls like .intValue().
    • Makes arithmetic operations easy: you can use wrapper objects directly in expressions.
    • Supports seamless interaction between object-oriented APIs and primitive types.

    ⚠️ Important Consideration:
    Beware of null pointer exceptions when unboxing.
    If the wrapper object is null, unboxing it will throw a NullPointerException:

    Integer obj = null;
    int num = obj;  // Throws NullPointerException!

    πŸš€ Unboxing helps Java handle the transition from objects to primitive types automatically, making code easier to write and read, while keeping object-oriented benefits intact.

    4️⃣Converting Wrapper Class to Primitive Type

    A Wrapper Class (such as Integer, Double, or Boolean) wraps a primitive type into an object. However, sometimes you need to extract the primitive value from the wrapper object, for example, when performing arithmetic operations or passing values to methods that require primitives.

    ⚑ How to Convert Wrapper Class to Primitive Type

    You can explicitly convert a wrapper object to its primitive type by using methods provided by the wrapper classes:

    Wrapper ClassMethod Example
    Integer.intValue()
    Double.doubleValue()
    Boolean.booleanValue()

    These methods return the underlying primitive value stored in the wrapper object.

    βœ… Example:

    Use methods like intValue(), doubleValue(), booleanValue() to extract the primitive value from a wrapper object.

    Example:

    public class WrapperToPrimitive {
        public static void main(String[] args) {
            Integer intObj = 123;               // Integer wrapper object
            int num = intObj.intValue();       // Extract int value
    
            Double doubleObj = 45.67;          // Double wrapper object
            double d = doubleObj.doubleValue(); // Extract double value
    
            Boolean boolObj = true;            // Boolean wrapper object
            boolean flag = boolObj.booleanValue(); // Extract boolean value
    
            System.out.println("int: " + num);
            System.out.println("double: " + d);
            System.out.println("boolean: " + flag);
        }
    }
    

    πŸ‘‰ In this example:

    • intObj.intValue() extracts the primitive int from the Integer object.
    • doubleObj.doubleValue() extracts the primitive double.
    • boolObj.booleanValue() extracts the primitive boolean.
    βœ… When Is This Useful?
    • When working in older Java versions (before autoboxing/unboxing was introduced).
    • When you want to explicitly extract a primitive value to avoid any confusion.
    • When working with APIs that require primitive arguments.

    ⚠️ Important Note:
    If the wrapper object is null, calling .intValue(), .doubleValue(), or .booleanValue() will throw a NullPointerException.

    Example of what to avoid:

    Integer obj = null;
    int num = obj.intValue();  // Throws NullPointerException!
    

    πŸš€ Explicit conversion from a Wrapper Class to its primitive type gives you full control and ensures that your program behaves predictably when mixing objects and primitives.


    5️⃣Converting Primitive Type to Wrapper Class

    In Java, Wrapper Classes provide an object representation of primitive types like int, double, or boolean. Sometimes, it is necessary to convert primitive types into their corresponding wrapper objects explicitly, especially when working with collections such as ArrayList, or when an API requires an object type.

    ⚑ How Does This Conversion Work?

    There are two main approaches to convert a primitive type into its corresponding Wrapper Class object:

    1. Using valueOf() Method (Recommended)
      • This is the preferred way because it may cache frequently used values (e.g., small integers), which improves performance.
    2. Using Wrapper Class Constructor (Deprecated in some versions)
      • Example: new Integer(10) works but is discouraged in favor of Integer.valueOf(10).

    Example:

    public class PrimitiveToWrapper {
        public static void main(String[] args) {
            int num = 10;
            Integer intObj = Integer.valueOf(num);  // Converts int β†’ Integer
    
            double d = 99.99;
            Double doubleObj = Double.valueOf(d);  // Converts double β†’ Double
    
            boolean flag = false;
            Boolean boolObj = Boolean.valueOf(flag);  // Converts boolean β†’ Boolean
    
            System.out.println("Integer Object: " + intObj);
            System.out.println("Double Object: " + doubleObj);
            System.out.println("Boolean Object: " + boolObj);
        }
    }

    πŸ‘‰ In this example:

    • Integer.valueOf(num) converts the primitive int num = 10 into an Integer object.
    • Double.valueOf(d) converts the primitive double d = 99.99 into a Double object.
    • Boolean.valueOf(flag) converts the primitive boolean flag = false into a Boolean object.
    βœ… Why Use valueOf() Instead of Constructors?
    • Performance Benefits: The valueOf() method can cache common values, such as integers from -128 to 127, which reduces memory usage and improves performance.
    • Best Practice: Using valueOf() is now preferred over using constructors like new Integer(num).

    Example :

    Integer a = Integer.valueOf(100);
    Integer b = Integer.valueOf(100);
    System.out.println(a == b);  // true, because of caching
    
    Integer x = Integer.valueOf(200);
    Integer y = Integer.valueOf(200);
    System.out.println(x == y);  // false, because 200 is outside cache range
    βœ… When Is Conversion Needed?
    • Adding numbers to a collection like ArrayList<Integer>:
    • Passing objects where APIs expect a Number, Object, or other wrapper type.
    <code>ArrayList<Integer> numbers = new ArrayList<>(); int primitiveNum = 5; numbers.add(Integer.valueOf(primitiveNum)); // Explicit conversion</code>

    ⚠️ Important Note:
    Thanks to Autoboxing, explicit calls to valueOf() are often unnecessary in modern Java. The compiler automatically converts primitive types to their wrapper equivalents when needed.

    Example with Autoboxing:

    Integer intObj = 10;  // Autoboxing automatically calls Integer.valueOf(10)

    However, understanding explicit conversion is useful for clarity, performance considerations, and when reading legacy code.

    πŸš€ Converting primitive types to Wrapper Classes allows you to take advantage of Java’s object-oriented features while working safely and efficiently with APIs that require objects.


    6️⃣ Usage of Wrapper Classes

    Wrapper classes in Java play a crucial role whenever we need to treat primitive types as objects. Here are two of the most important real-world use cases for Wrapper Classes explained in detail.

    βž” 6.1 Working with Collections (e.g., ArrayList)

    Java Collections (like ArrayList, HashMap, etc.) work with objects only, not primitive types. Since primitives such as int, double, and boolean are not objects, we use their corresponding Wrapper Classes (Integer, Double, Boolean) when storing them in collections.

    βœ… Example: Storing Integers in an ArrayList
    import java.util.ArrayList;
    
    public class WrapperWithCollection {
        public static void main(String[] args) {
            ArrayList<Integer> numbers = new ArrayList<>();
    
            // Autoboxing automatically converts primitives to wrapper objects
            numbers.add(10);  // int β†’ Integer
            numbers.add(20);
    
            // When retrieving elements, unboxing happens automatically
            int sum = numbers.get(0) + numbers.get(1);
    
            System.out.println("Sum: " + sum);  // Output: Sum: 30
        }
    }
    

    πŸ‘‰ How It Works:

    • numbers.add(10); β†’ The primitive int value 10 is autoboxed to an Integer object and stored in the ArrayList.
    • numbers.get(0) β†’ Retrieves an Integer object, which is unboxed back to a primitive int when used in arithmetic.
    βœ… Why Is This Important?
    • Collections work with objects, so Wrapper Classes allow primitives to fit in.
    • Autoboxing and Unboxing simplify the code by handling conversions automatically.
    • Avoids manually creating objects like new Integer(10).

    βž” 6.2 Parsing Strings to Primitive Types

    When working with user input or data from external sources (e.g., files, APIs), values are often in String form. To use these values in calculations, they must be converted into primitive types.

    βœ… Example: Converting String to Primitives
    public class StringToPrimitive {
        public static void main(String[] args) {
            String strInt = "100";
            int num = Integer.parseInt(strInt);  // Converts String β†’ int
    
            String strDouble = "99.99";
            double d = Double.parseDouble(strDouble);  // Converts String β†’ double
    
            System.out.println("Parsed int: " + num);      // Output: Parsed int: 100
            System.out.println("Parsed double: " + d);    // Output: Parsed double: 99.99
        }
    }
    

    πŸ‘‰ How It Works:

    • Integer.parseInt(strInt) converts a numeric string into a primitive int.
    • Double.parseDouble(strDouble) converts a string representing a decimal into a primitive double.
    βœ… Why Is This Useful?
    • Essential for applications that receive numeric input as strings (e.g., user input forms).
    • Prevents manual parsing or errors by using built-in utility methods.
    • Works reliably and efficiently, ensuring type safety.

    πŸš€ By using Wrapper Classes, Java bridges the gap between primitive types and objects, enabling powerful functionality while maintaining simplicity through autoboxing and unboxing.


    7️⃣Summary Table of Common Wrapper Class Methods

    Wrapper ClassMethod ExamplePurpose
    IntegerInteger.parseInt("123")Convert String to int
    DoubleDouble.valueOf(3.14)Convert double primitive to Double object
    BooleanBoolean.parseBoolean("true")Convert String to boolean
    CharacterCharacter.toUpperCase('a')Character manipulation utility

    🎯 Conclusion

    Wrapper Classes are powerful tools in Java that bridge the gap between primitive types and objects. They enable convenient operations such as collection storage, type conversion, and utility functions. Autoboxing and unboxing make it seamless to switch between primitive types and their wrappers without explicit conversions in most cases.

  • Java Keywords

    In Java, keywords are reserved words that have a predefined meaning in the language. These words form the core building blocks of Java’s syntax and cannot be used as identifiers (such as variable names, class names, or method names).

    βœ”οΈ Example :
    int age;

    In this statement, int is a keyword that tells the compiler the variable age is of integer type (32-bit signed two’s complement integer). We cannot use int as a variable name, class name, or method name. Attempting to do so results in a compilation error.

    βœ… What are Keywords in Java?

    A keyword is a word that is reserved by Java because it has a special function in the language. Java has a total of 53 keywords (as of Java SE 17), and they cannot be redefined by the user.

    βœ… Why Are Keywords Important?

    • Keywords define the structure and behavior of a Java program.
    • They instruct the compiler to perform specific actions.
    • Prevent the use of meaningful reserved words for other purposes, ensuring consistency.

    βœ…Classification of Java Keywords

    Let’s classify some of the most important Java keywords by their functionality:

    1️⃣ Access Modifiers

    In Java, Access Modifiers are keywords used to control the visibility and accessibility of classes, methods, and variables. They define which parts of your program can access a particular class member (variable, method, or constructor).

    • public, private, protected
    βœ”οΈExample:
    public class MyClass {
        private int data;  // Private variable
    
        public void display() {  // Public method
            System.out.println(data);
        }
    }
    

    2️⃣ Class, Interface, Inheritance Related

    • class, interface, extends, implements

    Example:

    public interface Animal {
        void sound();
    }
    
    public class Dog implements Animal {
        public void sound() {
            System.out.println("Bark");
        }
    }
    
    public class AnimalTester {
        public static void main(String[] args) {
            Dog dog = new Dog();
            dog.sound();
        }
    }
    

    3️⃣ Data Type Keywords

    • int, boolean, char, double, float, long, short, byte

    Example:

    public class DataTypes {
        public static void main(String[] args) {
            int number = 100;
            double price = 99.99;
            boolean isAvailable = true;
            char grade = 'A';
    
            System.out.println("Number: " + number);
            System.out.println("Price: " + price);
            System.out.println("Available: " + isAvailable);
            System.out.println("Grade: " + grade);
        }
    }
    

    4️⃣ Control Flow Keywords

    • if, else, switch, case, default, for, while, do, break, continue, return

    Example:

    public class ControlFlowExample {
        public static void main(String[] args) {
            int number = 5;
    
            if (number > 0) {
                System.out.println("Positive Number");
            } else {
                System.out.println("Non-positive Number");
            }
    
            for (int i = 0; i < 3; i++) {
                System.out.println("Loop iteration: " + i);
            }
        }
    }
    

    5️⃣ Exception Handling Keywords

    • try, catch, finally, throw, throws

    Example:

    public class ExceptionExample {
        public static void main(String[] args) {
            try {
                int result = 10 / 0;
            } catch (ArithmeticException e) {
                System.out.println("Cannot divide by zero");
            } finally {
                System.out.println("Execution completed");
            }
        }
    }
    

    6️⃣ Object Creation and Memory Management

    • new, this, super

    Example:

    class Parent {
        Parent() {
            System.out.println("Parent constructor");
        }
    }
    
    class Child extends Parent {
        Child() {
            super();  // Calls Parent constructor
            System.out.println("Child constructor");
        }
    }
    
    public class ObjectCreation {
        public static void main(String[] args) {
            Child child = new Child();
        }
    }
    

    7️⃣ Concurrency Keywords

    • synchronized, volatile

    Example:

    class Counter {
        private int count = 0;
    
        public synchronized void increment() {
            count++;
        }
    
        public int getCount() {
            return count;
        }
    }
    

    8️⃣ Miscellaneous

    • static, final, abstract, const, native, strictfp, transient

    Example of final and static:

    public class ConstantsExample {
        public static final double PI = 3.14159;
    
        public static void main(String[] args) {
            System.out.println("Value of PI: " + PI);
        }
    }
    

    🚨 Keywords You Should Never Use as Identifiers

    int class = 10;   // ❌ Invalid β€” 'class' is a reserved keyword
    

    βœ…Complete List of Java Keywords (for Reference)

    There are 51 standard keywords in Java that cannot be used as identifiers.

    KeywordDescription
    abstractUsed with classes/methods. An abstract class cannot be instantiated directly. An abstract method must be implemented by a child class.
    assertEnables testing of assumptions in the program.
    booleanRepresents true or false values.
    breakTerminates a loop (for, while, do-while) or a switch block.
    byteStores integer values from -128 to 127.
    caseA block in a switch statement.
    catchHandles exceptions after a try block.
    charStores a single character.
    classDefines a class.
    constReserved keyword (use final instead).
    continueSkips the current iteration in a loop.
    defaultSpecifies the default block in switch, or default methods in interfaces.
    doExecutes a block repeatedly while a condition is true.
    double64-bit floating-point number.
    elseProvides alternative in if-else.
    enumDefines a type with a fixed set of constants.
    extendsInheritance from a superclass.
    finalPrevents reassignment of variables, method overriding, or subclassing.
    finallyCode that executes after a try-catch, regardless of outcome.
    float32-bit floating-point number.
    forLoop that executes a set of statements repeatedly.
    gotoReserved but not used.
    ifConditional branch.
    implementsImplements an interface.
    importImports classes, packages, or interfaces.
    instanceofChecks object type at runtime.
    int32-bit integer.
    interfaceDeclares an interface.
    long64-bit integer.
    nativeDeclares platform-dependent methods.
    newCreates new objects.
    packageDefines a package for organizing classes.
    privateAccess limited to the current class.
    protectedAccessible in current package or subclass.
    publicAccessible from anywhere.
    returnReturns a value from a method.
    short16-bit integer.
    staticBelongs to the class, not an instance.
    strictfpEnforces strict floating-point behavior.
    superRefers to parent class object.
    switchMultiple execution paths based on a variable.
    synchronizedEnsures thread safety.
    thisRefers to the current object.
    throwExplicitly throws an exception.
    throwsDeclares exceptions a method can throw.
    transientPrevents serialization of variables.
    tryWraps code expected to throw exceptions.
    voidMethod returns no value.
    volatileVariable is always read from main memory.
    whileLoops while condition is true.
    _ (Underscore)Since Java 9, used to prevent underscores as unused identifiers.

    ⚠️ Special Notes

    • The keywords const and goto are reserved but not currently used in Java.
    • The literals true, false, and null are not keywords but literals. Still, they cannot be used as identifiers.
    • Keywords such as strictfp, assert, and enum were added in later JDK versions:
      • strictfp β†’ JDK 1.2
      • assert β†’ JDK 1.4
      • enum β†’ JDK 1.5
    • Newer Java features, such as sealed classes, records, and JPMS (Java Platform Module System), introduced contextual keywords.

    ▢️Contextual Keywords

    These words act as keywords in certain contexts but are valid as identifiers otherwise.

    KeywordDescription
    exportsUsed for exporting modules.
    moduleDeclares a module.
    non-sealedUsed with sealed classes.
    openDeclares an open module.
    opensExports a module for reflection.
    permitsDefines allowed subclasses for sealed classes.
    providesUsed in module definition to specify service providers.
    recordDefines a compact data class.
    requiresSpecifies dependencies between modules.
    sealedRestricts class extension.
    toUsed in module declarations.
    transitiveRequires transitive dependencies.
    usesSpecifies a service interface for the module system.
    varInferred local variable type.
    withUsed in module declarations.
    yieldReturns a value from a switch expression.

    βœ”οΈExample of Contextual Keyword record

    public record Person(String name, int age) {}
    
    public class RecordExample {
        public static void main(String[] args) {
            Person person = new Person("Alice", 30);
            System.out.println(person.name() + " - " + person.age());
        }
    }
    

    🎯 Summary

    Java keywords are the backbone of the language’s syntax. Understanding them is essential for writing clean, efficient, and error-free code. By mastering how and where to use them, developers can write maintainable and optimized Java applications.

  • Java main() Method Interview Questions with Answers

    FAQ Section

    1. Why is the main() method public static void in Java?
    2. Can we overload the main() method in Java?
    3. Can the main() method be declared private, protected, or without any modifier?
    4. Is it possible to declare the main() method as non-static?
    5. Can we change the return type of the main() method?
    6. Can the main() method accept arguments other than String[]?
    7. Can a Java program run without the main() method?
    8. Can the main() method be declared final in Java?

    1. Why is the main() method public static?

    • Public β†’ JVM needs to access it from outside the class.
    • Static β†’ JVM can call it without creating an object of the class.
    public class Test {
        public static void main(String[] args) {
            System.out.println("Program starts here!");
        }
    }

    πŸ‘‰ If main() were not public, JVM would not be able to access it.
    πŸ‘‰ If it were not static, JVM would need to instantiate the class before calling it, which may not be possible.

    2. Can we overload the main() method in Java?

    βœ… Yes, you can overload main() with different parameter lists, but JVM always calls the standard one:

    public class Test {
        public static void main(String[] args) {
            System.out.println("Main with String[] called");
            main(10);  // You can call overloaded versions manually
        }
    
        public static void main(int x) {
            System.out.println("Overloaded main with int: " + x);
        }
    }

    Output :

    Main with String[] called
    Overloaded main with int: 10

    3. Can we declare the main() method as private, protected, or with no access modifier?

    ❌ No. JVM requires main() to be public. If you try other access modifiers, you get a runtime error:

    class Test {
        private static void main(String[] args) {
            System.out.println("Won’t run!");
        }
    }

    Output:

    Error: Main method not found in class Test

    4. Can we declare the main() method as non-static?

    ❌ No. If main() is not static, JVM cannot call it without creating an object.

    class Test {
        public void main(String[] args) { // non-static
            System.out.println("This won't run!");
        }
    }
    

    Output:

    Error: Main method is not static in class Test
    

    5. Can we change the return type of the main() method?

    ❌ No, it must be void.
    If you try to return something, JVM won’t recognize it as the entry point.

    class Test {
        public static int main(String[] args) {
            return 0; // Invalid main()
        }
    }
    

    Output:

    Error: Main method must return a value of type void
    

    6. Can the main() method take an argument other than String[]?

    ❌ No. JVM recognizes only String[] (or String... args using varargs).
    Other parameter types won’t work.

    class Test {
        public static void main(int[] args) { // Invalid signature
            System.out.println("Won’t run!");
        }
    }
    

    Valid alternative:

    public static void main(String... args) {
        System.out.println("Valid with varargs");
    }
    

    7. Can we run a Java class without the main() method?

    • In Java 7 and earlier, you could use a static block as an entry point.
    • From Java 8 onward, it is mandatory to have main(); otherwise, JVM throws an error.
    class Test {
        static {
            System.out.println("Static block executes");
            System.exit(0); // Exit without main()
        }
    }
    

    βœ… Works in Java 6/7
    ❌ Throws error in Java 8+


    8. Can we make the main() method final in Java?

    βœ… Yes, you can declare main() as final. It still runs normally because JVM only calls it, not overrides it.

    class Test {
        public final static void main(String[] args) {
            System.out.println("Main declared as final");
        }
    }
    

    Output:

    Main declared as final
    

    πŸ“Œ Summary Table

    QuestionAnswer
    Why public static?JVM needs external access, static avoids object creation
    Overload main()?Yes, but JVM calls only main(String[] args)
    Private/protected main()?No, runtime error
    Non-static main()?No, JVM won’t run it
    Change return type?No, must be void
    Other args than String[]?No, only String[] or String...
    Run without main()?Possible in Java 7 or earlier using static block, not in Java 8+
    Final main()?Yes, works fine