Think of a variable as a labeled box in your computer’s memory. You give the box a name, decide what kind of thing it can hold, and then put a value inside it. Later, you can look at the value, change it, or pass it along to another part of your program.
More formally, a variable is a named memory location that stores a value of a specific data type. Every Java program you write will be full of variables, so understanding them deeply is one of the most important steps in becoming a strong developer.
// A simple variable: a labeled box named "age" that holds the integer 30 int age = 30; System.out.println(age); // Output: 30
In Java, creating a variable is a two-part process: declaration and initialization. You can do them separately or on the same line.
Declaration tells the compiler: “Reserve a spot in memory with this name and this type.”
Initialization tells the compiler: “Put this value in that spot.”
The general syntax is:
type name = value;
// Declaration and initialization on the same line String firstName = "Folau"; int numberOfItems = 42; double accountBalance = 1250.75; boolean isActive = true; // Declaration first, initialization later String lastName; lastName = "Kaveinga"; // Declaring multiple variables of the same type on one line int x = 1, y = 2, z = 3; System.out.println(firstName); // Output: Folau System.out.println(lastName); // Output: Kaveinga System.out.println(numberOfItems); // Output: 42 System.out.println(accountBalance); // Output: 1250.75 System.out.println(isActive); // Output: true System.out.println(x + y + z); // Output: 6
A variable has three essential parts:
1. Type – What kind of data it holds (int, String, double, boolean, etc.)
2. Name – The label you use to refer to it in your code
3. Value – The actual data stored in memory
The equals sign (=) is the assignment operator. It takes the value on the right and stores it in the variable on the left. This is not the same as mathematical equality. It means “assign this value to this variable.”
// The assignment operator in action String firstName = "Folau"; System.out.println(firstName); // Output: Folau // Reassigning a new value to the same variable firstName = "Lisa"; System.out.println(firstName); // Output: Lisa // The old value "Folau" is gone. The box now holds "Lisa".
Java has three categories of variables based on where they are declared. Understanding the differences is critical because it affects their lifetime, default values, and visibility.
Local variables are declared inside a method, constructor, or block. They exist only while that method or block is executing, and they are destroyed once execution leaves that scope.
Key facts about local variables:
– They must be initialized before use. Java will not assign a default value. If you try to use an uninitialized local variable, the compiler will throw an error.
– They are not accessible outside the method or block where they are declared.
– They cannot have access modifiers (public, private, protected) because they belong to the method, not the class.
public class LocalVariableExample {
public void calculateTotal() {
// These are local variables - they exist only inside this method
int quantity = 5;
double pricePerItem = 19.99;
double total = quantity * pricePerItem;
System.out.println("Total: $" + total); // Output: Total: $99.95
}
public void anotherMethod() {
// This will NOT compile - "total" does not exist here
// System.out.println(total); // ERROR: cannot find symbol
// You must declare your own variables in this scope
double total = 0.0;
System.out.println("Total: $" + total); // Output: Total: $0.0
}
public static void main(String[] args) {
LocalVariableExample example = new LocalVariableExample();
example.calculateTotal();
example.anotherMethod();
}
}
Instance variables are declared inside a class but outside any method. Each object (instance) of the class gets its own copy of these variables. If you create three Person objects, each one has its own separate name and age.
Key facts about instance variables:
– They receive default values if you do not initialize them (0 for numbers, false for booleans, null for objects).
– They exist as long as the object exists.
– They can have access modifiers (private, public, protected).
public class Person {
// Instance variables - each Person object gets its own copy
private String name;
private int age;
private String email;
public Person(String name, int age, String email) {
this.name = name;
this.age = age;
this.email = email;
}
public void introduce() {
System.out.println("Hi, I'm " + name + ", age " + age);
}
public static void main(String[] args) {
// Two separate objects, each with their own instance variables
Person person1 = new Person("Folau", 30, "folau@example.com");
Person person2 = new Person("Lisa", 28, "lisa@example.com");
person1.introduce(); // Output: Hi, I'm Folau, age 30
person2.introduce(); // Output: Hi, I'm Lisa, age 28
// Changing person1's name does NOT affect person2
// Each object owns its own copy of the instance variables
}
}
Static variables are declared with the static keyword inside a class but outside any method. Unlike instance variables, there is only one copy shared across all instances of the class. If one object changes a static variable, every other object sees the change.
Static variables are perfect for values that should be the same for every instance, such as a counter that tracks how many objects have been created, or a configuration value shared by the whole application.
public class Employee {
// Static variable - shared by ALL Employee objects
private static int employeeCount = 0;
private static String companyName = "LoveMeSomeCoding";
// Instance variables - each Employee gets its own copy
private String name;
private int id;
public Employee(String name) {
this.name = name;
employeeCount++; // Increment the shared counter
this.id = employeeCount; // Assign a unique ID
}
public void displayInfo() {
System.out.println("ID: " + id + ", Name: " + name + ", Company: " + companyName);
}
public static int getEmployeeCount() {
return employeeCount;
}
public static void main(String[] args) {
Employee emp1 = new Employee("Folau");
Employee emp2 = new Employee("Lisa");
Employee emp3 = new Employee("James");
emp1.displayInfo(); // Output: ID: 1, Name: Folau, Company: LoveMeSomeCoding
emp2.displayInfo(); // Output: ID: 2, Name: Lisa, Company: LoveMeSomeCoding
emp3.displayInfo(); // Output: ID: 3, Name: James, Company: LoveMeSomeCoding
// The static variable is shared - all three objects see the same count
System.out.println("Total employees: " + Employee.getEmployeeCount());
// Output: Total employees: 3
}
}
Scope defines where a variable can be accessed in your code. Once you leave a variable’s scope, it no longer exists. Java has three levels of scope you need to understand.
A variable declared inside a pair of curly braces { } only exists within those braces. This includes if-statements, for-loops, while-loops, and any other block.
A variable declared at the top of a method is accessible anywhere within that method, but not outside of it. Method parameters also have method scope.
Instance and static variables have class scope. They are accessible from any method within the class (and potentially from outside the class, depending on their access modifier).
public class ScopeDemo {
// Class scope - accessible from any method in this class
private String classLevelVar = "I'm available everywhere in this class";
public void demonstrateScope() {
// Method scope - accessible anywhere in this method
int methodLevelVar = 100;
System.out.println(classLevelVar); // OK - class scope
System.out.println(methodLevelVar); // OK - method scope
if (methodLevelVar > 50) {
// Block scope - only exists inside this if-block
String blockLevelVar = "I only exist inside this if-block";
System.out.println(blockLevelVar); // OK - we are inside the block
System.out.println(methodLevelVar); // OK - method scope is wider
}
// This will NOT compile - blockLevelVar is out of scope
// System.out.println(blockLevelVar); // ERROR: cannot find symbol
for (int i = 0; i < 3; i++) {
// "i" only exists inside this for-loop
System.out.println("Loop index: " + i);
}
// This will NOT compile - "i" is out of scope
// System.out.println(i); // ERROR: cannot find symbol
}
public void anotherMethod() {
System.out.println(classLevelVar); // OK - class scope
// System.out.println(methodLevelVar); // ERROR - method scope is limited to demonstrateScope()
}
public static void main(String[] args) {
ScopeDemo demo = new ScopeDemo();
demo.demonstrateScope();
}
}
Starting with Java 10, you can use var to let the compiler figure out the type for you. This is called local variable type inference. The compiler looks at the value on the right side of the assignment and determines the type automatically.
Important rules about var:
- var only works with local variables. You cannot use it for instance variables, static variables, or method parameters.
- The variable must be initialized on the same line. The compiler needs the right-hand side to infer the type.
- var is not a keyword technically - it is a reserved type name, so you could still name a variable "var" (though you should not).
- The type is still determined at compile time. Java is still statically typed. var is just syntactic convenience, not dynamic typing.
public class VarExample {
public static void main(String[] args) {
// Without var - explicit types
String name = "Folau";
int age = 30;
List hobbies = new ArrayList<>();
// With var - the compiler infers the types
var name2 = "Lisa"; // Inferred as String
var age2 = 28; // Inferred as int
var hobbies2 = new ArrayList(); // Inferred as ArrayList
System.out.println(name2.getClass().getSimpleName()); // Output: String
System.out.println(((Object) age2).getClass().getSimpleName()); // Output: Integer
// var is great for reducing verbosity with long type names
var employeeMap = new HashMap>();
// Without var, that same line would be:
// HashMap> employeeMap = new HashMap>();
// These will NOT compile:
// var x; // ERROR: cannot infer type - no initializer
// var y = null; // ERROR: cannot infer type - null has no type
}
}
A good rule of thumb: use var when the type is obvious from the right-hand side of the assignment. If it makes the code harder to read, stick with the explicit type.
If you have a value that should never change after it is set, mark it with the final keyword. Once assigned, a final variable cannot be reassigned. This is how you create constants in Java.
By convention, constants are named using UPPER_SNAKE_CASE (all uppercase letters with underscores between words). When combined with the static keyword, a final variable becomes a true class-level constant shared across all instances.
public class ConstantExample {
// Class-level constants: static + final
// Convention: UPPER_SNAKE_CASE
public static final double PI = 3.14159265358979;
public static final int MAX_LOGIN_ATTEMPTS = 5;
public static final String DEFAULT_CURRENCY = "USD";
// Instance-level final variable - set once per object, then locked
private final String createdAt;
public ConstantExample() {
this.createdAt = java.time.LocalDateTime.now().toString();
// createdAt cannot be changed after this point
}
public void tryToBreakConstants() {
// This will NOT compile - cannot reassign a final variable
// PI = 3.14; // ERROR: cannot assign a value to final variable PI
// Local final variable
final int maxRetries = 3;
// maxRetries = 5; // ERROR: cannot assign a value to final variable maxRetries
System.out.println("PI: " + PI);
System.out.println("Max login attempts: " + MAX_LOGIN_ATTEMPTS);
System.out.println("Created at: " + createdAt);
}
public static void main(String[] args) {
ConstantExample example = new ConstantExample();
example.tryToBreakConstants();
// Output:
// PI: 3.14159265358979
// Max login attempts: 5
// Created at: 2026-02-28T10:30:00.123456
}
}
When you declare an instance or static variable without assigning a value, Java automatically gives it a default value. This does not apply to local variables. Local variables have no default and must be initialized before use.
Here is the full table of default values:
| Data Type | Default Value |
|---|---|
| byte | 0 |
| short | 0 |
| int | 0 |
| long | 0L |
| float | 0.0f |
| double | 0.0 |
| char | '\u0000' (null character) |
| boolean | false |
| Any object (String, arrays, etc.) | null |
public class DefaultValueDemo {
// Instance variables with no explicit initialization
int number;
double decimal;
boolean flag;
char character;
String text;
int[] numbers;
public void printDefaults() {
System.out.println("int default: " + number); // Output: 0
System.out.println("double default: " + decimal); // Output: 0.0
System.out.println("boolean default: " + flag); // Output: false
System.out.println("char default: [" + character + "]"); // Output: [ ] (null character)
System.out.println("String default: " + text); // Output: null
System.out.println("Array default: " + numbers); // Output: null
}
public void localVariableExample() {
int localNumber;
// This will NOT compile - local variables have no default value
// System.out.println(localNumber); // ERROR: variable localNumber might not have been initialized
// You must assign a value first
localNumber = 10;
System.out.println(localNumber); // Output: 10
}
public static void main(String[] args) {
DefaultValueDemo demo = new DefaultValueDemo();
demo.printDefaults();
demo.localVariableExample();
}
}
Java enforces specific rules about what constitutes a valid variable name. If you break these rules, your code will not compile.
Rule 1: Variable names can contain letters, digits, underscores (_), and dollar signs ($).
// Valid names using allowed characters int age = 25; int _count = 10; int $price = 99; int item2 = 5; // Invalid - contains special characters that are not allowed // int my-variable = 1; // ERROR: '-' is not allowed // int my variable = 1; // ERROR: spaces are not allowed // int my@name = 1; // ERROR: '@' is not allowed
Rule 2: Variable names must begin with a letter, underscore, or dollar sign. They cannot start with a digit.
// Valid - starts with a letter, underscore, or dollar sign int age = 25; int _hidden = 0; int $amount = 100; // Invalid - starts with a digit // int 10things = 10; // ERROR: cannot start with a digit // int 1stPlace = 1; // ERROR: cannot start with a digit
Rule 3: Variable names are case-sensitive. The variables firstName and firstname are two completely different variables.
String firstName = "Folau"; // 'N' is uppercase String firstname = "Lisa"; // 'n' is lowercase // These are two separate variables System.out.println(firstName); // Output: Folau System.out.println(firstname); // Output: Lisa
Rule 4: Variable names cannot be Java reserved keywords. Words like int, double, class, static, public, return, and about 50 others are reserved for the language itself.
// Invalid - these are reserved keywords // int class = 5; // ERROR: 'class' is a keyword // int static = 10; // ERROR: 'static' is a keyword // int return = 0; // ERROR: 'return' is a keyword // String double = ""; // ERROR: 'double' is a keyword // Valid - similar but not identical to keywords int classCount = 5; int staticValue = 10; String returnMessage = "success";
Rule 5: Variable names cannot contain whitespace.
// Invalid - contains spaces // String first name = "Folau"; // ERROR: spaces not allowed // Valid alternatives String firstName = "Folau"; // camelCase (preferred in Java) String first_name = "Folau"; // snake_case (works but not standard Java style)
Beyond the rules the compiler enforces, the Java community follows strong naming conventions. These are not required for your code to compile, but following them makes your code professional and readable. In a team environment, consistent naming is expected.
In Java, the standard convention is camelCase: start with a lowercase letter, and capitalize the first letter of each subsequent word. This is different from Python and C, which commonly use snake_case.
// Correct - camelCase (Java convention) String firstName = "Folau"; int numberOfStudents = 42; double accountBalance = 1500.00; boolean isLoggedIn = true; // Avoid - snake_case is not standard Java style // String first_name = "Folau"; // int number_of_students = 42;
Variables declared with static final should use all uppercase letters with underscores separating words.
// Correct - UPPER_SNAKE_CASE for constants public static final int MAX_RETRY_COUNT = 3; public static final String BASE_URL = "https://lovemesomecoding.com"; public static final double TAX_RATE = 0.08; // Incorrect - inconsistent style // public static final int maxRetryCount = 3; // looks like a regular variable // public static final int Max_Retry_Count = 3; // mixed style
Great developers write code that reads like a story. A variable name should tell you exactly what it represents without needing a comment. Do not abbreviate unless the abbreviation is universally understood (like "id" or "url").
// Good - clear and descriptive int numberOfStudents = 30; double monthlyPayment = 1200.50; String customerEmailAddress = "folau@example.com"; boolean hasActiveSubscription = true; List<String> pendingOrderIds = new ArrayList<>(); // Bad - vague, abbreviated, or lazy int n = 30; // What does "n" mean? double mp = 1200.50; // Unclear abbreviation String cea = ""; // Unreadable boolean flag = true; // Flag for what? List<String> list = new ArrayList<>(); // List of what?
Boolean variables should read like a yes/no question. Start them with is, has, can, should, or similar prefixes.
// Good - reads naturally as a true/false question boolean isActive = true; boolean hasPermission = false; boolean canDelete = true; boolean shouldRetry = false; boolean isEligibleForDiscount = true; // Bad - unclear whether it is a boolean or something else boolean active = true; // "active" could be a noun boolean permission = false; // sounds like it holds a permission object boolean delete = true; // sounds like a verb/action
Whatever naming style you choose, stick with it throughout your entire project. If you name one constant NUMBER_OF_PERSONS, do not name the next one Number_Of_Rocks. Consistency makes your codebase predictable and easy to navigate.
Remember: code is written for humans to read. Reading code should be like reading a story. It should flow and make sense. Your variable names are one of the strongest signals of how well you understand the program you are building.
After years of writing Java professionally, here are the mistakes I see most often with variables, along with the practices that strong developers follow.
public void processOrder() {
double total;
// MISTAKE: using "total" before assigning a value
// System.out.println(total); // ERROR: variable total might not have been initialized
// FIX: always initialize local variables
total = 0.0;
System.out.println(total); // Output: 0.0
}
Shadowing happens when a local variable has the same name as an instance variable. This can cause subtle bugs because you might think you are modifying the instance variable when you are actually modifying a local copy.
public class ShadowingExample {
private String name = "Default";
public void setName(String name) {
// MISTAKE: this assigns the parameter to itself, not the instance variable
// name = name; // Does nothing useful!
// FIX: use "this" to refer to the instance variable
this.name = name;
}
public static void main(String[] args) {
ShadowingExample example = new ShadowingExample();
example.setName("Folau");
System.out.println(example.name); // Output: Folau
}
}
Declare variables as close as possible to where they are first used, and in the narrowest scope possible. This makes your code easier to follow and reduces the chance of accidental misuse.
// Bad - declared far from where it is used
public void processOrders(List<Order> orders) {
String status; // Declared here...
double discount; // ...but used 20 lines later
for (Order order : orders) {
// ... lots of code ...
}
status = "complete";
discount = 0.10;
}
// Good - declared right where it is needed
public void processOrders(List<Order> orders) {
for (Order order : orders) {
// ... lots of code ...
}
String status = "complete";
double discount = 0.10;
}
A "magic number" is a raw numeric value in your code with no explanation. Replace them with named constants so the code is self-documenting.
// Bad - what does 5 mean? What does 0.08 mean?
if (loginAttempts > 5) {
lockAccount();
}
double tax = subtotal * 0.08;
// Good - the constants explain themselves
public static final int MAX_LOGIN_ATTEMPTS = 5;
public static final double SALES_TAX_RATE = 0.08;
if (loginAttempts > MAX_LOGIN_ATTEMPTS) {
lockAccount();
}
double tax = subtotal * SALES_TAX_RATE;
1. Always initialize local variables. Do not rely on remembering to set them later.
2. Use the narrowest scope possible. If a variable is only needed inside a loop, declare it inside the loop.
3. Prefer final when a variable should not change. This communicates intent and prevents accidental reassignment.
4. Use meaningful, descriptive names. Spend an extra 10 seconds naming a variable well. It will save you and your teammates hours of confusion later.
5. Follow Java naming conventions. camelCase for variables and methods, UPPER_SNAKE_CASE for constants, PascalCase for class names.
6. Replace magic numbers with named constants. Your future self will thank you.
7. One variable, one purpose. Do not reuse a variable for a different purpose partway through a method. Create a new variable with a descriptive name instead.
Here is a complete, runnable program that demonstrates every concept covered in this tutorial.
public class JavaVariablesTutorial {
// ---- Static (class) variables ----
private static int instanceCount = 0;
public static final String APP_NAME = "LoveMeSomeCoding";
public static final int MAX_USERS = 1000;
// ---- Instance variables (default values if not set) ----
private String username;
private int loginAttempts;
private boolean isActive;
// Constructor
public JavaVariablesTutorial(String username) {
this.username = username;
this.isActive = true;
instanceCount++;
}
// Method demonstrating local variables and scope
public void displayProfile() {
// Local variable - must be initialized
String greeting = "Welcome back, " + username + "!";
System.out.println(greeting);
System.out.println("Active: " + isActive);
System.out.println("Login attempts: " + loginAttempts); // default value: 0
// Block scope
if (isActive) {
String status = "Status: Online";
System.out.println(status);
}
// "status" is no longer accessible here
// var keyword (Java 10+)
var totalUsers = instanceCount;
System.out.println("Total users created: " + totalUsers);
}
// Method demonstrating final (local constant)
public boolean canLogin() {
final int maxAttempts = 5;
return loginAttempts < maxAttempts;
}
public void attemptLogin() {
if (canLogin()) {
loginAttempts++;
System.out.println(username + " logged in. Attempts: " + loginAttempts);
} else {
System.out.println(username + " is locked out!");
}
}
public static void main(String[] args) {
System.out.println("App: " + APP_NAME);
System.out.println("Max users allowed: " + MAX_USERS);
System.out.println("---");
// Create instances - each has its own instance variables
JavaVariablesTutorial user1 = new JavaVariablesTutorial("Folau");
JavaVariablesTutorial user2 = new JavaVariablesTutorial("Lisa");
user1.displayProfile();
System.out.println("---");
user2.displayProfile();
System.out.println("---");
// Demonstrate login attempts (instance variable tracks per user)
user1.attemptLogin();
user1.attemptLogin();
user2.attemptLogin();
System.out.println("---");
System.out.println("Total instances created: " + instanceCount);
}
}
/*
* Output:
* App: LoveMeSomeCoding
* Max users allowed: 1000
* ---
* Welcome back, Folau!
* Active: true
* Login attempts: 0
* Status: Online
* Total users created: 2
* ---
* Welcome back, Lisa!
* Active: true
* Login attempts: 0
* Status: Online
* Total users created: 2
* ---
* Folau logged in. Attempts: 1
* Folau logged in. Attempts: 2
* Lisa logged in. Attempts: 1
* ---
* Total instances created: 2
*/
Variables are the foundation of every Java program. Here is what you should take away from this tutorial:
A variable is a named memory location with a type, a name, and a value.
Local variables live inside methods and must be initialized before use. Instance variables belong to objects and get default values. Static variables are shared across all instances of a class.
Scope determines where a variable is visible: block, method, or class level. Always use the narrowest scope possible.
The var keyword (Java 10+) lets the compiler infer the type of local variables from their initializer.
The final keyword makes a variable a constant that cannot be reassigned.
Follow naming conventions consistently: camelCase for variables, UPPER_SNAKE_CASE for constants. Choose clear, descriptive names that make your code read like a well-written story.
Master these fundamentals and you will have a rock-solid foundation for everything else in Java.