-- JLS §4.12: Variable Declarations --
-- Variables are declared via FieldDeclaration, LocalVariableDeclaration,
-- FormalParameter, ExceptionParameter, PatternVariable, etc.
-- JLS §8.3: Field Declarations --
FieldDeclaration:
{FieldModifier} UnannType VariableDeclaratorList ;
FieldModifier:
Annotation
public | protected | private
static | final | transient | volatile
UnannType:
UnannPrimitiveType
UnannReferenceType
VariableDeclaratorList:
VariableDeclarator { , VariableDeclarator }
VariableDeclarator:
VariableDeclaratorId [= VariableInitializer]
VariableDeclaratorId:
Identifier [Dims]
VariableInitializer:
Expression
ArrayInitializer
-- JLS §14.4: Local Variable Declaration Statements --
LocalVariableDeclaration:
{VariableModifier} LocalVariableType VariableDeclaratorList
LocalVariableDeclarationStatement:
LocalVariableDeclaration ;
LocalVariableType:
UnannType
var
VariableModifier:
Annotation
final
-- JLS §8.4.1: Formal Parameters --
FormalParameter:
{VariableModifier} UnannType VariableDeclaratorId
VariableArityParameter
VariableArityParameter:
{VariableModifier} UnannType {Annotation} ... Identifier
-- JLS §14.20: Exception Parameters --
CatchFormalParameter:
{VariableModifier} CatchType VariableDeclaratorId
CatchType:
UnannClassType { | ClassType }
-- JLS §4.12.4: Final Variables --
-- A variable is effectively final if:
-- 1. It is declared final, OR
-- 2. It is not declared final but is never assigned after initial assignment.
-- JLS §16: Definite Assignment --
-- Every local variable must be definitely assigned before its value is accessed.
-- This is tracked via flow analysis at compile time.
Java has eight kinds of variables: 1. Class variables — static fields; exist from class initialization until unloading. 2. Instance variables — non-static fields; exist from object creation until GC. 3. Array components — unnamed; created with array; destroyed with array. 4. Method parameters — scoped to method body; new binding per invocation. 5. Constructor parameters — scoped to constructor body; new binding per invocation. 6. Lambda parameters — scoped to lambda body. 7. Exception parameters — in catch clause; scoped to catch block. 8. Local variables — declared in method body, constructor body, or initializer block.
Only class/instance variables and array components have default initial values. Local variables do NOT have defaults — using them before assignment is a compile error.
Class variable / instance variable: scope is the entire class body (can refer to it before declaration textually, with restrictions on forward references in initializers).
Method/constructor parameter: scope is the method/constructor body.
Local variable: scope from the declaration point to the end of the enclosing block.
For-loop init variable: scope is the for statement (init + condition + update + body).
Exception parameter: scope is the catch block only.
Pattern variable (Java 16+): scope is the "true" part of the enclosing instanceof expression.
// JLS §6.3: It is illegal to declare a local variable with the same
// name as a local variable or parameter in an enclosing scope:
void foo(int x) {
int x = 0; // compile error: x already defined
{
int x = 1; // compile error: x already defined
}
}
// But: in for-loop init, the variable is a new scope
for (int i = 0; i < 10; i++) { }
for (int i = 0; i < 10; i++) { } // OK: each for creates new scope
classConfig{finalinttimeout;Config(booleanfast){if(fast){timeout=100;}else{timeout=5000;}// OK: exactly one branch assigns timeout in every constructor path}}
Objectobj="hello";if(objinstanceofStrings&&s.length()>3){// s is in scope here — pattern match succeededSystem.out.println(s.toUpperCase());}// s is NOT in scope here
classCounter{privatevolatileintcount=0;// NOT atomic: count++ is read-modify-writevoidincrement(){count++;}// thread-unsafe despite volatile// Atomic with synchronizedsynchronizedvoidsafeIncrement(){count++;}}
// Example 1: Variable Kinds Demonstration// File: VariableKinds.javapublicclassVariableKinds{// Class variable (static field)staticintinstanceCount=0;// Instance variableprivatefinalStringname;privateintvalue;// Constructor parameterpublicVariableKinds(Stringname,intvalue){this.name=name;// 'name' is constructor parameterthis.value=value;instanceCount++;}// Method with local variables and method parameterpublicintcompute(intmultiplier){// 'multiplier' is method parameterintresult=value*multiplier;// 'result' is local variablereturnresult;}publicstaticvoidmain(String[]args){// 'args' is method parameterVariableKindsv1=newVariableKinds("first",10);VariableKindsv2=newVariableKinds("second",20);System.out.println("instances: "+instanceCount);// 2// Local variable with var (Java 10+)varresult=v1.compute(5);System.out.println("result: "+result);// 50// Exception parametertry{int[]arr=newint[0];intx=arr[5];// throws}catch(ArrayIndexOutOfBoundsExceptione){// 'e' is exception parameterSystem.out.println("Caught: "+e.getMessage());}}}
// Example 2: Scope and Shadowing// File: ScopeDemo.javapublicclassScopeDemo{privateintx=100;// instance variablepublicvoidscopeTest(){intx=200;// local variable shadows instance variableSystem.out.println("local x: "+x);// 200System.out.println("field x: "+this.x);// 100{// inner blockinty=300;// y scoped to this blockSystem.out.println("inner y: "+y);}// y not accessible here// For-loop creates its own scopefor(inti=0;i<3;i++){intloopLocal=i*2;System.out.println(loopLocal);}// i and loopLocal not accessible here// Can reuse i in a new for-loopfor(inti=0;i<2;i++){System.out.println("second loop i: "+i);}}publicstaticvoidmain(String[]args){newScopeDemo().scopeTest();}}
// Example 3: final and Effectively Final// File: FinalDemo.javaimportjava.util.function.Supplier;publicclassFinalDemo{// Blank final fieldfinalintmaxRetries;FinalDemo(booleanstrict){maxRetries=strict?3:10;// assigned in constructor}publicSupplier<String>makeGreeter(Stringname){// 'name' is effectively final (never reassigned)return()->"Hello, "+name;// captures effectively final}publicvoiddemonstrateVar(){// var type inferencevarmessage="Inferred String";// type: Stringvarnumber=42;// type: intvarlist=newjava.util.ArrayList<Integer>();// type: ArrayList<Integer>list.add(1);list.add(2);for(varitem:list){// item: IntegerSystem.out.println(item);}}publicstaticvoidmain(String[]args){FinalDemodemo=newFinalDemo(true);System.out.println("maxRetries: "+demo.maxRetries);Supplier<String>greeter=demo.makeGreeter("World");System.out.println(greeter.get());demo.demonstrateVar();}}
// Example 5: volatile and Thread Safety// File: VolatileDemo.javapublicclassVolatileDemo{// volatile ensures visibility across threadsprivatevolatilebooleanrunning=true;privatevolatileintcounter=0;// For true atomicity, use AtomicIntegerprivatefinaljava.util.concurrent.atomic.AtomicIntegeratomicCounter=newjava.util.concurrent.atomic.AtomicInteger(0);publicvoidstart()throwsInterruptedException{Threadworker=newThread(()->{while(running){counter++;// NOT atomic (read-modify-write), but visibleatomicCounter.incrementAndGet();// atomic}});worker.start();Thread.sleep(10);running=false;// volatile write — visible to worker threadworker.join();System.out.println("counter (may be imprecise): "+counter);System.out.println("atomicCounter (precise): "+atomicCounter.get());}publicstaticvoidmain(String[]args)throwsInterruptedException{newVolatileDemo().start();}}