Scope and Access
Why this matters
Imagine you're working on a group project for your history class. You have a shared Google Doc where your whole team—Carlos, Maya, and you—keeps the main research and outline. This is your project's "source of truth." But for your specific section on the Boston Tea Party, you jot down some quick notes on a sticky pad right next to your laptop. Those sticky notes are temporary and just for you, right now. You wouldn't expect Carlos, who is working on the Declaration of Independence, to see or use your sticky notes.
In programming, we have a similar concept. Some variables are like the shared Google Doc—available to the whole object. Others are like that sticky note—temporary, private, and only available in the small section of code where you create them. Understanding this difference, called scope, is key to writing clean, bug-free programs.
Concept overview
flowchart TD
subgraph Class Scope
A[Instance Variable: private int score]
end
B(Method Call: updateScore(100)) --> C{Local Scope for updateScore}
subgraph C
D[Parameter 'score' (local) is created, value is 100]
E{this.score = score}
F[Local 'score' (100) is assigned to Instance 'score']
end
C --> G(Method Ends)
G --> H[Parameter 'score' is destroyed]
A -- persists after method call --> I[Instance Variable 'score' now holds 100]
Core explanation
When we write classes, we're creating blueprints for objects. These objects have attributes (data) and behaviors (methods). The data is stored in variables, but not all variables are created equal. The "where" of a variable declaration determines its scope.
Think of scope as a variable's home and the rules for visiting it.
Two Types of Homes: Instance vs. Local
Let's use an analogy. Imagine a Student object is like a student's life at school.
- 1Instance VariablesThese are like your school locker. Your locker belongs to you for the entire school year. You can access it between any of your classes. It holds your core stuff: textbooks, your jacket, your student ID. In code, instance variables are declared inside the class but outside of any method. They represent the core state of an object and exist as long as the object exists.
- 2Local VariablesThese are like a piece of scratch paper you use for a single math problem in algebra class. You write down some numbers, do a calculation, and when you're done with the problem, you might even toss the paper. It's temporary and only relevant to that specific task. In code, local variables are declared inside a method or constructor. They only exist and can only be used within that block of code.
Here's a Student class to illustrate:
public class Student {
// INSTANCE VARIABLE: Like the school locker.
// Belongs to the whole Student object.
private String studentID;
public Student(String id) {
// 'id' is a PARAMETER, which is a type of local variable.
// It only exists inside this constructor.
studentID = id;
}
public void studyForTest(String subject) {
// 'subject' is a PARAMETER (local).
// 'hours' is a LOCAL VARIABLE.
int hours = 2; // Only exists inside studyForTest.
System.out.println("Studying " + subject + " for " + hours + " hours.");
System.out.println("My student ID is: " + studentID); // I can access my instance variable here!
}
public void anotherMethod() {
// System.out.println(hours); // ERROR!
// The 'hours' variable from studyForTest doesn't exist here.
<figure class="lesson-figure"><div class="shr-widget" data-shr-widget="{"code":["public class Student {"," private String studentID;"," public void studyForTest(String subject) {"," int hours = 2;"," System.out.println(\"Studying \" + subject + \" for \" + hours + \" hours.\");"," }"," public void anotherMethod() {"," \/\/ ERROR: 'hours' is out of scope here!"," System.out.println(hours);"," }","}"],"type":"for_loop_trace","trace_steps":[{"line":4,"vars":{"hours":2},"explanation":"Local variable 'hours' created in studyForTest."},{"line":5,"explanation":"studyForTest completes, 'hours' is destroyed."},{"line":9,"error":"Cannot find symbol: hours","explanation":"anotherMethod tries to access 'hours', but it's gone (out of scope)."}]}" aria-label="A for loop trace widget showing Java code. The code attempts to print 'hours' in 'anotherMethod' after it was declared in 'studyForTest'. The trace shows an error when 'anotherMethod' tries to access 'hours'."></div><figcaption class="lesson-figure-caption">Demonstrating local variable scope: `hours` is not accessible outside `studyForTest`.</figcaption></figure>
// It's out of scope, like trying to find your math scratch paper in history class.
}
}
Notice a few key things:
studentIDis an instance variable. It can be accessed in the constructor, instudyForTest, and inanotherMethod. It's available everywhere inside the class.hoursis a local variable insidestudyForTest. Trying to access it fromanotherMethodwill cause a compiler error. Its scope is limited to the curly braces{}of thestudyForTestmethod.idandsubjectare parameters. Parameters are always local variables. Their scope is limited to the constructor or method they belong to. You also can't declare thempublicorprivate—it just doesn't make sense for a temporary variable.
The Name Collision Problem: Shadowing
Now, what happens if a local variable has the same name as an instance variable?
Let's say you have a planner in your locker (instance variable) and you also have a small to-do list in your pocket for your next class (local variable). If someone asks, "What's next on your list?" you're going to pull out the list from your pocket, not go all the way to your locker. The local list "hides" or shadows the one in the locker.
This is a very common situation in Java, especially in constructors and setter methods.
public class Player {
private String teamName;
public Player(String initialTeam) {
this.teamName = initialTeam;
}
// A method to update the player's team
public void setTeam(String teamName) {
// DANGER! Which 'teamName' is which?
teamName = teamName; // This does NOT work as intended.
}
}
In the setTeam method, the parameter teamName (the local variable) shadows the instance variable teamName. When you write teamName = teamName;, Java thinks you mean "set the local variable equal to itself." You're not actually changing the object's instance variable at all! The player's team remains unchanged.
The Solution: this
To solve this, we need a way to explicitly say, "I don't want the local variable in my pocket; I want the instance variable from my locker!"
The keyword this is our solution. this is a reference to the current object—the "whole thing." When you use this.variableName, you are unambiguously referring to the instance variable.
Here is the corrected setTeam method:
public void setTeam(String teamName) {
// Correct!
// this.teamName refers to the instance variable.
// teamName (on the right) refers to the local parameter.
this.teamName = teamName;
}
This line now correctly reads: "Set this object's teamName to the value of the teamName parameter that was just passed into the method."
Using this is not just good practice when shadowing occurs; it makes your code clearer by showing exactly when you're interacting with the object's state versus a temporary local variable.
See it in action
Worked examples
Let's walk through a couple of examples to make sure this is crystal clear.
Updating a User's Score
Problem: We have a GameProfile class that tracks a user's score. We need a method updateScore that takes a new score and updates the user's profile. However, the parameter for the new score is also named score.
public class GameProfile {
private String username;
private int score;
public GameProfile(String username, int initialScore) {
this.username = username;
this.score = initialScore;
}
// How do we correctly implement this method?
public void updateScore(int score) {
// ???
}
public int getScore() {
return this.score;
}
}
Solution Walkthrough:
- Identify the variables: Inside the
updateScoremethod, we have two variables namedscore. One is theprivate int scoreinstance variable that belongs to theGameProfileobject. The other is theint scoreparameter, which is local to theupdateScoremethod. - Recognize the shadowing: The local parameter
scoreis shadowing the instance variablescore. If we just writescore = score;, we'll be assigning the local variable to itself, and the object's actual score won't change. - Use
thisto disambiguate: To specify that we want to modify the instance variable, we must use thethiskeyword.
Correct Implementation:
public void updateScore(int score) {
// "Set this object's score to the value of the score parameter."
this.score = score;
}
Why it works: this.score points directly to the instance variable, bypassing the local variable's shadow. The score on the right side of the = refers to the closest variable with that name, which is the method's parameter.
Calculating a Temporary Value
Problem: We have a Ticket class for a concert in Boston. It has an instance variable for the price. We need a method that calculates the final cost after adding a 6.25% Massachusetts sales tax. This final cost should only be calculated and returned, not stored as part of the object's state.
public class Ticket {
private String eventName;
private double price; // e.g., 50.00
// constructor and other methods...
public double getFinalCost() {
// How do we calculate and return the price with tax?
}
}
Solution Walkthrough:
- 1Define the goalWe need a temporary variable to hold the calculated final cost. We don't want to overwrite the base
priceof the ticket. - 2Declare a local variableInside the
getFinalCostmethod is the perfect place for a local variable. Its life will be contained entirely within this one calculation. Let's call itfinalCost. - 3Perform the calculationWe can access the instance variable
price(orthis.price) within the method. We'll calculateprice * 1.0625and store it in our new local variable. - 4Return the resultThe method's job is to return this value, so we'll return the local variable.
Correct Implementation:
public double getFinalCost() {
// 'finalCost' is a local variable. It only exists here.
double finalCost = this.price * 1.0625;
return finalCost;
}
Try it yourself
Time to put this into practice.
-
The
BookClass: Create aBookclass withprivateinstance variables fortitle(String) andcurrentPage(int).- Write a constructor that accepts a title and sets the
currentPageto1. - Write a method
turnPage()that incrementscurrentPageby 1. - Write a method
jumpToPage(int pageNumber)that sets thecurrentPageto the givenpageNumber. Be careful! The parameter namepageNumbermight be a good candidate for shadowing if you also had an instance variable with a similar name. In this case, you don't, but think about how you would handle it if you did.
- Write a constructor that accepts a title and sets the
-
The
CoffeeOrderClass: Create aCoffeeOrderclass with aprivate double price.- Write a method
getCostWithTip(double tipRate)that takes a tip rate (e.g.,0.20for 20%) as a parameter. - Inside the method, declare a local variable
tipAmountand another local variabletotalCost. - Calculate the values, and have the method return the
totalCost. The originalpriceof the order should not be changed.
- Write a method
Practice — 8 questions
In simple terms, scope is about where your variables can be seen and used in your code, just like some notes are for one class and others are for the whole year.
public class Student {
// INSTANCE VARIABLE: Like the school locker.
// Belongs to the whole Student object.
private String studentID;
public Student(String id) {
// 'id' is a PARAMETER, which is a type of local variable.
// It only exists inside this constructor.
studentID = id;
}
public void studyForTest(String subject) {
// 'subject' is a PARAMETER (local).
// 'hours' is a LOCAL VARIABLE.
int hours = 2; // Only exists inside studyForTest.
System.out.println("Studying " + subject + " for " + hours + " hours.");
System.out.println("My student ID is: " + studentID); // I can access my instance variable here!
}
public void anotherMethod() {
// System.out.println(hours); // ERROR!
// The 'hours' variable from studyForTest doesn't exist here.
[[fig:local_variable_error]]
// It's out of scope, like trying to find your math scratch paper in history class.
}
}
- 3.8.A: Explain where variables can be used in the code.
- 3.8.A.1
- Local variables are variables declared in the headers or bodies of blocks of code. Local variables can only be accessed in the block in which they are declared. Since constructors and methods are blocks of code, parameters to constructors or methods are also considered local variables. These variables may only be used within the constructor or method and cannot be declared to be public or private.
- 3.8.A.2
- When there is a local variable or parameter with the same name as an instance variable, the variable name will refer to the local variable instead of the instance variable within the body of the constructor or method.
flowchart TD
subgraph Class Scope
A[Instance Variable: private int score]
end
B(Method Call: updateScore(100)) --> C{Local Scope for updateScore}
subgraph C
D[Parameter 'score' (local) is created, value is 100]
E{this.score = score}
F[Local 'score' (100) is assigned to Instance 'score']
end
C --> G(Method Ends)
G --> H[Parameter 'score' is destroyed]
A -- persists after method call --> I[Instance Variable 'score' now holds 100]
Read what Saavi narrates
Hello, and welcome to Shrutam. I'm Saavi, and today we're going to talk about one of the most fundamental concepts in programming: variable scope.
Imagine you're working on a group project. You have a shared Google Doc where your whole team keeps the main research. That's your project's source of truth. But for your specific section, you might jot down some quick notes on a sticky pad. Those notes are temporary and just for you, right now.
In programming, it's the same idea. Some variables are like that shared doc—available to the whole object. We call these instance variables. Others are like that sticky note—temporary, and only available in the small section of code where you create them. We call these local variables. Understanding this difference is key to writing clean, bug-free programs.
So, this lesson is all about a variable's lifespan and visibility. Where can it be used, and for how long does it exist?
Let's look at a quick example. Imagine a Game Profile class that tracks a user's score. The class has an instance variable for the score. Now, let's say we have a method to update that score. The method takes a parameter... which we also decide to call 'score'. Now we have a problem. Inside that method, which 'score' is which?
The parameter, which is a local variable, "shadows" the instance variable. If you write code that says score equals score... you're just setting the local variable equal to itself. The object's actual score never changes. This is a super common bug!
So how do we fix it? We use the keyword 'this'. The 'this' keyword is a way of saying "I mean the one that belongs to the whole object... the instance variable." So you'd write: this-dot-score equals score. That tells Java to take the value from the local parameter and assign it to the object's instance variable.
It's a small detail, but it's what separates code that *looks* right from code that *is* right. As you practice, this will become second nature. You've got this.
Local variables are destroyed once the method finishes executing. They are out of scope and inaccessible anywhere else.
If you need data to be accessible across multiple methods, make it an instance variable. If you need to pass a value from one method to another, return it from the first method and pass it as a parameter to the second.
Writing `variable = variable;` inside a method like `public void setValue(int variable)` does nothing. You are assigning the local parameter's value to itself, and the instance variable is never updated.
Always use `this.variable = variable;` in setters or constructors where names overlap to ensure you're modifying the instance variable.
Access modifiers like `public` and `private` are for controlling access to class members (instance variables and methods). Parameters are temporary, local variables; the concept of `public` or `private` doesn't apply to them.
Simply declare the parameter with its type and name, like `public void myMethod(int number)`.
A variable declared in a `for` loop header (e.g., `for (int i = 0; ... )`) has a scope that is limited to the body of that loop. You cannot access `i` after the loop finishes.
Recognize that loop variables have one of the smallest scopes. If you need to use its final value after the loop, declare a variable *before* the loop and update it inside.
Writing `int score = 100;` inside a method when you already have a `private int score;` instance variable creates a *new*, separate local variable. This new variable shadows the instance variable, and any changes to it will be lost when the method ends.
If you mean to change the state of the object, access the instance variable directly, e.g., `score = 100;` or `this.score = 100;`. Do not re-declare it with the type (`int`).