Unit 3 Class Creation: Understanding Scope, Static Members, and Object References
Static Variables and Methods
When you write a class in Java, you’re defining a blueprint for creating objects (also called instances). Most of what you put in a class—instance variables and instance methods—belongs to each individual object. But sometimes you want data or behavior to belong to the class as a whole, shared across every object created from that class. That’s exactly what static is for.
What “static” means (and why it matters)
A static variable (also called a class variable) is a variable that is stored once per class, not once per object. A static method (also called a class method) is a method you can call using the class name, without having an object.
This matters because many real problems have “shared” information:
- Counting how many objects have been created (a shared counter)
- A constant that should be the same for everyone (like a tax rate)
- A utility method that doesn’t depend on any one object (like
Math.random())
In AP CSA, you’re expected to recognize when something should be instance-based versus class-based—and to understand the rules about what static code can and can’t access.
How static variables work
An instance variable lives inside each object. If you make three Student objects, each has its own name.
A static variable lives once, in the class itself. If you make three Student objects, they all share the same static variable.
A helpful analogy: instance variables are like each person’s personal notebook; static variables are like the class whiteboard—everyone sees and updates the same one.
Example: counting created objects
A classic use of static variables is keeping a shared count.
public class Student {
private String name;
private static int numStudents = 0;
public Student(String name) {
this.name = name;
numStudents++;
}
public static int getNumStudents() {
return numStudents;
}
}
Key ideas here:
nameis per object.numStudentsis shared across all students.- The constructor increments the shared count each time a new
Studentis created.
If another class runs:
public class Main {
public static void main(String[] args) {
Student a = new Student("Ava");
Student b = new Student("Ben");
System.out.println(Student.getNumStudents());
}
}
Expected output:
2
Notice that getNumStudents() is called using the class name Student, not an object.
How static methods work
A static method belongs to the class. You typically call it like:
ClassName.methodName(...)
Static methods are useful when the method does not depend on the state of a particular object.
The most important rule: static code can’t directly use instance members
Inside a static method, you cannot directly access:
- instance variables
- instance methods
Reason: a static method runs without an object. Instance variables/methods require a specific object.
This is one of the most common AP CSA reasoning points: “Do we have an object here?” If not, you can’t refer to instance data.
Example of what goes wrong:
public class Student {
private String name;
public static void printName() {
System.out.println(name); // ERROR: name is not static
}
}
To make something like this work, the static method would need an object reference:
public class Student {
private String name;
public Student(String name) {
this.name = name;
}
public static void printName(Student s) {
System.out.println(s.name); // allowed because we use a specific object
}
}
Even here, note that accessing s.name directly is only possible because we’re inside the Student class (so private access is allowed within the same class). Outside the class, you’d typically use a getter.
Static constants: static final
A very common pattern is a constant shared by everyone:
public class Circle {
public static final double PI = 3.141592653589793;
}
staticmeans one shared value per class.finalmeans you can’t change it after initialization.
AP CSA often expects you to recognize the convention that constants are written in ALL_CAPS.
Static vs instance: a comparison
| Feature | Instance (non-static) | Static |
|---|---|---|
| Belongs to | each object | the class |
| Memory created | each time you new an object | once when the class is loaded |
| Accessed with | an object reference | the class name (usually) |
| Can use instance variables directly? | yes | no |
Common misconceptions with static
One subtle misconception: “If I access a static variable through an object, does it become object-specific?” No. It’s still shared.
Java allows this syntax (but it’s misleading):
Student s = new Student("Ava");
System.out.println(s.getNumStudents());
This compiles if getNumStudents() is static, but the method still belongs to the class, not s. On the AP exam (and in good style), prefer:
System.out.println(Student.getNumStudents());
Exam Focus
- Typical question patterns:
- Determine the output when static variables are updated by constructors or methods.
- Identify whether a method/variable should be static based on how it’s used.
- Decide whether code compiles when static methods reference instance variables/methods.
- Common mistakes:
- Trying to use instance variables directly inside a static method (forgetting there is no
this). - Thinking each object has its own copy of a static variable.
- Calling static methods through object references and then reasoning as if the method depended on that object.
- Trying to use instance variables directly inside a static method (forgetting there is no
Scope and Access
To write correct Java code, you need to understand two related ideas:
- Scope: where a variable or method name can be used (where it’s “visible” in the code).
- Access control: whether code from other classes is allowed to use a field or method (public vs private).
On AP CSA, scope questions often show up as “Does this compile?” or “Which variable is being referenced?” Access-control questions often connect to encapsulation: keeping data private and controlling it through methods.
Scope: where names are visible
Scope is determined largely by curly braces { }. A name declared inside a block is generally usable only within that block.
Java commonly uses these kinds of scopes:
- Local scope: variables declared inside a method or inside a block (like an
iforfor). - Parameter scope: method parameters behave like local variables inside that method.
- Instance variable scope: fields declared in a class (outside methods) are visible in all instance methods of that class.
- Class (static) scope: static variables and methods are available through the class.
Local variables (including loop variables)
A local variable is declared inside a method or block.
public void example() {
int x = 10; // local to example()
if (x > 5) {
int y = 3; // local to this if-block
System.out.println(x + y);
}
// System.out.println(y); // ERROR: y not in scope here
}
The key rule: once execution leaves the block where a variable was declared, that variable name is no longer in scope.
A very common AP CSA case is a for loop variable:
for (int i = 0; i < 5; i++) {
System.out.println(i);
}
// System.out.println(i); // ERROR: i not in scope here
Parameters as local variables
Method parameters are in scope for the entire method body.
public int addOne(int n) {
return n + 1;
}
Here, n is in scope anywhere inside addOne.
Shadowing: same name, different variable
Sometimes the same name is used in different scopes. The inner scope “wins,” meaning it shadows the outer one.
public class ShadowDemo {
private int x;
public ShadowDemo(int x) {
x = x; // does NOT do what you want
}
}
This is a scope issue:
- The parameter
xis a local variable in the constructor scope. - The instance variable
xis hidden (shadowed) by the parameter. - So
x = x;assigns the parameter to itself.
This exact pattern is one reason the this keyword matters (you’ll see it in the next major section).
Access control: public vs private
Access control answers: “Even if a name is in scope, am I allowed to use it from here?”
In AP CSA class design, you’ll most often use:
private: accessible only within the same class.public: accessible from other classes.
Why private instance variables are standard
A core object-oriented design idea in AP CSA is encapsulation: keep an object’s data hidden (private) and provide controlled ways to read or change it (usually public methods).
Example:
public class BankAccount {
private double balance;
public BankAccount(double initialBalance) {
balance = initialBalance;
}
public double getBalance() {
return balance;
}
public void deposit(double amount) {
if (amount > 0) {
balance += amount;
}
}
}
From another class:
BankAccount acct = new BankAccount(100);
System.out.println(acct.getBalance());
// acct.balance = 1000000; // ERROR: balance is private
Even though balance exists inside the object, other classes are not allowed to access it directly.
Scope vs access: how they differ
It’s easy to confuse scope and access because both can cause “cannot find symbol” or “has private access” errors.
- If something is out of scope, the compiler acts like the name doesn’t exist in that location.
- If something is in scope but not accessible, the compiler knows it exists but blocks you due to access rules.
How static affects access and scope
Static members introduce an extra “layer” to keep straight:
- Instance methods can access both instance variables and static variables.
- Static methods can access only static variables directly.
This is not about public/private; it’s about whether an object exists.
Example:
public class Counter {
private int instanceCount;
private static int totalCount;
public void increment() {
instanceCount++;
totalCount++;
}
public static int getTotalCount() {
return totalCount;
// return instanceCount; // ERROR: cannot use instanceCount in static context
}
}
“Dot notation” and what it implies
When you see obj.method() or obj.field, you should ask: “Is this an instance member or static member?”
obj.instanceMethod()calls an instance method on that object.ClassName.staticMethod()calls a static method belonging to the class.
Java will let you write obj.staticMethod(), but it’s better style (and clearer reasoning) to use the class name.
Exam Focus
- Typical question patterns:
- Decide whether a variable is in scope at a certain line (especially with loops and if-blocks).
- Identify which variable is referenced when names are shadowed (parameter vs instance variable).
- Determine whether code can access a private field from another class.
- Common mistakes:
- Assuming a variable declared in a loop or if-block can be used afterward.
- Confusing “not in scope” with “private access” (different compiler errors, different causes).
- Forgetting that static methods don’t have access to instance variables unless they use an object reference.
This Keyword
The keyword this is one of the most important tools for writing clear, correct class code. It shows up constantly in constructors and in instance methods.
What this is
this is a reference to “the current object”—the specific instance whose method or constructor is currently running.
So if you write:
Student s = new Student("Ava");
During the Student constructor call, this refers to the object being created (the same object that will be stored in s once construction finishes).
Why this matters
this solves several common problems:
- Disambiguation: if a parameter/local variable has the same name as an instance variable,
thislets you explicitly refer to the instance variable. - Clarity: it makes it obvious you’re using an instance field/method.
- Constructor chaining: you can call one constructor from another using
this(...). - Passing the current object: you can hand the current object to another method.
The AP exam often targets (1) and (3), and it also expects you to know that this cannot be used in a static context.
How this works in assignments (fixing shadowing)
Recall the earlier shadowing bug:
public class ShadowDemo {
private int x;
public ShadowDemo(int x) {
x = x; // wrong
}
}
To assign the parameter into the instance variable, you need to refer to the instance variable explicitly:
public class ShadowDemo {
private int x;
public ShadowDemo(int x) {
this.x = x; // correct
}
}
Read it as: “set the current object’s x to the parameter x.”
This pattern is extremely common in AP CSA constructors.
this to call another instance method
Inside an instance method, you can write this.methodName() to emphasize you’re calling a method on the current object:
public class Greeter {
private String name;
public Greeter(String name) {
this.name = name;
}
public void greet() {
System.out.println("Hi, " + this.name);
this.logGreeting();
}
private void logGreeting() {
// internal helper
}
}
Most of the time, this. is optional when referring to instance members (because Java will assume you mean the current object). But it becomes required when there’s shadowing.
this(...): calling another constructor
Java lets you overload constructors (multiple constructors with different parameter lists). Sometimes you want one constructor to reuse another to avoid duplicating logic. You can do this with constructor chaining using this(...).
Important rule: this(...) must be the first statement in a constructor.
public class Rectangle {
private int width;
private int height;
public Rectangle(int width, int height) {
this.width = width;
this.height = height;
}
public Rectangle(int sideLength) {
this(sideLength, sideLength); // must be first line
}
}
Why this is good design:
- It reduces repeated code.
- It ensures all constructors initialize the object consistently.
A common error is trying to do work before this(...):
public Rectangle(int sideLength) {
System.out.println("Making a square");
this(sideLength, sideLength); // ERROR: not first statement
}
Passing this as an argument
Because this is just a reference to an object, you can pass it to other methods.
public class Team {
public void addMember(Player p) {
// ...
}
}
public class Player {
private Team team;
public Player(Team team) {
this.team = team;
team.addMember(this); // pass the current Player object
}
}
You don’t need this pattern often for AP CSA free-response, but it reinforces the meaning: this is “the current object.”
this and static context: what goes wrong
Because static methods run without an object, there is no “current object.” Therefore, you cannot use this in a static method.
public class Demo {
private int x;
public static void bad() {
// System.out.println(this.x); // ERROR: cannot use this in static context
}
}
A good mental check: if you can call a method like Demo.bad() (with no object), then inside it you cannot refer to this.
this vs object references
this is an object reference, just like any variable that points to an object.
public class Thing {
public void show() {
Thing ref = this;
System.out.println(ref == this); // true
}
}
You don’t need to use == with objects often in AP CSA (and it has special meaning), but the key idea is: this is not magical data; it’s a reference to an object.
Common misconceptions with this
- Thinking
thismeans “the class.” It doesn’t.thismeans “this object.” - Using
thisin a static method. There is no object in that context. - Forgetting that
this(...)must be the first statement in a constructor.
Exam Focus
- Typical question patterns:
- Identify what
thisrefers to at a given point in code (the current object). - Predict the effect of constructor code using
this.field = parameter(especially with shadowing). - Determine whether constructor chaining with
this(...)is legal and what it calls.
- Identify what
- Common mistakes:
- Writing
x = x;in a constructor and assuming the instance variable changes (shadowing bug). - Placing code before
this(...)in a constructor. - Trying to use
thisinside a static method or assuming static methods have a “current object.”
- Writing