Local Variables and Scope in Java
A member variable is declared outside any subroutine but inside a class; a static member variable belongs to the class as a whole and exists as long as the class exists.
Try it: Scope: Local, Enclosing, Global, Built-in
How Python looks up a name Local → Enclosing → Global → Built-in, why assigning to a name inside a function makes it local (and raises UnboundLocalError if it is read first), and what global, nonlocal and closures change.
How it works
- Before a function runs, Python marks every name assigned inside it as local to that function, unless it is declared global or nonlocal.
- Reading a name searches the local namespace, then enclosing functions, then the module's globals, then the built-ins; the first hit wins.
- A local name read before it has a value raises UnboundLocalError (Python does not fall back to the global).
- global x makes assignments go to the module namespace; nonlocal x makes them go to the nearest enclosing function.
- A function's local frame disappears when it returns, unless an inner function (a closure) still uses its variables.
Default run (10 steps): Ready: Local shadows global. Every name is looked up Local, then Enclosing, then Global, then Built-in. … Finished. Printed: inside: 99 / outside: 10.
Simplified: The lab's own small Python interpreter runs a fixed, hand-written script (you choose the variant and the values, never the code); nothing is executed as real Python. Every script was run in CPython 3.12 with the same inputs and the lab reproduces its output and error messages. Built-ins shows only the names the script used.
Loading the simulation…
Where a Variable Is Written Decides Its Reach
So far, most of the variables you have written were declared inside a subroutine. Those variables are called local variables. A class, however, can contain more than subroutines. It can also contain variable declarations that sit outside every subroutine. Such a variable is called a member variable, because it is a member of the class. The same kind of variable is also sometimes called a global variable.
The difference between the two kinds of variable comes down to placement. A local variable is declared inside a subroutine. A member variable is declared outside any subroutine, though it still must be inside a class. That placement decides the variable's scope, meaning which code is able to see it, and its lifetime, meaning how long it exists. This article follows one particular kind of member variable, the static member variable, and shows how its placement lets one subroutine leave a value that another subroutine can use.
Tracing a Value Across Two Subroutines
Start with a question about a program. Think about what happens when one subroutine stores a number and a different subroutine later reads it. Before reading on, try to decide: can a plain local variable carry that number from the first subroutine to the second?
What do you think happens?
If addPoints is called with 10 and then with 5, what does currentScore return afterwards?
Reveal answer
18
The member variable score is shared by all static subroutines in the class, so each call to addPoints changes the same score. The first call adds 10 plus a bonus of 2, giving 12. The second call adds 5 plus a bonus of 1, giving 18. currentScore then reads that same stored value.
18- score is declared outside every subroutine, so it is a member variable of Scoreboard
- bonus is declared inside
addPoints, so it is a local variable that exists only during that call currentScorereads the same score thataddPointswrote
The value does not live inside addPoints or inside currentScore. It lives in the memory that belongs to the class as a whole. Memory for a static member variable is allocated when the class is first loaded by the Java interpreter, and that memory remains in use as long as the class exists. Every assignment to score changes the contents of that same memory, no matter which subroutine contains the assignment. Every use of score in an expression fetches its value from that same memory, no matter where the expression is. That is why the value written by addPoints is still there when currentScore runs.
Why Local Variables Disappear
A local variable is declared inside a subroutine, so each subroutine gets its own private variable. When the subroutine finishes, the local variable's value disappears. Here, bonus is a local variable of addPoints. Each call to addPoints creates a new bonus, computes it, uses it, and then lets it go. currentScore has no way to reach bonus, because bonus is not inside currentScore and is not a member of the class.
The two edges from the subroutines to score are the important part. Each subroutine has a link to the same variable, which is the structural version of the rule that static member variables are shared by all static subroutines in the class. The class is the container, and score sits directly inside it, so every static subroutine in that class can reach it.
Anatomy of a Static Member Declaration
A member variable declaration looks almost exactly like a local variable declaration. There are two differences. First, the member variable is written outside any subroutine, although it still has to be inside a class. Second, the declaration can carry modifiers such as static, public, and private. In this chapter every member variable declaration includes static. The modifiers public and private may also appear and control access, but they are not required.
- 1Read the modifier list at the front. static means the variable belongs to the class as a whole, not to one subroutine. private or public, if present, controls who may access it.
- 2Read the type next. int tells Java the kind of value the variable holds, the same way it does for a local variable.
- 3Read the name. score is the identifier that every static subroutine in the class uses to reach the stored value.
- 4Read the optional initializer. = 0 assigns a starting value. If it is omitted, Java still gives the variable a default, covered later in this article.
Several variables of the same type can share one line. The source notes that one line can declare several variables of the same type, with the modifiers applied to the whole declaration. Every line in the example has no subroutine around it, which is what makes these member variables rather than locals.
Default Values for Unassigned Members
Local variables and member variables handle a missing assignment differently. When you declare a local variable in a subroutine, you have to assign it a value before you can do anything with it. Member variables do not have that requirement. They are automatically initialized with a default value, so a member variable that is never assigned still holds a well-defined value.
| Kind of variable | Value if never assigned | Practical consequence |
|---|---|---|
| Member variable of a numeric type | zero | Reads return 0 before any assignment |
| Member variable of type boolean | false | Reads return false before any assignment |
| Member variable of type char | the Unicode zero character | Reads return that character before any assignment |
| Member variable holding an object such as String | null | Using it before assignment leads to a null value, not an empty string |
| Local variable of any type | no default | Must be assigned before it is used, or the code will not compile |
Default values Java gives unassigned variables, compared with local variables
Compile error: variable total might not have been initialized- total is a local variable because it sits inside demo
- Java gives no default to a local variable, so reading it before assignment is rejected
What do you think happens?
If score is declared as a static int member with no initializer, and the program calls currentScore before any addPoints call, what does it return?
Reveal answer
0
An unassigned static int member variable receives the default value zero. Because the member variable is never assigned, the default is what currentScore reads.
Mistakes Beginners Make with Scope
Common mistake Expecting a local variable to keep its value after the subroutine returns
What it looks likeDeclaring int bonus = points / 5 inside addPoints, then reading bonus inside currentScore.
Why it failsA local variable exists only while its subroutine runs. bonus is not inside
currentScoreand is not a member of the class, socurrentScorecannot reach it.Do this insteadIf the value must survive across subroutines, declare it as a static member variable outside every subroutine.
Common mistake Assuming a local variable starts at zero like a member variable
What it looks likeDeclaring int total; inside a subroutine and printing it right away.
Why it failsMember variables receive defaults, but local variables do not. The code fails to compile because total was never assigned.
Do this insteadAssign a value to a local variable before using it, for example int total = 0;.
Common mistake Expecting an unassigned String member to be an empty string
What it looks likeDeclaring static String label; with no initializer and assuming label holds empty text.
Why it failsAn unassigned String member variable starts as null, not as an empty string.
Do this insteadAssign an explicit value such as an empty string if you need one, or check for null before using the value.
Common mistake Forgetting that the static modifier is what makes the value shared, so omitting it changes who can see the variable
Practice Tracing Shared State
Using the Scoreboard class above, trace the program if main called addPoints(5) twice instead of addPoints(10) and addPoints(5). Work out the value of score after each call and the value printed by currentScore. Then explain which variable is the local one and which is shared.
Hints
- For each call, compute bonus first as points divided by 5, then add points and bonus to score.
- The value after the first call becomes the starting value for the second call, because score is a member variable.
- bonus is discarded when each call finishes; score is not.
Summary of Scope and Lifetime
- 1A local variable is declared inside a subroutine and exists only while that subroutine runs.
- 2A member variable is declared outside any subroutine but inside a class; a static member variable belongs to the class and exists as long as the class exists.
- 3Static member variables are shared by all static subroutines in the class, so a value set in one subroutine can be read in another.
- 4Unassigned member variables receive defaults: zero for numeric types, false for boolean, the Unicode zero character for char, and null for objects such as String. Local variables receive no default and must be assigned before use.
At a glance
- A local variable is declared inside a subroutine and disappears when that subroutine finishes.
- A static member variable is declared outside every subroutine but inside a class, and it exists as long as the class exists.
- Every static subroutine in the class reads and writes the same static member variable, which is how a value carries from one subroutine to another.
- Unassigned member variables get defaults such as zero, false, the Unicode zero character, or null, while local variables must be assigned before use.