Java
Java
You write Java code in .java files using a text editor or an Integrated Development Environment (IDE) like
Eclipse, IntelliJ IDEA, or VS Code.
After writing the Java source code, it needs to be compiled. The compilation process involves converting
human-readable code into bytecode that can be executed by the JVM.
The Java compiler (javac) translates the .java file into a bytecode file with the .class extension.
This bytecode is platform-independent and can be run on any machine with a JVM.
The next step is to run the compiled bytecode. This is where the Java Virtual Machine (JVM) comes into
play. The JVM is responsible for executing the bytecode on a specific platform (Windows, Linux, macOS,
etc.).
This is the main method that serves as the entry point of the program. Each part of the method has a specific
purpose:
public: It is a access specifier. It makes the main method accessible to other parts of the program.
static: Indicates that this method belongs to the class, not to instances of it. This allows the method to be
called without creating an object of the class.
void: Specifies that the method does not return any value.
main: This is the name of the method. It's a special method in Java because it's the starting point when the
program is executed.
String[] args: This is an array of String objects, which can store command-line arguments passed to the
program.
2. System.out.println("Hello world");
This line prints the text "Hello world" to the console.
System: This is a class in the java.lang package that provides access to system-related resources.
out: This is an object of the PrintStream class, part of System. It represents the standard output stream
(console output).
println: This is a method of PrintStream that prints a message to the console and then moves the cursor to
the next line.
You can have multiple main methods in a Java program, but they must have different method signatures, i.e.,
the parameter list must differ. However, only the main method with the signature public static void
main(String[] args) is recognized as the entry point of the program when you run it.
When you run the program, only the public static void main(String[] args) method will be called by
default. The other main methods won't be invoked unless you call them explicitly within the program.
}
When you try to print the args array directly using System.out.println(args), Java does not print the contents of the array
but instead prints a memory reference (the hash code) of the array object.
OUTPUT :- [Ljava.lang.String;@15db9742
Compiler (javac)
Bytecode (.class)
DAY-2
In Java, type casting refers to converting a variable from one data type to another. This process can be either
implicit (automatic) or explicit (manual). These conversions are also known as widening conversion and
narrowing conversion, respectively.
Why It's Safe: Because a smaller type can fit into a larger type without losing information. For example,
an int can easily fit into a double without losing precision.
Why It's Risky: Narrowing can cause data loss or imprecise values. For example, converting a float to an
int results in the fractional part being discarded.
DAY-3
1. IF-ELSE :-
Key Differences:
Type of condition:
In C++, any value can be treated as a condition (non-zero for true, zero for false).
In Java, the condition must evaluate to boolean.
Compilation error: In Java, using non-boolean expressions in if results in a compilation error, while C++
allows such expressions.
2. SWITCH :-
The switch statement exists in both C++ and Java, but the rules governing the types of expressions allowed,
and the behavior are slightly different.
C++ switch:
The expression in the switch statement can be an integral type (i.e., int, char, enum, or short), but it
cannot be floating-point (float, double).
Strings are not allowed as switch expressions in C++.
Fall-through: Like in Java, the switch statement in C++ does not automatically break after each case.
You need to use the break statement to prevent fall-through.
Java switch:
The expression in the switch statement can be an integral type (byte, short, int, char), but also String,
enum, and certain wrapper types (Byte, Integer, etc.).
Floating-point (float, double) types are still not allowed in Java.
Switching on String values is supported in Java (from Java 7 onwards).
Fall-through: Similar to C++, you need break statements to prevent fall-through. However, in Java 12+,
the switch expression uses -> and does not require break statements.
1. Class: Scanner
What it is: Scanner is a built-in class in Java from the java.util package.
Purpose: It's used to take input from various input sources like the console, files, or even strings.
Use here: In this context, Scanner is used to capture input from the user through the console.
2. Object: sc
What it is: sc is an object of the Scanner class.
Purpose: It represents the instance of the Scanner class, and through this object, you can call various
methods of the Scanner class to read user input (like sc.nextInt(), sc.nextLine(), etc.).
Use here: sc is being created to call input methods to read data entered by the user.
4. System.in
What it is: System.in is a standard input stream in Java.
Purpose: It provides a way to read input data from the console.
Use here: It directs the Scanner to take input from the user via the keyboard.
STRINGS
String str1 = "Hello"; Using String Literal
Key Differences:
When you create a string using a string literal (String str1 = "Hello";), the string is stored in a
special area of memory called the String Pool.
If another string with the same value already exists in the pool, Java will reuse that string, rather
than creating a new one.
This is more memory-efficient because it avoids creating multiple copies of the same string.
When you create a string using the new keyword (String str2 = new String("Hello");), Java will
always create a new object in the heap memory, even if a string with the same value exists in the
String Pool.
It does not check for existing strings with the same value in the pool, so this approach consumes
more memory.
2. Object Creation:
String Literal:
Only one object is created if the string value is not already present in the String Pool. If it is
already there, no new object is created, and the reference points to the existing object.
A new object is created every time, regardless of whether the same string exists in the String Pool.
3. String Interning:
String Literal: Strings created as literals are automatically interned (stored in the String Pool).
Using new Keyword: The new keyword doesn't automatically intern the string. However, you can
manually add the string to the pool using the intern() method
Object Creation
This Java statement, Dog dog1 = new Dog();, involves object creation and can be broken down
into several parts:
Dog is the name of the class. In Java, objects are created from classes, which act as
blueprints. Here, the Dog class represents the type of object you are creating.
dog1 is the name of the object reference variable. It holds the reference (address in
memory) to the newly created object. This variable will allow you to interact with the
object's properties and methods.
The = is the assignment operator. It assigns the reference of the newly created object (new
Dog()) to the variable dog1.
4. new Keyword:
The new keyword is used to allocate memory for the new object. It dynamically creates a
new instance of the Dog class.
new Dog() is the constructor call. It invokes the constructor of the Dog class to initialize
the newly created object. If no constructor is explicitly defined in the class, the default
constructor (with no parameters) is automatically called.
If the class has a constructor that accepts parameters, you can pass values during object creation.
A factory method is a method that returns an object. Instead of using new, you call a method that
returns an instance of the class.
Sometimes, you create an object but don't assign it to a variable (if you're just using it for a one-
time operation).
new Dog().bark(); // Calls the bark method without storing the object
You can use reflection to create an object if you don't know the class at compile time.
7. Cloning an Object
You can create a new object by cloning an existing one (assuming the class implements
Cloneable).
8. Deserialization
POINTS TO REMEMBER
Constructor Availability :- If your class does not define a constructor, the Java compiler automatically provides a
default constructor (a no-argument constructor). However, if a parameterized constructor is defined and no default
constructor is, attempting to create an object without arguments will result in a compilation error.
Object Scope and Lifetime :- Local objects (created inside methods) will be destroyed once the method
exits, while objects created as class-level fields (instance variables) will live as long as the object instance
remains in memory.
INHERITANCE
Constructor in Inheritance:
When a subclass object is created, the constructor of the superclass is invoked first, and then the subclass's
constructor is called.
The subclass can explicitly invoke a superclass constructor using super().
ACCESS SPECIFIERS
Key Notes:
Private members are only accessible within the same class.
Default (no modifier) members are accessible within the same package but not outside the
package.
Protected members are accessible within the same package and also by subclasses in other
packages.
Public members are accessible from anywhere.
this Keyword
The this keyword in Java is a reference variable that refers to the current object, the instance of the class from which
it is called. It is commonly used in several contexts within a class.
2. Calling Another Constructor :- It can be used to call another constructor in the same class.
This is known as constructor chaining.
3. Passing the Current Object :- this can be passed as an argument to other methods or
constructors.
4. Returning the Current Object :- It can be returned from a method, allowing method chaining.
Static Context: In static methods or static blocks, this cannot be used because static members
belong to the class rather than any specific instance.
super KEYWORD
The super keyword in Java is used to refer to the parent class (superclass) of the current
object. It serves various purposes related to inheritance.
Important Points
Constructor Call: If super is used in a constructor, it must be the first statement.
Single Inheritance: super can only refer to the immediate parent class. It cannot be used to
refer to a grandparent or any other ancestor class directly.
Static Context: super cannot be used in static methods or static blocks, as it requires an
instance context.
final Keyword
In Java, the final keyword is used to restrict the user from making further modifications. It can
be applied to classes, methods, and variables.
In Java, the final keyword is used to restrict the user from making further modifications. It can
be applied to classes, methods, and variables. Here’s a breakdown of the different usages of the
final keyword:
1. Final Variables
Definition: When a variable is declared as final, its value cannot be changed once it has
been initialized.
Usage: This is commonly used for constants.
2. Final Methods
Abstraction
Abstract Keyword :-
In Java, the abstract keyword is used to declare classes and methods that are incomplete and meant to be
extended or implemented by subclasses. It serves as a blueprint for other classes and ensures that certain
methods are implemented in the derived classes.
1. Abstract Class
Definition: An abstract class is a class that cannot be instantiated directly. It can contain both abstract
(unimplemented) and non-abstract (implemented) methods.
Purpose: Used when you want to provide a base class with some default behavior while enforcing the
implementation of specific methods in derived classes.
2. Abstract Method
Definition: An abstract method is a method declared without a body, meaning it has no implementation in the
abstract class.
Purpose: Forces subclasses to provide their own implementation for this method.
Rules:
Must be declared inside an abstract class.
Cannot be static or final.
When you have a common base class and want to ensure certain methods are implemented in all derived classes.
To enforce consistency across a group of subclasses.
Interfaces :-
In Java, an interface is a reference type that defines a contract or blueprint that other classes must follow. It
contains abstract methods (implicitly public and abstract) and constants (implicitly public, static, and final).
Interfaces are used to achieve abstraction and multiple inheritance in Java.
1. Definition
2. Features of Interfaces
3. Implementing an Interface :- A class that implements an interface must provide implementations for all its methods
unless the class is declared abstract.
4. Extending Interfaces :- An interface can extend another interface, allowing hierarchical organization of related
functionalities.
6. Functional Interfaces (Java 8+) :- An interface with a single abstract method is called a functional interface. It is used
in lambda expressions and method references.
INNER CLASSES
Inner Classes
An inner class is a class defined within another class. It is associated with an instance of the outer class
and has access to all its fields and methods, including private ones.
Key Points:
A nested static class is a static class defined within another class. Unlike inner classes, it does not have
access to the outer class's instance members. It can access static members of the outer class directly.
Key Points:
1. Static: Nested static classes are not tied to an instance of the outer class.
2. Access: They can only access the outer class's static members.
3. Use Case: Used when the inner class does not require access to the instance members of the outer class.
Anonymous Classes
An anonymous class in Java is a type of inner class that has no name and is defined and instantiated in a single
statement. It is primarily used to provide a quick implementation of an interface or an abstract class, or to
override methods of an existing class without formally creating a new subclass.
1. Cannot have a constructor (but can initialize fields within the block).
2. Cannot explicitly extend a class and implement an interface simultaneously.
3. Cannot define static members (except static constants).
1. Single Abstract Method (SAM): Functional interfaces must have only one abstract method, which defines the
interface's functionality.
2. @FunctionalInterface Annotation: It is a marker annotation that explicitly declares an interface as functional. It
is optional but recommended as it prevents accidental addition of multiple abstract methods.
3. Default and Static Methods: Functional interfaces can include default and static methods without affecting
their functional nature since these are not abstract.
4. Compatible with Lambda Expressions: Functional interfaces are designed to work seamlessly with lambda
expressions.
1. Dynamic Allocation:
3. Garbage Collection:
The heap is managed by the garbage collector, which automatically reclaims memory by removing
objects that are no longer reachable.
4. Thread-Safe:
The heap is shared among all threads in a Java application. Synchronization mechanisms are used to
ensure thread safety during access.
1. Object Creation :- When you create an object using the new keyword, the JVM allocates memory for it in the
heap.
2. Garbage Collection :- The JVM periodically performs garbage collection to free up memory occupied by
objects no longer in use, ensuring efficient memory utilization.
3. Out of Memory :- If the heap is full and garbage collection cannot free enough space, the JVM throws an
OutOfMemoryError.
Slower Access: Accessing heap memory is slower compared to stack memory due to global sharing.
Garbage Collection Overhead: Garbage collection may introduce performance overhead during cleanup.
1. Thread-Specific :- Each thread has its own stack memory, independent of others.
2. Stores Method Information :- Includes details of active methods (method calls), local variables, and
references to objects in heap memory.
3. LIFO Structure :- Memory is allocated and deallocated in a Last-In-First-Out order, ensuring efficient
execution.
4. Limited Size :- Stack memory is smaller than heap memory and has a fixed size, configurable with JVM
options (e.g., -Xss).
5. No Garbage Collection :- Stack memory is automatically managed by the JVM. When a method completes, its
stack frame is removed, freeing up space.
1. Fast Access: Due to its LIFO structure, stack memory is faster than heap memory.
2. Thread Safety: Each thread has its own stack, eliminating the need for synchronization.
3. Automatic Memory Management: Memory is automatically freed when a method ends.
1. Limited Size: Stack memory is smaller and can lead to StackOverflowError if too many nested method calls
or recursion occur.
2. Temporary Storage: Data in the stack is temporary and only exists for the lifetime of the method.
1. Root of the Class Hierarchy :- All classes in Java are either a direct or indirect subclass of the Object class.
2. Universal Methods :- The Object class defines methods that every Java object inherits, such as toString(),
equals(), hashCode(), etc.
3. Supports Polymorphism :- A variable of type Object can refer to any object.
1. toString():
Returns a string representation of the object.
Default implementation: getClass().getName() + "@" + Integer.toHexString(hashCode()).
Typically overridden to provide meaningful object details.
2. equals(Object obj):
Checks if two objects are equal.
Default implementation compares memory addresses.
Should be overridden to compare object content.
3. hashCode():
Returns a hash code value for the object.
Must be overridden if equals() is overridden to ensure consistency.
4. clone():
Creates a new object that is a copy of the current object.
The class must implement Cloneable interface to use this method.
6. finalize() :-
Called by the garbage collector before reclaiming an object’s memory.
Deprecated and rarely used in modern Java.
Polymorphism
Polymorphism is one of the key concepts of object-oriented programming, and it allows a single action to
behave differently based on the object or context. Java supports two types of polymorphism: Compile-time
polymorphism and Runtime polymorphism.
Compile-time polymorphism is achieved through method overloading. In this type, the method to be called is
resolved at compile time.
Key Characteristics:
Binding at Compile Time: The compiler determines which method to invoke based on the method signature.
Method Overloading: Occurs when two or more methods in the same class have the same name but different
parameter lists (number, type, or order of parameters).
No Inheritance Required: Can exist within a single class.
Advantages:
Improves code readability by allowing multiple methods with the same name but different functionality.
Increases code flexibility.
Key Characteristics:
Binding at Runtime: The JVM determines which method to invoke based on the actual object type, not the
reference type.
Method Overriding: Occurs when a subclass provides its specific implementation of a method defined in the
parent class.
Inheritance Required: Involves a superclass and a subclass.
Advantages:
Exception Handling
An exception in Java is an unexpected event or error that occurs during the execution of a program and
disrupts its normal flow. Exceptions are Java's way of handling errors and other exceptional events in a
controlled and structured manner.
1. RuntimeException
Common Examples:
NullPointerException
ArrayIndexOutOfBoundsException
ArithmeticException
2. IOException
Category: It is a checked exception, meaning it must be either caught or declared in the method signature.
Definition: IOException and its subclasses are used for handling input/output operations where exceptions may
occur, such as reading from a file, writing to a file, or working with network streams.
Handling Requirement: You are required to handle IOException using a try-catch block or propagate it using
the throws keyword in the method declaration.
Common Causes:
File not found
Unable to read or write a file
Network communication failures
Common Examples:
FileNotFoundException
EOFException
SocketException
1. Unified Architecture :- Provides a common structure for working with collections through interfaces,
implementations, and algorithms.
2. Type Safety :- With generics, collections ensure type safety, preventing runtime errors.
3. Dynamic Memory Allocation :- Collections can dynamically grow and shrink in size, unlike arrays.
4. Built-in Utility Methods :- Methods for sorting, searching, and manipulating data.
Advantages of the Collection Framework
Disadvantages
1. Performance Overhead :- Some collection classes (e.g., LinkedList) may have higher memory or
processing requirements compared to arrays.
2. Complexity :- Overhead in learning the various classes and interfaces.
The Stack class in Java is a subclass of Vector, which is synchronized, making it slower for single-threaded
operations.
ArrayDeque is not synchronized but provides faster operations in single-threaded scenarios, making it a better
choice for modern applications.
1. Key-Value Pair Storage :- Each entry in the map consists of a unique key and its associated value.
2. No Duplicate Keys :- A Map does not allow duplicate keys; if a duplicate key is added, the old value associated
with the key is replaced.
3. Null Handling :- Most implementations allow one null key and multiple null values (e.g., HashMap).
4. Implementations :- Common implementations include HashMap, LinkedHashMap, TreeMap, and
Hashtable.
Why do we need explicit conversion when working with the values of a Map?
When you want to store all values of a collection or map under a variable name, you often need
explicit conversion to transform the data into a specific format or type that can be handled more
conveniently. This process ensures compatibility and clarity.
1. Flexibility:
The values() method returns a Collection view, which is not a concrete implementation like List or
Set. If you want to perform operations specific to a List (like indexing) or Set (like ensuring
uniqueness), you need explicit conversion.
2. Specific Type Requirement:
If you pass values to a method that expects a specific type, such as List or Set, conversion is
necessary.
3. Immutability of View:
The Collection returned by values() is often a view tied to the original Map. Modifying it directly
may not be allowed or may impact the map, so a concrete copy is safer.