In Java, every variable has a data type, which defines both the kind of values it can store and the operations that can be performed on it. As a result, data types act as the foundation of Java programming because they ensure type safety while also supporting efficient memory management. Moreover, when you select the correct data type, your program runs more smoothly and consumes less memory. On the other hand, choosing the wrong type may waste resources or even cause errors during execution.
2. Categories of Data Types in Java
Java provides two main categories of data types:
Primitive Data Types (built-in, predefined by Java)
Non-Primitive Data Types (objects and references)
3. Primitive Data Types in Java
Java has 8 primitive data types. These are the simplest building blocks.
Data Type
Size
Default Value
Range
Example Usage
byte
8-bit
0
-128 to 127
byte b = 100;
short
16-bit
0
-32,768 to 32,767
short s = 3000;
int
32-bit
0
-2,147,483,648 to 2,147,483,647
int num = 100000;
long
64-bit
0L
huge range
long big = 1000000000L;
float
32-bit
0.0f
7 decimal digits precision
float pi = 3.14f;
double
64-bit
0.0d
15 decimal digits precision
double d = 3.14159265359;
char
16-bit
‘\u0000’
0 to 65,535 (Unicode)
char c = ‘A’;
boolean
1 bit (JVM dependent)
false
true / false
boolean flag = true;
π Key Notes:
int works best for most integer calculations
When numbers go beyond the int range, switch to long
For decimal values, you can choose floator double, though double is usually preferred for higher precision.
A boolean is the right choice whenever you need to represent true/false conditions.
4. Non-Primitive Data Types in Java
Non-primitive (also called reference types) store memory addresses of objects instead of raw values.
Examples include:
Strings (String name = "Java";)
Arrays (int[] numbers = {1,2,3};)
Classes (class Person { })
Interfaces
Objects created from custom classes
π‘ Non-primitive types are created by programmers and are not defined directly by the Java language, except String (which is special).
5. Type Conversion in Java
Java allows converting between compatible data types.
Widening Conversion (Automatic / Implicit)
Smaller β Larger type conversion happens automatically. Example:
int num = 100;
double d = num; // automatic conversion
Narrowing Conversion (Explicit / Casting)
Larger β Smaller type conversion requires explicit casting.
double d = 9.78;
int num = (int) d; // manual casting
6. Wrapper Classes
Every primitive type has a corresponding πwrapper class in java.lang package. These are used when working with collections or frameworks that require objects instead of primitives.
Primitive
Wrapper
byte
Byte
short
Short
int
Integer
long
Long
float
Float
double
Double
char
Character
boolean
Boolean
Example:
int num = 10;
Integer obj = Integer.valueOf(num); // wrapping
int n = obj; // unwrapping
7. Memory Usage & Performance
Primitive types are stored directly in stack memory, fast and efficient.
Objects (non-primitives) are stored in heap memory, and variables hold references to them.
Choosing the right data type improves performance and reduces memory consumption.
8. Real-World Examples
Banking application: Use long for account numbers, double for balance.
Gaming: Use float for character positions, boolean for game status.
Text Processing: Use String for player names, char for symbols.
πSummary
Java provides 8 primitive types and multiple non-primitive types.
On the other hand, primitives are fast and memory-efficient, while objects are powerful and flexible.
Always choose the appropriate type for efficiency.
Wrapper classes allow primitives to be used as objects.
FAQ Section
Q1: What are the 8 primitive data types in Java? They are byte, short, int, long, float, double, char, boolean.
Q2: What is the difference between primitive and non-primitive data types in Java? Primitives store raw values, while non-primitives store references to objects.
Q3: Why use double instead of float in Java? double is more precise (15 digits) compared to float (7 digits).
Q4: Is String a primitive type in Java? No, String is a non-primitive type, but itβs treated specially in Java.
The structure of a Java program is organized into distinct components that work together to define how the program operates. At its core, every Java program includes a class definition, the main method, and the entry point for execution. In addition, programs often use packages and comments to improve organization and readability.
1. General Structure of a Java Program
A simple Java program typically includes:
Package Declaration (optional)
Import Statements (optional)
Class Definition (mandatory)
Main Method (mandatory for standalone execution)
Statements and Expressions
Example: Hello World Program
// Step 1: Package Declaration (optional)
package com.mypackagename;
// Step 2: Import Statements (optional)
import java.util. * ;
// Step 3: Class Definition
public class HelloWorld {
// Step 4: Main Method
public static void main(String[] args) {
// Step 5: Statements
System.out.println("Hello, World!");
}
}
1. Package Declaration
Packages are used to organize classes.
Must be the first statement in the program (except comments).
package com.mypackagename;
2.Import Statements
Used to access classes from other packages.
Example:
You can also use import java.util.*; to import all classes from a package.
import java.util.Scanner;
3. Class Definition
A class in Java is a blueprint or template for creating objects.
It defines the data (fields or variables) and behavior (methods) of those objects.
In fact, every Java program must have at least one class. If declared public, the class can be accessed from other packages.
The class body is enclosed in curly braces {} and typically contains variables, constructors, and methods.
Syntax Example:
public class MyClass {
// fields (data members)
// methods (behavior)
}
4. Main Method
The main method is the entry point of any standalone Java application.
The JVM always starts program execution from this method.
It must follow the exact signature:
public static void main(String[] args) {
// code to execute
}
Explanation of keywords:
public β makes the method accessible to the JVM.
static β allows the method to be called without creating an instance of the class.
void β means the method does not return a value.
String[]β is the data type used to represent an array of text values in Java. The square brackets [ ] indicate that it is an array type.
args β is the name of the method parameter of type String[]. This allows the main method to accept multiple text inputs (command-line arguments) when the program starts. These arguments are typically used to pass user input or configuration data to the program at runtime.
Entry Point of Execution
π Frequently asked questions about the Java main() method βπ Click here to read more
When you run a Java program, the JVM looks for the main method inside the specified class.
The code inside main() is executed sequentially until the program finishes or terminates early.
Inside main, you can create objects, invoke other methods, or perform operations.
5. Statements
Inside the main method, we write instructions.
Example:
System.out.println("Hello, World!");
6. Other Elements in Java Programs
Comments:
Improve readability with // for single-line or /* ... */ for multi-line comments.
// Single-line comment
/* Multi-line
comment */
Variables and Data Types
Store data values.
int number = 10;
Methods
Functions inside a class.
public void greet() {
System.out.println("Welcome to Java!");
}
Objects
Instances of a class used to call methods.
HelloWorld obj = new HelloWorld();
obj.greet();
β Example: A Simple Java Program
package myapp;
import java.util.Scanner;
public class StructureExample {
// method
public void greet(String name) {
System.out.println("Hello, " + name + "!");
}
// main method
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.print("Enter your name: ");
String name = sc.nextLine();
// creating object
StructureExample obj = new StructureExample();
obj.greet(name);
}
}
Explanation:
public class StructureExample : Defines a class named StructureExample. The file name must be HelloWorld.java.
public static void main(String[] args): This is the entry point method where the program begins execution.
System.out.println("Enter your name: ");: This statement prints the text “Hello, World!” to the console.
π Steps to Compile and Run a Java Program
Step 1: Save the Program
Save your code to a file named StructureExample.java. In Java, the file name must always match the public class name.
Step 2: Open Terminal or Command Prompt
Navigate to the directory where the file is saved.
Step 3: Compile the Program
Run the following command to compile the Java file:
javac StructureExample.java
This will create a StructureExample.class file containing the bytecode.
Step 4: Run the Compiled Bytecode
Now, run the program with:
java StructureExample
Output:
Enter your name: Ashish
Hello, Ashish!
π Summary
In summary, the basic structure of a Java program includes a class definition to encapsulate data and behavior, and a main method that acts as the programβs entry point. Moreover, packages, imports, and comments improve maintainability and organization. Understanding this structure is essential for every beginner learning Java programming.
FAQ Section:
Q1: What is the main method in Java? It is the entry point where execution begins: public static void main(String[] args).
Q2: Can a Java program run without a main method? No, a standalone program requires a main method.
Q3: Why is class mandatory in Java? Because Java is object-oriented; everything must reside inside a class.
Q4: Can we write multiple classes in one file? Yes, but only one public class is allowed, and the filename must match it.
When the JVM runs out of memory and cannot allocate more objects or native resources, it throws an OutOfMemoryError. This error can occur in several scenarios. Therefore, understanding the root causes is important for diagnosing and fixing memory problems effectively.
1. Java Heap Space Exhaustion
This occurs when the heap memory is full and no more objects can be allocated.
As a result, the Garbage Collector cannot free enough space to handle new allocations.
Common causes include:
Memory leaks, where objects are unintentionally held in memory.
Sudden spikes in object creation, which exceed the available heap.
Insufficient maximum heap size (-Xmx set too low).
2. GC Overhead Limit Exceeded
This happens when the JVM spends too much time (>98%) on garbage collection but recovers very little memory (<2%).
In other words, the heap is almost full, and GC cannot reclaim enough space to keep the application running efficiently.
3. Metaspace Exhaustion (Java 8 and later)
Metaspace stores class metadata, such as class definitions and methods.
Unlike the old PermGen, Metaspace grows dynamically. However, it can still run out of space if not managed properly.
Causes include:
Loading too many classes dynamically.
ClassLoader leaks, where classes are never unloaded.
In such cases, you may see the error: java.lang.OutOfMemoryError: Metaspace.
4. Native Memory Exhaustion
The JVM also relies on native (off-heap) memory for several purposes, including:
Thread stacks
Direct byte buffers (DirectByteBuffer)
Code cache (JIT compiled code)
JNI/native library allocations
Causes: If these resources are overused, the JVM can fail. For example:-
Creating too many threads can cause unable to create new native thread.
Memory leaks in direct buffer allocations may also lead to OOM errors
5. Array Size Limit Exceeded
The JVM has a platform-dependent maximum array size (close to Integer.MAX_VALUE, ~2 billion).
Consequently, requesting an array larger than this limit results in:
java.lang.OutOfMemoryError: Requested array size exceeds VM limit.
6. Kernel or OS Memory Limits
Even if the JVM is configured with enough memory, the operating system or container may impose stricter limits.
For example:
Running in Docker/Kubernetes with strict memory quotas can trigger OOM errors.
OS-level restrictions on processes or threads may also prevent new allocations.
πSummary of Key Causes
In summary, OutOfMemoryError in Java occurs when the JVM cannot allocate the required memory due to one of several reasons: heap space exhaustion, excessive GC activity, Metaspace leaks, native memory shortages, oversized arrays, or memory limits imposed by the OS or container. Therefore, by identifying the correct cause, developers can apply targeted fixes to resolve the issue
πJava Heap Sizing Best Practices with -Xms and -Xmx
The JVM provides the flags -Xms (initial heap size) and -Xmx (maximum heap size) to control heap memory allocation. Proper sizing is critical because it directly impacts application performance, garbage collection behavior, and system stability.
1. Set Initial and Maximum Heap Size Appropriately
Use -Xms to define the initial heap size and -Xmx to set the maximum heap size.
In many cases, it is recommended to set both values to the same size (for example, -Xms4G -Xmx4G).
By doing so, you avoid heap resizing at runtime, which can otherwise introduce performance overhead.
2. Size Heap Based on Application Needs and Physical Memory
The heap should be large enough to hold the applicationβs live data footprint, which reduces garbage collection frequency.
However, it should not be so large that it results in excessive GC pause times.
In addition, always ensure that the heap fits comfortably within the available physical memory to prevent OS-level swapping, which slows down performance significantly.
3. Avoid Setting Heap Too Small
A heap that is too small leads to frequent full GCs and may trigger OutOfMemoryError exceptions.
Therefore, always monitor GC logs and heap usage metrics to make informed adjustments.
4. Avoid Oversized Heap Without Proper GC Tuning
A very large heap can reduce GC frequency; however, it also increases pause times during collection.
Consequently, if you need very large heaps, you should use advanced collectors such as G1GC or ZGC.
Moreover, tune GC flags according to your applicationβs workload to balance throughput and latency.
5. Rely on Profiling and Monitoring
Rather than guessing heap sizes, use profiling and monitoring tools (e.g., JVisualVM, JFR, or GC logs).
These tools provide insights into heap usage patterns, GC frequency, and pause durations.
As a result, you can make data-driven decisions when setting -Xms and -Xmx.
6. Consider Platform Limitations
The maximum heap size depends on the underlying platform.
For example, 32-bit JVMs are limited in addressable memory compared to 64-bit JVMs.
Therefore, always check system and container limits before assigning a very large heap.
π Summary
In summary, optimal Java heap sizing with -Xms and -Xmx depends on balancing application needs, garbage collection performance, and system resources. Start by setting both flags to the same size, monitor heap behavior closely, and adjust based on profiling data rather than arbitrary values
To download and install the Java Development Kit ( JDK) and Java Runtime Environment (JRE), follow these step-by-step instructions for Windows, macOS, and Linux.The overall process is similar across all platforms, with minor differences in installation steps and setting up environment variables.
β What is JDK in Java?
The Java Development Kit (JDK) is a complete software development kit used to build Java applications. It includes:
Java Runtime Environment (JRE) β provides the libraries and tools to run Java programs.
Java Virtual Machine (JVM) β executes the compiled Java bytecode.
Development tools β such as the Java compiler (javac), debugger, and packaging utilities.
In short, the JDK is more than just a runtime environmentβit provides everything needed to develop, compile, and run Java programs.
β Why Do We Need JDK Instead of Just JRE?
A common question developers ask is: π βTo run Java programs, isnβt the JRE enough? Why do we need the complete JDK?β
The answer:
The JRE is enough to run Java applications.
But to develop Java applications, you need tools like the compiler (javac), debugger, and other utilities that are only included in the JDK.
Thatβs why programmers use the JDK for development and the JRE for execution.
β The Architecture of JDK in Java
The architecture of JDK consists of three essential components:
JVM (Java Virtual Machine)
Provides a runtime environment for Java programs.
Converts compiled Java bytecode into machine code.
Powers Javaβs famous feature: βWrite once, run anywhere.β
JRE (Java Runtime Environment)
Provides the core libraries, Java ClassLoader, and other components required to run applications.
It does not include development tools like the compiler.
Development Tools (inside JDK)
Includes javac (Java compiler), jdb (debugger), jar (archiver), and other utilities required for building Java applications.
β Downloading Java JDK and JRE
1. Visit the Official Website Go to the Oracle Java Downloads page or the OpenJDK official site. The current stable Java versions are JDK 21 (LTS) and JDK 23 (latest release).
2. Choose Your Operating System Download the installer that matches your operating system:
Windows (.exe)
macOS (.dmg or .pkg)
Linux (.tar.gz or Debian package)
3. Accept the License Agreement For Oracle JDK downloads, review and accept the license agreement before proceeding with the download.
β Installing Java JDK on Windows
1. Run the Installer Double-click the downloaded .exe file to start the installation.
2. Follow Installation Prompts Proceed with the setup wizard, selecting the default options unless you prefer a custom location. By default, Java is installed in:
C:\Program Files\Java\jdk-xx
3. Set the JAVA_HOME Environment Variable
Right-click This PC β Properties β Advanced system settings β Environment Variables.
Add a new variable:
Name:JAVA_HOME
Value: path of your JDK installation (e.g., C:\Program Files\Java\jdk-21).
Edit the existing Path variable and add: %JAVA_HOME%\bin
4. Verify Installation Run the following commands to confirm Java is installed correctly:
java --version
javac --version
β Installing Java JRE
On Windows
Download the Java Runtime Environment (JRE) installer from the official Oracle Java Downloads page. Run the installer, follow the setup prompts, and configure the JRE path in System Environment Variables, similar to the JDK setup process.
On macOS/Linux
In most modern setups, the JRE is already bundled with the JDK. If you still need a standalone JRE, the process is similar: download the installer for your OS, complete the installation, set the JAVA_HOME environment variable, and verify the installation.
π Important Notes
Most modern JDK packages include JRE by default, so a separate JRE installation is usually unnecessary.
Always download Java from official sources (Oracle or OpenJDK) to ensure security and long-term support.
Correct installation and environment variable setup ensure Java is ready for both development (JDK) and runtime (JRE) tasks on your system.
Garbage Collection (GC) is the process by which the JVM automatically frees up memory by removing objects that are no longer reachable in the program. It runs in the background along with the Java application, reclaiming unused memory to improve performance and avoid memory leaks.
πΉPurpose of Garbage Collection in Java
In Java, garbage collection (GC) is the process of automatically reclaiming memory by removing objects that are no longer reachable or needed by the application.
Java programs create many objects dynamically (using new).
Some of these objects may only be used temporarily. Once no references point to them, they become eligible for garbage collection.
Instead of requiring developers to explicitly free memory (like in C/C++ with free() or delete), Javaβs GC automates memory cleanup.
πΉAutomated Nature of Garbage Collection
No manual deallocation: Developers donβt have to explicitly release memory. The Java Virtual Machine (JVM) handles it.
Background process: The GC runs in the background, periodically scanning the heap to find unused objects.
Reachability analysis: GC uses a graph of object references starting from “roots” (like local variables, static fields, and active threads). If an object cannot be reached from any root, it is considered garbage.
Algorithms: The JVM uses different GC algorithms (e.g., Mark-and-Sweep, G1, ZGC) depending on performance requirements.
πΉWhy Memory Management Matters
Even though Java has automatic GC, memory issues can still occur if resources are not handled correctly:
Avoiding OutOfMemoryError
If the heap fills up with objects that are still referenced (or not collected quickly enough), the JVM can throw an OutOfMemoryError.
Example: Loading millions of large objects without proper disposal can exhaust heap space.
Preventing Memory Leaks
A memory leak happens when objects are no longer needed but still kept referenced (e.g., in collections like List or Map).
GC cannot collect these objects, leading to gradual memory exhaustion.
Example: Forgetting to remove old listeners, cache entries, or closing database connections.
π In short: Garbage collection in Java automates memory cleanup, reducing developer burden and errors. Still, developers must write mindful code to avoid memory leaks and manage resources properly, or they risk OutOfMemoryError and performance issues.
πΉ JVM Memory Architecture Overview
When a Java program runs, the JVM divides memory into different runtime areas. These ensure that objects, variables, and methods are managed efficiently.
1. Heap Memory
Heap is the runtime area where all objects are stored. It is shared among all threads.It is further divided into generations to optimize garbage collection:
Young Generation
Where new objects are created.
Further divided into:
Eden Space β New objects are allocated here first.
Survivor Spaces (S0, S1) β Objects that survive garbage collection in Eden are moved here.
Frequent garbage collections happen here (Minor GC).
Old Generation (Tenured)
Stores long-lived objects that survived multiple GC cycles.
Garbage collection here is less frequent but more expensive (Major GC / Full GC).
Metaspace (Java 8+)
Replaced PermGen.
Stores class metadata (class definitions, method info, static variables).
Grows dynamically, unlike the fixed-size PermGen.
2. Stack Memory
Each thread has its own stack.
Stores:
Method call frames.
Local variables (including primitives).
References to objects (but not the objects themselves).
When a method is invoked, a new frame is pushed; when the method ends, the frame is popped.
If stack space runs out (e.g., due to deep recursion), a StackOverflowError occurs.
3. Other Areas (briefly)
Program Counter (PC) Register: Holds the address of the currently executing instruction for each thread.
Native Method Stack: Supports execution of native (non-Java) code.
Other parts like PC Register and Native Stack support execution.
πΉWays to Make an Object Eligible for Garbage Collection :
Nullifying the reference variable
Reassign the reference variable
Objects created inside a metho
β 1. Nullifying the reference variable
If an object is no longer required, you can make it eligible for GC by assigning null to its reference variable:
Student s1 = new Student();
s1 = null; // Now eligible for GC
β 2.Reassigning the reference variable
If a reference variable is reassigned to point to another object, the old object becomes unreachable and eligible for Garbage Collection(GC).
Student s1 = new Student();
Student s2 = new Student();
s1 = s2; // Old s1 object is now eligible for GC
β 3.Objects created inside a method
Objects created inside a method are eligible for Garbage Collection (GC) once the method completes, provided there are no references to them outside the method:
void myMethod() {
MyClass obj = new MyClass();
// obj is eligible for GC after method execution
}
Example:
class MyClass {
int id;
MyClass(int id) {
this.id = id;
System.out.println("Object " + id + " created");
}
// finalize() is deprecated after Java 9,
// but here we use it only for demonstration
@Override
protected void finalize() throws Throwable {
System.out.println("Object " + id + " is garbage collected");
}
}
public class GCDemo {
public static void main(String[] args) {
createObject();
// Requesting JVM to run GC
System.gc();
// Adding delay to give GC some time
try { Thread.sleep(1000); } catch (InterruptedException e) {}
System.out.println("End of main method");
}
static void createObject() {
MyClass obj = new MyClass(1);
// After this method ends, 'obj' goes out of scope
// and becomes eligible for Garbage Collection
}
}
Explanation
Inside createObject()
obj is a local variable referring to a MyClass object.
When the method finishes, the variable obj goes out of scope.
After method execution
No references to that object remain.
Hence, the object becomes eligible for Garbage Collection.
System.gc() call
Requests JVM to run the GC.
If the JVM runs GC, the overridden finalize() method is called, and youβll see:
Object 1 is garbage collected
β Ways for Requesting the JVM to Run Garbage Collector
Although you cannot force garbage collection, you can request it using the folowing methods:
β System.gc()
A static method in the System class that requests GC.
System.gc()
System.gc() method is used to call the garbage collector to perform clean-up processing.
β Runtime.getRuntime().gc()
The Runtime class, present in the java.lang package, is a singleton that provides the gc() method through the getRuntime() factory method.
Runtime.getRuntime().gc();
π Both methods are (System.gc() and Runtime.getRuntime().gc() )equivalent, but the JVM is not obligated to perform garbage collection immediately.
Quest : Can Garbage Collection be forced?
β No. Garbage Collection cannot be forced. You can only request it, but the JVM decides when (or if) it will actually run.
β Finalization (β οΈ Deprecated)
Before destroying an object, the Garbage Collector (GC) once invoked the finalize() method to perform cleanup activities.
The finalize() method is defined in the Object class:
β οΈ Note: Since Java 9, the finalize() method has been deprecated and its use is strongly discouraged. Developers should instead use alternatives such as try-with-resources or implement the AutoCloseable interface for cleanup tasks.
try-with-resources for automatic resource management, or
AutoCloseable interface for cleanup tasks.
β Memory Leak
A memory leak occurs when an object is no longer needed by the application but is still being referenced. This prevents GC from reclaiming it, leading to unnecessary memory consumption.
This results in unnecessary memory consumption and may cause the application to slow down or even crash.
β Common Causes of OutOfMemoryError(OOM) in JVM
When the JVM runs out of memory and cannot allocate more objects or native resources, it throws an OutOfMemoryError. This can happen in several scenarios depending on how the application uses memory.
The Java Virtual Machine (JVM) is a virtual machine that provides the runtime environment to execute Java bytecode. The JVM does not understand Java source code directly. Thatβs why .java files are first compiled into .class files containing bytecode, which the JVM can interpret and execute.This bytecode is platform-independent and can run on any machine with a compatible JVM. The JVM is responsible for controlling the execution of every Java program and enables important features such as automatic memory management and security.
The JVM architecture consists of several key components that work together to execute Java programs:
1.Class Loader
The Class Loader loads classes into memory for execution.
There are three main types of class loaders:
Boot Strap ClassLoader β Loads core Java classes from rt.jar file (inside JRE/lib). It has the highest priority.
Extension ClassLoader β β Loads classes from the ext directory (jre/lib/ext).
Application (System) ClassLoader β Loads classes from the applicationβs classpath (environment variables, project paths, etc.).
3.Method Area
Stores class-level data such as class structures, metadata, method code, and static variables. There is only one Method Area per JVM instance.
3.Heap
Stores all Java objects, their instance variables, and arrays. The heap is shared among all threads, and hence the data stored here is not thread-safe by default.
4.JVM Stack
Each thread has its own JVM stack, created when the thread starts. It stores:
Local variables
Partial results
Method call frames (each frame holds data, local variables, and references to objects in the heap
5.Program Counter (PC) Register
Each thread has its own PC register. It holds the address of the current JVM instruction being executed.
6.Native Method Stack
Contains instructions for native methods (non-Java code, usually written in C/C++). It supports interaction between Java applications and platform-specific native libraries.
7.Execution Engine
The Execution Engine runs the bytecode. It consists of:
Interpreter β Executes bytecode line by line (simple but slower).
JIT (Just-In-Time) Compiler β Improves performance by compiling frequently used bytecode into native machine code.
Garbage Collector (GC) β Automatically manages memory by removing unused objects from the heap
8.Native Method Interface (JNI)
Acts as a bridge between Java code and native applications/libraries (C, C++, etc.), allowing Java to call platform-specific methods.
9.Native Method Libraries
A collection of native libraries required by the Execution Engine. These are loaded and linked using the JNI.
πKey Features of JVM
Provides platform independence by executing bytecode on any system.
Ensures memory management with garbage collection.
Handles runtime exceptions automatically.
Supports integration with native libraries through JNI.
β Go to My Computer / This PC icon on your desktop (or File Explorer). Right-click on it and select Properties.
β In the System window, click on Advanced system settings.
β In the System Properties dialog box, click on the Advanced tab.
β Click the Environment Variables button.
β Under System Variables, click on the New button.
β A dialog box will appear. Donβt close it.
β Open My Computer / This PC β C:\Program Files\Java\jdk1.8.0_144\bin (navigate to your installed JDK folder). Copy this full path:
C:\Program Files\Java\jdk1.8.0_144\bin
β Go back to the New System Variable dialog box.In Variable Name, type : Path and In Variable Value, paste the copied path:
C:\Program Files\Java\jdk1.8.0_144\bin
π If there are already other values in the Path variable, donβt delete them β instead, click Edit and add a semicolon (;) at the end of the existing values, then paste your Java path.
TheisEnum() method in Java, available in the java.lang.Class class, is used to check whether a given Class object represents an enumeration type.
If the class represents an enum, the method returns true, otherwise, it returns false.
This method is particularly useful in reflection-based programming, where enums need to be verified or processed dynamically (for example, in frameworks, libraries, or configuration systems).
Syntax :
public boolean isEnum()
β Parameters
This method takes no parameters.
β Returns
true β if the class object represents an enum type.
false β if the class object is not an enum type.
Understanding of isEnum():
The method allows developers to check at runtime whether a class is an enum.This can be very useful when you want to dynamically handle enums (for example, iterating through their constants, generating dropdown options, or validating user inputs).
Example 1: Basic Usage
public class IsEnumExample {
public static void main(String[] args) {
Class<PaymentStatus> clazz = PaymentStatus.class;
boolean result = clazz.isEnum();
System.out.println("Is PaymentStatus an enum? " + result);
}
public enum PaymentStatus {
PENDING, PROCESSING, SUCCESS, FAILED
}
}
Output :
Is PaymentStatus an enum? true
β π Here, PaymentStatusis an enum, so isEnum() returns true.
Example 2: Checking a Non-Enum Class
public class NonEnumExample {
public static void main(String[] args) {
Class<Integer> clazz = Integer.class;
boolean result = clazz.isEnum();
System.out.println("Is Integer an enum? " + result);
}
}
Output:
Is Integer an enum? false
Note :π Since Integeris not an enum, the result is false.
πKey Ponts:
The Class.isEnum() method provides a reliable way to identify enums at runtime.
It returns true for enums and false otherwise.
Itβs often used in reflection-based frameworks to dynamically handle enums for configuration, validation, or UI generation.
This makes it an important tool when building generic and reusable libraries.
Enums were introduced in Java 5 (JDK 1.5) as a way to define a collection of named constants in a type safe manner. Unlike enums in older languages (like C or C++), Java enums are far more powerful since they are implemented using class concepts and can contain constructors, methods, and variables.
β What is an Enum?
Enum is a special data type used to define a group of named constants.
Each enum constant is implicitly:
public, static, and final.
Enums make the code readable, maintainable, and less error-prone compared to using intor Stringconstants.
Example :
enum Month {
JAN,FEB,MAR,DEC;
}
β Internal Implementation of Enum
Internally, an enum is implemented as a class.
Every enum constant is a reference variable that points to its own enum object.
You can think of enums as a fixed set of static final objects.
Enum Declaration and Usage :
enum Month{
JAN, FEB, MAR, DEC; // semicolon at the end is optional if no extra members
}
class Test {
public static void main(String[] args) {
Month mon = Month.FEB;
System.out.println(mon);
}
}
Output:
FEB
π Note: Since enum constants are implicitly static, we can access them using EnumName.CONSTANT.
β Enum with Switch Statement :
Before Java 5, switchallowed only byte,short,char,int(and their wrappers). From Java 5 onwards, enumtypes can also be used in a switch.
enum PaymentStatus {
PENDING, PROCESSING, SUCCESS, FAILED;
}
class Test {
public static void main(String[] args) {
PaymentStatus status = PaymentStatus.PROCESSING;
switch (status) {
case PENDING:
System.out.println("Payment is pending. Please wait...");
break;
case PROCESSING:
System.out.println("Payment is being processed. Do not refresh the page.");
break;
case SUCCESS:
System.out.println("Payment successful! Thank you for your purchase.");
break;
case FAILED:
System.out.println("Payment failed. Please try again.");
break;
default:
System.out.println("Unknown payment status.");
}
}
}
Example:
Output :
Payment is being processed. Do not refresh the page.
π Every caselabel must be a valid enum constant, otherwise youβll get a compile-time error.
β Enum and Inheritance
Every enum in Java is implicitly a child of java.lang.Enum.
Hence, enums cannot extend other classes.
Enums are implicitly final, so they cannot be extended.
But enums can implement interfaces.
β Useful Enum Methods
values() β returns all constants as an array.
ordinal() β returns the index (zero-based position) of the constant.
valueOf(String name) β returns the enum constant with the specified name
Enum values():
The values() method is a built-in static method that is automatically added by the Java compiler for every enum. π It returns an array of all the constants defined in the enum, in the order they are declared.
Return type: EnumType[]
π Syntax :
public static EnumType[] values()
β Why Use values()?
To iterate over all enum constants.
Useful when you want to display options, validate input, or implement logic based on all possible values.
Example :
public enum Day {
MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY;
}
public class EnumExample {
public static void main(String[] args) {
Day[] days = Day.values(); // Calls the values() method
for (Day day : days) {
System.out.println(day);
}
}
}
The ordinal() method is a built-in method provided by Java for enum constants. π It returns the position (index) of the enum constant in its declaration, starting from 0.
Return type: int
π Syntax :
int ordinal()
β Why Use ordinal()?
To get the relative position of a constant in the enum.
It is helpful when you need the position or order of the enum constant (e.g., for iteration, comparison, or sorting purposes). β οΈ However, avoid using ordinal() for persistent logic (e.g., storing in databases) because adding or reordering constants changes ordinal values.
Example :
public enum Priority {
LOW, MEDIUM, HIGH, CRITICAL;
}
public class OrdinalExample {
public static void main(String[] args) {
for (Priority level : Priority.values()) {
System.out.println(level + " has ordinal: " + level.ordinal());
}
}
}
Output :
LOW has ordinal: 0
MEDIUM has ordinal: 1
HIGH has ordinal: 2
CRITICAL has ordinal: 3
π Notes :
β οΈ Donβt use ordinal() for business logic that persists data (e.g., database values), because adding/reordering enum constants changes their ordinal values, which breaks the logic.
valueOf(String name)
The valueOf(String name) method is a static method automatically provided by the Java compiler for every enum. π It returns the enum constant that exactly matches the given string name
Returns the enum constant with the specified name.
The name must exactly match the declared constant (case-sensitive).
Return type: EnumType
Use case: Useful for converting a string into the corresponding enum constant.
π Syntax :
public static EnumType valueOf(String name)
β Why Use valueOf(String name) in Enum?
The valueOf(String name) method is used to convert a String into its corresponding Enum constant.
β Key Use Cases:
User Input Conversion When a user provides input as a string (e.g., from a form, API, or command line), you can convert it to the corresponding enum constant for type-safe processing.
Configuration Parsing Configuration files often store values as strings. Using valueOf(), you can convert these string values into enums for easy and reliable usage in your code.
Validation Instead of using complex if-else chains to validate a string against a predefined set of constants, valueOf() allows direct validation by attempting the conversion (and handling exceptions if invalid).
Example :
public enum Day {
MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY;
}
public class ValueOfExample {
public static void main(String[] args) {
String input = "FRIDAY";
// Convert String to Enum constant
Day day = Day.valueOf(input);
System.out.println("Enum constant from String: " + day);
}
}
Output :
Enum constant from String: FRIDAY
β οΈ Important Note:
β The input string must match the enum constant name exactly (case-sensitive).
β Otherwise, it throws IllegalArgumentException
"monday" (lowercase) would fail because enum names are case-sensitive.
null input throws NullPointerException.
β So yes, valueOf(String name) is always available for enums in Java, either via the compiler-generated method or the generic Enum.valueOf() method.
πNote :
ordinal() is defined in the java.lang.Enum class.
valueOf(String) is also defined in the Enum class.
values() is not defined in Enum; instead, it is a synthetic method automatically generated by the compiler for each enum type. Thatβs why you wonβt find it in the JDK source of Enum.
β Key Differences :
Feature
ordinal()
valueOf(String name)
values()
Purpose
Returns index (position) of constant
Returns enum constant by its name
Returns an array of all enum constants
Return Type
int
Enum type itself
Enum array (EnumType[])
Input
No input (called on enum constant)
Takes String argument
No input (called on enum type)
Example Usage
Day.MONDAY.ordinal()β0
Day.valueOf("MONDAY") β Day.MONDAY
Day.values() β [MONDAY, TUESDAY, β¦]
Risk
Changes if enum order is modified
Throws IllegalArgumentException if not found
None (safe, but array order depends on enum order)
β Enum with Constructors and Fields
Enums in Java are more powerful than simple lists of constants.
π You can define fields, constructors, and methods inside an enum to associate additional data with each constant.
πEach enum constant is actually an object, and constructors are executed at class loading time.
β Why Use Enum Fields and Constructors?
To store additional information (metadata) for each enum constant.
Helps model real-world entities more effectively.
Makes the code cleaner, avoids external mappings (e.g., maps or switch cases).
π Syntax
public enum EnumName {
CONSTANT1(value1),
CONSTANT2(value2);
private DataType field; // Field to store additional data
// Constructor
EnumName(DataType field) {
this.field = field;
}
// Getter
public DataType getField() {
return field;
}
}
Example :
Step 1 β Define the Enum(UserRole.java)
public enum UserRole {
ADMIN(1, "Full access to all system features"),
MODERATOR(2, "Can manage user content and moderate discussions"),
USER(3, "Standard user with limited access"),
GUEST(4, "Read-only access to public content");
private final int accessLevelCode;
private final String description;
// Constructor
UserRole(int accessLevelCode, String description) {
this.accessLevelCode = accessLevelCode;
this.description = description;
}
// Getters
public int getAccessLevelCode() {
return accessLevelCode;
}
public String getDescription() {
return description;
}
}
Step 2 β Using the Enum in Application(UserAccessTest.java)
public class UserAccessTest {
public static void main(String[] args) {
UserRole userRole = UserRole.MODERATOR;
System.out.println("User Role: " + userRole);
System.out.println("Access Level Code: " + userRole.getAccessLevelCode());
System.out.println("Description: " + userRole.getDescription());
// Display all Access Levels
System.out.println("\nAll Access Levels:");
for (UserRole role : UserRole.values()) {
System.out.printf("%s (%d): %s%n",
role, role.getAccessLevelCode(), role.getDescription());
}
}
}
Output :
User Role: MODERATOR
Access Level Code: 2
Description: Can manage user content and moderate discussions
All Access Levels:
ADMIN (1): Full access to all system features
MODERATOR (2): Can manage user content and moderate discussions
USER (3): Standard user with limited access
GUEST (4): Read-only access to public content
π Note :
π You cannot create enum objects manually (new UserRole() is not allowed). They are created internally at load time.
π This way, each UserRole constant represents a real application role with an access level (like permissions in a system).
β Why Is This Useful in Real Applications?
Instead of hardcoding access levels, this enum stores both a code (levelCode) and a description.
Helps manage user permissions in a type-safe and centralized way.
Easy to display in UI (dropdowns) or use in logic:
if (userAccess == AccessLevel.ADMIN) {
System.out.println("Grant full system access");
}
πNote : Using fields and constructors in enums makes your code cleaner and models real-world scenarios more effectively than plain enums or constants.
β Enum with Methods
An enum in Java can have fields, constructors, and methods just like a regular class.
π Methods allow adding behavior to enums, making them powerful for modeling real-world concepts.
πEnums can override methods just like classes.
β Why Use Methods in Enum?
To provide logic related to the enum constants.
Avoids switch-case or if-else statements scattered across the code.
Encourages encapsulation and clean code structure.
π Syntax :
public enum EnumName {
CONSTANT1, CONSTANT2;
// Custom method
public ReturnType methodName() {
// Logic
}
}
Enum Example with Methods and Override
public enum NotificationType {
EMAIL {
@Override
public void send() {
System.out.println("Sending Email Notification...");
}
},
SMS {
@Override
public void send() {
System.out.println("Sending SMS Notification...");
}
},
PUSH {
// Uses default implementation
};
// Default behavior
public void send() {
System.out.println("Sending Push Notification...");
}
}
//Main class
public class Test {
public static void main(String[] args) {
for (NotificationType type : NotificationType.values()) {
type.send();
}
}
}
Each enum constant (EMAIL, SMS) overrides the send() method with its own implementation.
The PUSH constant uses the default implementation of send().
This pattern is useful when different constants require different behaviors.
β Static Import with Enum
What Is Static Import in Java?
Normally, to access enum constants, you use the full reference like:
Day.MONDAY
π The static import feature allows you to import static members (including enum constants) directly, so you donβt need to prefix them with the enum type every time.
π You can use static imports to avoid qualifying enum constants.
β Why Use Static Import with Enum?
π Improves code readability by avoiding repetitive enum type references.
π Makes code cleaner when using enums frequently (like in switch cases or comparisons).
π Syntax of Static Import
import static packageName.EnumType.*;
This imports all enum constants statically.
Or, import a specific constant:
import static packageName.EnumType.CONSTANT_NAME;
Example :
package pack1;
public enum Fish {
STAR, GUPPY;
}
package pack2;
import static pack1.Fish.*;
class A {
public static void main(String[] args) {
System.out.println(STAR);
System.out.println(GUPPY);
}
}
Valid imports:
import static pack1.Fish.*; β
import static pack1.Fish.STAR; β
Invalid imports:
import pack1.*; β
import pack1.Fish; β
πImportant
β οΈ Avoid overusing static imports for large enums in complex projects, as it can reduce code clarity if multiple enums have overlapping constant names.
β Recommended for enums with small, well-defined constants frequently used in the same context.
π―Key Points (Latest Java Versions β )
Enums are type-safe constants.
They can have fields, methods, and constructors.
They cannot extend other classes, but can implement interfaces.
Enums are thread-safe since all constants are created at class loading.