3.7.1 Class Variables Are Shared
A club wants its Member class to keep track of how many members have joined. Where should that number live? It cannot be an ordinary instance variable. Recall from Topic 3.3 that every object gets its own copy of each instance variable. If every Member object had its own count, each one would only know about itself. The count is not a fact about Ana or about Ben; it is a fact about the club as a whole.
Java’s answer is a variable that belongs to the class instead of to any one object. There is exactly one copy of it, no matter how many objects exist, and every object of the class uses that same copy. Think of a classroom whiteboard: each student has their own notebook (an instance variable), but there is only one whiteboard, and when one student writes on it, everyone sees the change. The comparison has a limit: a whiteboard sits in one room, while a Java class variable can be reached by any code that is allowed to see it, as you will learn in 3.7.2.
A class variable is a variable that belongs to the class itself, so all objects of the class share a single copy of it. You make one by writing the keyword static before the variable’s type in the declaration. You met static in Topic 1.10 as the word that marks a class method; on a variable it means the same thing: “this belongs to the class.”
private static int memberCount = 0;
| Part | What it means |
|---|---|
private |
Only code inside the class can use it, the same rule as for instance variables. |
static |
One shared copy that belongs to the class. Leave it out and every object gets its own copy. |
int |
The type, as with any variable. |
memberCount |
The name. |
= 0 |
The starting value, given right in the declaration. |
Why is the starting value written in the declaration instead of in the constructor? A constructor runs once for each new object. If the constructor set memberCount = 0, every new member would wipe out the count. A class variable is set up once, when the class is first used, so its starting value goes on the declaration line.
Key idea
A class variable is declared with static before its type. It belongs to the class, so there is exactly one copy,
shared by every object of the class.
Worked example: Counting club members
The constructor below adds 1 to the shared count each time a Member is made. Watch what ana.getMemberCount() returns after each new member joins.
Every example in this chapter fits in one file. A Java file may hold only one public class, so the helper class (here Member) is written without public in front of class. In your own projects, each class would normally be public and live in its own file.
class Member
{
private String name;
private static int memberCount = 0;
public Member(String memberName)
{
name = memberName;
memberCount++;
}
public int getMemberCount()
{
return memberCount;
}
}
public class MemberCount
{
public static void main(String[] args)
{
Member ana = new Member("Ana");
System.out.println(ana.getMemberCount());
Member ben = new Member("Ben");
System.out.println(ana.getMemberCount());
Member cy = new Member("Cy");
System.out.println(ana.getMemberCount());
System.out.println(cy.getMemberCount());
}
}- Line 3 declares an instance variable: each
Memberhas its ownname. - Line 4 declares a class variable: one
memberCountfor the whole class, starting at0. - Line 9, inside the constructor, adds 1 to that one shared copy. Constructors and instance methods are allowed to use class variables.
- Lines 12 to 15 are an accessor (Topic 3.5) that returns the shared count.
Trace main. The memory picture after line 26 shows three objects, each with its own name, and one memberCount that belongs to the class:
Member class (one shared copy): memberCount = 3
ana --> [ name = "Ana" ]
ben --> [ name = "Ben" ]
cy --> [ name = "Cy" ]| Line | What happens | memberCount |
Printed |
|---|---|---|---|
| 22 | Ana’s object is made; constructor adds 1 | 1 | |
| 23 | ana.getMemberCount() |
1 | 1 |
| 24 | Ben’s object is made; constructor adds 1 | 2 | |
| 25 | ana.getMemberCount() sees Ben’s change |
2 | 2 |
| 26 | Cy’s object is made; constructor adds 1 | 3 | |
| 27 | ana.getMemberCount() |
3 | 3 |
| 28 | cy.getMemberCount() reads the same copy |
3 | 3 |
1
2
3
3Line 25 is the key moment. Nothing was done to Ana’s object, yet asking it for the count gives a new answer. That is because there is no count stored inside Ana’s object; every member reads the one shared copy.
Now vary the example so an instance variable and a class variable change side by side. Each Player keeps their own points, and the team keeps one shared teamPoints:
class Player
{
private int points;
private static int teamPoints = 0;
public Player()
{
points = 0;
}
public void scorePoints(int amount)
{
points += amount;
teamPoints += amount;
}
public int getPoints()
{
return points;
}
public int getTeamPoints()
{
return teamPoints;
}
}
public class TeamScore
{
public static void main(String[] args)
{
Player maya = new Player();
Player leo = new Player();
maya.scorePoints(3);
leo.scorePoints(2);
maya.scorePoints(4);
System.out.println(maya.getPoints());
System.out.println(leo.getPoints());
System.out.println(leo.getTeamPoints());
}
}scorePoints (lines 11 to 15) adds the same amount to both variables, but they behave differently:
| Line and call | maya.points |
leo.points |
teamPoints (shared) |
|---|---|---|---|
| 32–33 two players made | 0 | 0 | 0 |
34 maya.scorePoints(3) |
3 | 0 | 3 |
35 leo.scorePoints(2) |
3 | 2 | 5 |
36 maya.scorePoints(4) |
7 | 2 | 9 |
7
2
9
Each call changes only the points of the object it was called on, but every call changes the single teamPoints. That is why leo.getTeamPoints() reports 9, including the 7 points Maya scored.
Watch out
Forgetting static on a counter. Here is the member program with one word removed: line 4 says private int memberCount = 0; without static.
class Member
{
private String name;
private int memberCount = 0;
public Member(String memberName)
{
name = memberName;
memberCount++;
}
public int getMemberCount()
{
return memberCount;
}
}
public class MemberNoStatic
{
public static void main(String[] args)
{
Member ana = new Member("Ana");
System.out.println(ana.getMemberCount());
Member ben = new Member("Ben");
System.out.println(ana.getMemberCount());
Member cy = new Member("Cy");
System.out.println(ana.getMemberCount());
System.out.println(cy.getMemberCount());
}
}It compiles and runs, but prints the wrong thing:
1
1
1
1Without static, memberCount is an instance variable, so every new object gets its own copy starting at 0, and its constructor raises only that copy to 1. No object ever sees another object’s increment. Students make this mistake because the declaration looks almost the same either way. The fix is the one word: private static int memberCount = 0;. Ask yourself, “Is this value about one object, or about all of them?” If it is about all of them, it needs static.
Where in a class each kind of variable may be used is the subject of Topic 3.8.
Pause and try
Question 1 · Multiple choice
A Ticket class needs a variable that every Ticket object shares, to hold the total number of tickets printed. Which declaration is correct?
private int totalPrinted = 0;private static int totalPrinted = 0;private int static totalPrinted = 0;static private totalPrinted = 0;
Check your reasoning
B. A class variable has static written before its type, and static is what makes the copy shared.
- A is wrong: with no
static, eachTicketgets its owntotalPrinted, so the objects would not share a total. - C is wrong:
staticmust come before the typeint, not between the type and the name. This does not compile. - D is wrong: it is missing the type. Every variable declaration needs a type such as
int.
Reread 3.7.1 Class Variables Are Shared if you chose differently.
Question 2 · Tracing
Write the exact output.
class Bike
{
private int rides;
private static int totalRides = 0;
public Bike(int startingRides)
{
rides = startingRides;
totalRides += startingRides;
}
public void ride()
{
rides++;
totalRides++;
}
public int getRides()
{
return rides;
}
public int getTotalRides()
{
return totalRides;
}
}
public class BikeRides
{
public static void main(String[] args)
{
Bike red = new Bike(5);
Bike blue = new Bike(0);
blue.ride();
red.ride();
blue.ride();
System.out.println(red.getRides());
System.out.println(blue.getRides());
System.out.println(red.getTotalRides());
}
}Check your reasoning
6
2
8rides is an instance variable (each bike has its own), and totalRides is a class variable (one shared copy).
| Line and statement | red.rides |
blue.rides |
totalRides |
|---|---|---|---|
33 new Bike(5) |
5 | 5 | |
34 new Bike(0) |
5 | 0 | 5 |
35 blue.ride() |
5 | 1 | 6 |
36 red.ride() |
6 | 1 | 7 |
37 blue.ride() |
6 | 2 | 8 |
red.getTotalRides() returns the shared 8, which includes blue’s rides. A common wrong answer is 6 for the last line, which treats totalRides as red’s own.
Reread 3.7.1 Class Variables Are Shared if your output differed.
3.7.2 Public Class Variables and the Class Name
So far the shared count was private, so code outside the class needed an object to ask for it. But a class variable does not belong to any object. How should code in another class, such as main, refer to it directly?
Use the same pattern you used for class methods in Topic 1.10: the class name, the dot operator, then the variable name. If a class variable is declared public, any class can reach it as ClassName.variableName. The class name is the natural thing to write because the variable is attached to the class, not to an object. You have already done this once: in Topic 1.5 you used Integer.MAX_VALUE, which is a public class variable of Java’s Integer class.
Key idea
A public class variable is used from outside its class by writing the class name, a dot, and the variable name, as
in Raffle.ticketsSold.
Worked example: Reading a public class variable from main
ticketsSold is public static, so main, which is in a different class, can use it directly.
class Raffle
{
public static int ticketsSold = 0;
private String buyer;
public Raffle(String buyerName)
{
buyer = buyerName;
ticketsSold++;
}
}
public class RaffleSales
{
public static void main(String[] args)
{
System.out.println(Raffle.ticketsSold);
Raffle first = new Raffle("Jo");
Raffle second = new Raffle("Sam");
System.out.println(Raffle.ticketsSold);
Raffle.ticketsSold = 0;
System.out.println(Raffle.ticketsSold);
}
}| Line | What happens | Raffle.ticketsSold |
Printed |
|---|---|---|---|
| 17 | Read through the class name; no objects exist yet | 0 | 0 |
| 18 | Jo’s ticket is made; constructor adds 1 | 1 | |
| 19 | Sam’s ticket is made; constructor adds 1 | 2 | |
| 20 | Read through the class name | 2 | 2 |
| 21 | main assigns 0 to the shared copy |
0 | |
| 22 | Read again | 0 | 0 |
0
2
0Two things to notice:
- Line 17 works before any
Raffleobject exists. A class variable is not stored inside objects, so it is there as soon as the class is used, even with zero objects. - Line 21 shows the danger of
public. Any code anywhere can change a public variable, so the count now says0even though two tickets exist. This is why Topic 3.3 recommendsprivatefor data: the class should control its own data. A public class variable is used when the class’s specification calls for it; in 3.7.3 you will see the most common safe case, a value that can never be changed.
Now vary the access. Here ticketsSold is private and main tries the same read:
class Raffle
{
private static int ticketsSold = 0;
private String buyer;
public Raffle(String buyerName)
{
buyer = buyerName;
ticketsSold++;
}
}
public class RafflePrivate
{
public static void main(String[] args)
{
System.out.println(Raffle.ticketsSold);
Raffle first = new Raffle("Jo");
Raffle second = new Raffle("Sam");
System.out.println(Raffle.ticketsSold);
System.out.println(Raffle.ticketsSold);
}
}The compiler stops at line 17:
RafflePrivate.java:17: error: ticketsSold has private access in Raffle
The class name and dot are the right form, but private still means only code inside Raffle may touch the variable. Writing the class name never gets around private. To share a private class variable safely, the class provides a method that returns it. You will write that kind of method, one that needs no object at all, in 3.7.4.
Watch out
Leaving off the class name outside the class. Inside Raffle, the constructor can write just ticketsSold, because it is in the class that declares the variable. Code in another class cannot. If main writes System.out.println(ticketsSold);, Java looks for a variable named ticketsSold in main and in main’s own class, finds none, and reports error: cannot find symbol. This is the same rule you learned for class methods in Topic 1.10: inside the defining class, the class name is optional; from any other class, it is required. Write Raffle.ticketsSold.
Pause and try
Question 3 · Debugging
This program should print 1, but it does not compile. Find the error and write the corrected line.
class Raffle
{
public static int ticketsSold = 0;
private String buyer;
public Raffle(String buyerName)
{
buyer = buyerName;
ticketsSold++;
}
}
public class RaffleNoClassName
{
public static void main(String[] args)
{
Raffle first = new Raffle("Jo");
System.out.println(ticketsSold);
}
}Check your reasoning
Line 18 should be:
System.out.println(Raffle.ticketsSold);What was wrong: ticketsSold is declared in Raffle, but line 18 is in RaffleNoClassName, a different class. From outside the declaring class, a public class variable must be reached through the class name and a dot. Without it, the compiler reports error: cannot find symbol because there is no variable named ticketsSold in main or in RaffleNoClassName. With the fix, one Raffle has been made, so the program prints 1.
Reread 3.7.2 Public Class Variables and the Class Name if you found a different error.
Question 4 · Multiple choice
What does this program print?
class Museum
{
public static int visitors = 0;
private String exhibit;
public Museum(String exhibitName)
{
exhibit = exhibitName;
}
public void enter()
{
visitors++;
}
}
public class VisitorCount
{
public static void main(String[] args)
{
Museum dinosaurs = new Museum("Dinosaurs");
Museum space = new Museum("Space");
dinosaurs.enter();
space.enter();
space.enter();
System.out.println(Museum.visitors);
}
}123- Nothing;
Museum.visitorsdoes not compile becausevisitorsmust be reached through an object.
Check your reasoning
C. visitors is a class variable, so all Museum objects share one copy. dinosaurs.enter() raises it to 1, and space.enter() twice raises it to 3. Museum.visitors reads that one copy.
- A is wrong:
1is how many timesdinosaurscalledenter, as if each object had its own count. - B is wrong:
2is how many timesspacecalledenter; it ignores the call made throughdinosaurs. - D is wrong: a
publicclass variable is reached through the class name, which is exactly whatMuseum.visitorsdoes.
Reread 3.7.2 Public Class Variables and the Class Name if you chose differently.
3.7.3 Final Variables Cannot Change
Some values should never change while a program runs: the number of slices in a pizza, the passing score on a test, a student’s ID number. If such a value is stored in an ordinary variable, a careless line like the one in 3.7.2 could change it, and every calculation after that would be wrong. You want Java itself to refuse the change.
That is what the keyword final does. A final variable is a variable whose value cannot be modified once it has been given. Any statement that tries to assign it a new value is a compile error, so the mistake is caught before the program ever runs.
final combines naturally with static. A value like “8 slices per pizza” is the same for every pizza order, so there is no reason for each object to store its own copy; one shared copy is enough. And because it can never change, it is safe to make public: nobody can damage it. A public static final variable is called a class constant. By custom, Java programmers write constant names in all capital letters with underscores between words, such as SLICES_PER_PIZZA, so readers can spot them. Integer.MAX_VALUE from Topic 1.5 is a class constant.
public static final int SLICES_PER_PIZZA = 8;
Read it as: anyone may use it (public), there is one copy for the class (static), it cannot change (final), it is an int named SLICES_PER_PIZZA, and its value is 8.
Key idea
A variable declared final cannot be changed after it gets its value. A public static final variable is a class
constant: one shared, unchangeable value, used as ClassName.CONSTANT_NAME.
Worked example: A class constant for pizza slices
class PizzaOrder
{
public static final int SLICES_PER_PIZZA = 8;
private int pizzas;
public PizzaOrder(int pizzaCount)
{
pizzas = pizzaCount;
}
public int getSlices()
{
return pizzas * SLICES_PER_PIZZA;
}
}
public class PizzaParty
{
public static void main(String[] args)
{
System.out.println(PizzaOrder.SLICES_PER_PIZZA);
PizzaOrder party = new PizzaOrder(4);
System.out.println(party.getSlices());
}
}- Line 3 declares the class constant.
- Line 13 is inside
PizzaOrder, so it uses the constant by its name alone:pizzas * SLICES_PER_PIZZA. - Line 21 is in another class, so it uses the class name:
PizzaOrder.SLICES_PER_PIZZA. It prints8, and noPizzaOrderobject exists yet. - Line 22 makes an order of 4 pizzas, and line 23 prints
4 * 8, which is32.
8
32final is not only for class variables; it can go on any variable. Vary the example: here final is on an instance variable. Each student gets their own ID, set once in the constructor, and it should never change, while a nickname may change any time.
class Student
{
private final int idNumber;
private String nickname;
public Student(int id, String startingNickname)
{
idNumber = id;
nickname = startingNickname;
}
public void setNickname(String newNickname)
{
nickname = newNickname;
}
public int getIdNumber()
{
return idNumber;
}
public String getNickname()
{
return nickname;
}
}
public class StudentId
{
public static void main(String[] args)
{
Student kim = new Student(4417, "Kimmy");
Student raj = new Student(5280, "Raj");
kim.setNickname("K");
System.out.println(kim.getNickname());
System.out.println(kim.getIdNumber());
System.out.println(raj.getIdNumber());
}
}Line 3 declares idNumber as private final int with no value. The constructor gives it one on line 8, once per object. Kim’s nickname changes on line 34, but her ID stays 4417, and Raj has his own ID, 5280, because idNumber is not static:
K
4417
5280
If the class had a method such as setIdNumber that tried idNumber = newId;, the class would not compile: Java reports cannot assign a value to final variable idNumber. The same goes for a final local variable. In this code the third line fails to compile with cannot assign a value to final variable minutesPerHour:
final int minutesPerHour = 60;
int hours = 3;
minutesPerHour = 90;
System.out.println(hours * minutesPerHour);Remove that line and the code prints 180.
Watch out
Trying to change a constant from outside. Because a class constant is public, a student may think they are allowed to adjust it, for example to model a bigger pizza:
class PizzaOrder
{
public static final int SLICES_PER_PIZZA = 8;
private int pizzas;
public PizzaOrder(int pizzaCount)
{
pizzas = pizzaCount;
}
public int getSlices()
{
return pizzas * SLICES_PER_PIZZA;
}
}
public class FinalChange
{
public static void main(String[] args)
{
PizzaOrder.SLICES_PER_PIZZA = 10;
PizzaOrder party = new PizzaOrder(4);
System.out.println(party.getSlices());
}
}Line 21 does not compile. JDK 26 reports:
FinalChange.java:21: error: cannot assign a value to static final variable SLICES_PER_PIZZA(The exact wording can vary between JDK versions.) public controls who may read the constant; final stops everyone from changing it, including code inside its own class. If a value really needs to vary, it should not be final; for example, the number of slices could be a constructor parameter stored in an instance variable.
Pause and try
Question 5 · Multiple choice
This program does not compile. Which line causes the error?
class Student
{
private final int idNumber;
private String nickname;
public Student(int id, String startingNickname)
{
idNumber = id;
nickname = startingNickname;
}
public void setNickname(String newNickname)
{
nickname = newNickname;
}
public void setIdNumber(int newId)
{
idNumber = newId;
}
}
public class StudentIdChange
{
public static void main(String[] args)
{
Student kim = new Student(4417, "Kimmy");
kim.setNickname("K");
kim.setIdNumber(1000);
}
}- Line 8,
idNumber = id; - Line 14,
nickname = newNickname; - Line 19,
idNumber = newId; - Line 29,
kim.setIdNumber(1000);
Check your reasoning
C. idNumber is final, so after the constructor gives it its value, no statement may assign to it again. Line 19 tries, so the compiler reports cannot assign a value to final variable idNumber.
- A is wrong: a
finalinstance variable with no value in its declaration must get its value in the constructor. Line 8 is that one allowed assignment. - B is wrong:
nicknameis notfinal, so a mutator may change it. - D is wrong: calling a method is fine. The problem is inside the method, on line 19, and the compiler reports it there. Removing the
setIdNumbermethod (and this call) fixes the program.
Reread 3.7.3 Final Variables Cannot Change if you chose differently.
Question 6 · Short answer
A GradeBook class needs the value 100, the most points any test can be worth, and the value is the same for every gradebook. Explain why it makes sense to declare it as public static final int MAX_POINTS = 100;, giving a reason for each of the three keywords.
Check your reasoning
Model answer: static because the value is the same for every GradeBook, so one shared copy that belongs to the class is enough; storing a copy in each object would be wasteful. final because the value should never change, and Java will then refuse any statement that tries to change it. public because other classes may need to read it as GradeBook.MAX_POINTS, and making it public is safe: since it is final, no one outside can damage it.
A complete answer must:
- connect
staticto “one value shared by all objects, belonging to the class,” - connect
finalto “cannot be changed,” and - explain that
publicis safe here becausefinalprevents changes.
Reread 3.7.3 Final Variables Cannot Change if your answer differed.
3.7.4 Writing Class Methods
In 3.7.2, making the ticket count private meant main could not read it. An instance accessor would work, but only if you already had a ticket object to call it on, and the count is not about any one ticket. You need a method that, like the variable, belongs to the class.
In Topic 1.10 you called class methods such as Math.sqrt and wrote a few in the class that holds main. Now you will write them in your own object classes. A class method is written like any method from Topic 3.5, with static added before the return type:
public static int getTicketsSold()
A class method may use the class’s class variables, reading them or changing them, and may call the class’s other class methods. Everything it uses belongs to the class, so no object is needed to run it. From another class you call it as ClassName.methodName(arguments); inside its own class the class name may be left off, exactly as in Topic 1.10.
Key idea
A class method has static in its header. It can read and change class variables and call other class methods, and it
is called through the class name, with no object needed.
Worked example: A private count with class methods
ticketsSold is private again, and two class methods give controlled access: one reads it, one resets it.
class Raffle
{
private static int ticketsSold = 0;
private String buyer;
public Raffle(String buyerName)
{
buyer = buyerName;
ticketsSold++;
}
public static int getTicketsSold()
{
return ticketsSold;
}
public static void resetSales()
{
ticketsSold = 0;
}
}
public class RaffleReport
{
public static void main(String[] args)
{
System.out.println(Raffle.getTicketsSold());
Raffle first = new Raffle("Jo");
Raffle second = new Raffle("Sam");
Raffle third = new Raffle("Lee");
System.out.println(Raffle.getTicketsSold());
Raffle.resetSales();
System.out.println(Raffle.getTicketsSold());
}
}- Lines 12 to 15:
getTicketsSoldis a class method that reads a class variable. It is an accessor, as in Topic 3.5, but because it isstaticit needs no object. - Lines 17 to 20:
resetSalesis a void class method that changes a class variable. It is a mutator for the class’s data.
| Line | What happens | ticketsSold |
Printed |
|---|---|---|---|
| 27 | Raffle.getTicketsSold(), no objects yet |
0 | 0 |
| 28–30 | three tickets made; each constructor adds 1 | 3 | |
| 31 | Raffle.getTicketsSold() |
3 | 3 |
| 32 | Raffle.resetSales() sets the count to 0 |
0 | |
| 33 | Raffle.getTicketsSold() |
0 | 0 |
0
3
0Compare this with RaffleSales in 3.7.2: the count can still be reset, but only through a method the Raffle class chose to provide, not by any code writing to the variable.
Now vary it: a class with no instance variables at all, where one class method calls another. GradeScale works like Math: it is a toolbox of class methods.
class GradeScale
{
public static final int PASSING = 70;
public static double percent(int earned, int possible)
{
return 100.0 * earned / possible;
}
public static boolean passed(int earned, int possible)
{
return percent(earned, possible) >= PASSING;
}
}
public class GradeCheck
{
public static void main(String[] args)
{
System.out.println(GradeScale.percent(45, 50));
System.out.println(GradeScale.passed(45, 50));
System.out.println(GradeScale.passed(30, 50));
}
}percent(lines 5 to 8) computes100.0 * earned / possible. Starting with100.0makes the arithmeticdouble, so no integer division happens.passed(lines 10 to 13) calls another class method,percent, without a class name because both are inGradeScale. It compares the result with the class constantPASSING.
Line 20 prints 100.0 * 45 / 50, which is 4500.0 / 50, or 90.0. Line 21 calls passed(45, 50): percent returns 90.0, and 90.0 >= 70 is true. Line 22: percent(30, 50) is 60.0, and 60.0 >= 70 is false.
90.0
true
false
Watch out
Forgetting static on the method. Suppose getTicketsSold is written public int getTicketsSold(), without static, but main still calls Raffle.getTicketsSold():
class Raffle
{
private static int ticketsSold = 0;
private String buyer;
public Raffle(String buyerName)
{
buyer = buyerName;
ticketsSold++;
}
public int getTicketsSold()
{
return ticketsSold;
}
public static void resetSales()
{
ticketsSold = 0;
}
}
public class RaffleMissingStatic
{
public static void main(String[] args)
{
System.out.println(Raffle.getTicketsSold());
Raffle first = new Raffle("Jo");
Raffle second = new Raffle("Sam");
Raffle third = new Raffle("Lee");
System.out.println(Raffle.getTicketsSold());
Raffle.resetSales();
System.out.println(Raffle.getTicketsSold());
}
}The compiler reports, at line 27 (and again at lines 31 and 33):
RaffleMissingStatic.java:27: error: non-static method getTicketsSold() cannot be referenced from a static contextWithout static, getTicketsSold is an instance method, so it must be called on an object. Raffle.getTicketsSold() names only the class, not an object. Topic 1.10 showed the same message when main called a non-static method. The fix is to add static to the header, since the method uses only a class variable.
Pause and try
Question 7 · Tracing
Write the exact output.
class Garage
{
public static final int TOTAL_SPOTS = 5;
private static int spotsTaken = 0;
public static void park()
{
spotsTaken++;
}
public static void leave()
{
spotsTaken--;
}
public static int spotsOpen()
{
return TOTAL_SPOTS - spotsTaken;
}
public static boolean isFull()
{
return spotsOpen() == 0;
}
}
public class ParkingLot
{
public static void main(String[] args)
{
Garage.park();
Garage.park();
Garage.park();
Garage.leave();
System.out.println(Garage.spotsOpen());
Garage.park();
Garage.park();
Garage.park();
System.out.println(Garage.isFull());
}
}Check your reasoning
3
trueEvery method is a class method that changes or reads the one class variable spotsTaken.
| Lines | Calls | spotsTaken |
|---|---|---|
| 31–33 | park() three times |
3 |
| 34 | leave() |
2 |
| 35 | spotsOpen() returns 5 - 2 |
2, prints 3 |
| 36–38 | park() three times |
5 |
Line 39 calls isFull(), which calls the class method spotsOpen(). That returns 5 - 5, which is 0, and 0 == 0 is true.
Reread 3.7.4 Writing Class Methods if your output differed.
Question 8 · Multiple choice
A Library class has private static int booksOut = 0;. Which method, added to Library, compiles and can be called as Library.checkOut() with no Library object?
public void checkOut() { booksOut++; }public static void checkOut() { booksOut++; }public static checkOut() { booksOut++; }static public int checkOut() { booksOut++; }
Check your reasoning
B. It is static, so it can be called through the class name, and a class method may change a class variable.
- A is wrong: it compiles, but without
staticit is an instance method, soLibrary.checkOut()givesnon-static method checkOut() cannot be referenced from a static context. - C is wrong: there is no return type. Every method header needs one (
voidhere). - D is wrong: the return type is
int, but the body never returns a value, so it does not compile.
Reread 3.7.4 Writing Class Methods if you chose differently.
3.7.5 What Class Methods Cannot Reach
You can call a class method with no objects in existence. That raises a question: what happens if a class method tries to use an instance variable, such as a member’s name? Every Member object has its own name. Whose name should the method use? There might be a hundred members, or none at all.
Java does not guess. Inside a class method there is no particular object, so the method cannot use an instance variable or call an instance method by name alone. The only way to work with an object’s data is to be given an object, through a parameter. Then the method names the object it means: someone.getName() or someone.name. Recall from Topic 3.6 that a method inside a class may even use the private data of a parameter of that same class.
Key idea
A class method cannot read or change instance variables, or call instance methods, unless it is passed an object of the class through a parameter and uses that object.
Worked example: Giving a class method an object to work on
First, the attempt that fails. describe is static, and it tries to use name:
class Member
{
private String name;
public Member(String memberName)
{
name = memberName;
}
public String getName()
{
return name;
}
public static String describe()
{
return "Member: " + name;
}
}
public class StaticReadsInstance
{
public static void main(String[] args)
{
Member ana = new Member("Ana");
System.out.println(Member.describe());
}
}StaticReadsInstance.java:17: error: non-static variable name cannot be referenced from a static context“Static context” means “inside a class method, where there is no current object.” Line 26 calls Member.describe() with no object in sight, so the method has no name it could use. Calling the instance method instead, return "Member: " + getName();, fails the same way: non-static method getName() cannot be referenced from a static context.
The fix is a parameter that tells the method which member to describe:
class Member
{
private String name;
public Member(String memberName)
{
name = memberName;
}
public String getName()
{
return name;
}
public static String describe(Member someone)
{
return "Member: " + someone.getName();
}
public static void rename(Member someone, String newName)
{
someone.name = newName;
}
}
public class MemberDescribe
{
public static void main(String[] args)
{
Member ana = new Member("Ana");
Member ben = new Member("Ben");
System.out.println(Member.describe(ana));
Member.rename(ben, "Benji");
System.out.println(Member.describe(ben));
}
}- Line 17:
describecalls the instance methodgetNameon the parameter,someone.getName(). Now Java knows whose name to get. - Line 22:
renamechanges an instance variable through its parameter.someone.nameis private, butrenameis insideMemberandsomeoneis aMember, so it is allowed (Topic 3.6). - Line 33 passes
ben, sosomeonerefers to Ben’s object and his name becomes"Benji".
Member: Ana
Member: BenjiNow vary the number of objects. A class method can receive two objects of its class and compare them:
class Player
{
private String name;
private int points;
public Player(String playerName, int startingPoints)
{
name = playerName;
points = startingPoints;
}
public String getName()
{
return name;
}
public static Player higherScorer(Player first, Player second)
{
if (first.points >= second.points)
{
return first;
}
return second;
}
}
public class HigherScorer
{
public static void main(String[] args)
{
Player maya = new Player("Maya", 12);
Player leo = new Player("Leo", 15);
Player winner = Player.higherScorer(maya, leo);
System.out.println(winner.getName());
}
}higherScorer reads first.points and second.points (both allowed, since the parameters are Players and the method is in Player). On line 33, first refers to Maya (12) and second to Leo (15). 12 >= 15 is false, so line 23 returns the reference in second, Leo’s object, and main prints:
Leo
This also explains something you have done since Unit 1. main is a class method, so it has no object of its own; that is why it always makes an object first and then calls instance methods on it, like ana.getMemberCount(). Topic 3.9 adds a keyword for referring to the current object inside instance methods and constructors; class methods have no current object for it to refer to.
| Code inside a class method | Allowed? |
|---|---|
| Read or change a class variable | Yes |
| Call another class method | Yes |
| Use an instance variable by name alone | No: non-static variable error |
| Call an instance method by name alone | No: non-static method error |
| Use an instance variable or method through a parameter | Yes: someone.name, someone.getName() |
The reverse direction has no such limit: instance methods and constructors may use class variables freely, as Member’s constructor did with memberCount.
Watch out
Making a method static just to call it without an object. A student sees that Member.describe() is easy to call and adds static to a method that needs one member’s data. The error above is the result. Before writing static, ask: “Does this method need one object’s instance variables?” If yes, either leave it an instance method (called as ana.describe()) or give it a parameter that receives the object.
Pause and try
Question 9 · Debugging
This class does not compile. Explain the error and fix isTooHot so that it can still be called through the class name (as Thermostat.isTooHot(...)). Also give the corrected call in main.
class Thermostat
{
public static final int MAX_COMFORT = 76;
private int temperature;
public Thermostat(int startingTemp)
{
temperature = startingTemp;
}
public static boolean isTooHot()
{
return temperature > MAX_COMFORT;
}
}
public class ThermostatBug
{
public static void main(String[] args)
{
Thermostat kitchen = new Thermostat(80);
System.out.println(Thermostat.isTooHot());
}
}Check your reasoning
The compiler reports non-static variable temperature cannot be referenced from a static context at line 13. isTooHot is a class method, so it has no particular thermostat; temperature belongs to each object, and Java cannot know whose temperature to use. Give the method a Thermostat parameter and use its temperature:
public static boolean isTooHot(Thermostat room)
{
return room.temperature > MAX_COMFORT;
}and in main:
System.out.println(Thermostat.isTooHot(kitchen));room.temperature is allowed even though it is private, because the method is inside Thermostat and room is a Thermostat. Using MAX_COMFORT is fine either way: it is a class variable. With the fix, the kitchen is at 80, 80 > 76 is true, and the program prints true.
Reread 3.7.5 What Class Methods Cannot Reach if you found a different error.
Question 10 · Multiple choice
A Lamp class has an instance variable isOn, a class variable lampsOn, an instance method turnOn(), and a class method getLampsOn(). A new class method with no parameters is added to Lamp. Which of these can its body do?
- Read
isOn - Call
turnOn() - Call
getLampsOn() - Set
isOntofalse
Check your reasoning
C. A class method may call another class method; neither one needs an object.
- A is wrong:
isOnis an instance variable. With no parameter, the method has no lamp whoseisOnit could read, so this is anon-static variableerror. - B is wrong:
turnOnis an instance method and must be called on a particular lamp. With no object, this is anon-static methoderror. - D is wrong: changing an instance variable needs an object just as reading one does.
Reread 3.7.5 What Class Methods Cannot Reach if you chose differently.
Putting it together
A food truck numbers its orders starting at 101. Each Order remembers its own number and cost, the class keeps the next number to hand out and the number of orders placed, and every order pays the same delivery fee.
class Order
{
public static final double DELIVERY_FEE = 2.5;
private static int nextNumber = 101;
private static int ordersPlaced = 0;
private final int number;
private double foodCost;
public Order(double cost)
{
foodCost = cost;
number = nextNumber;
nextNumber++;
ordersPlaced++;
}
public int getNumber()
{
return number;
}
public double getTotal()
{
return foodCost + DELIVERY_FEE;
}
public static int getOrdersPlaced()
{
return ordersPlaced;
}
public static Order larger(Order first, Order second)
{
if (first.getTotal() >= second.getTotal())
{
return first;
}
return second;
}
}
public class OrderNumbers
{
public static void main(String[] args)
{
System.out.println(Order.getOrdersPlaced());
Order tacos = new Order(12.0);
Order salad = new Order(8.5);
Order pasta = new Order(15.25);
System.out.println(Order.getOrdersPlaced());
System.out.println(salad.getNumber());
System.out.println(salad.getTotal());
Order biggest = Order.larger(tacos, pasta);
System.out.println(biggest.getNumber());
System.out.println(Order.DELIVERY_FEE);
}
}Sort the variables first:
| Line | Variable | Kind | Why |
|---|---|---|---|
| 3 | DELIVERY_FEE |
class constant | same for every order and never changes |
| 4 | nextNumber |
class variable | one counter for the whole truck |
| 5 | ordersPlaced |
class variable | a total about all orders |
| 7 | number |
final instance variable | each order’s own number, set once |
| 8 | foodCost |
instance variable | each order’s own cost |
The constructor (lines 10 to 16) copies the shared nextNumber into this order’s number, then moves the shared counter forward, so the next order gets the next number. Trace main:
| Line | What happens | Shared afterward | Printed |
|---|---|---|---|
| 47 | class method call, no orders yet | nextNumber 101, ordersPlaced 0 |
0 |
| 48 | tacos gets number 101, cost 12.0 |
nextNumber 102, ordersPlaced 1 |
|
| 49 | salad gets number 102, cost 8.5 |
nextNumber 103, ordersPlaced 2 |
|
| 50 | pasta gets number 103, cost 15.25 |
nextNumber 104, ordersPlaced 3 |
|
| 51 | Order.getOrdersPlaced() |
unchanged | 3 |
| 52 | salad.getNumber() |
unchanged | 102 |
| 53 | salad.getTotal(): 8.5 + 2.5 |
unchanged | 11.0 |
| 55 | number of the larger order | unchanged | 103 |
| 56 | Order.DELIVERY_FEE |
unchanged | 2.5 |
On line 54, the class method larger receives two orders. It cannot use getTotal() by name alone, so it calls it on each parameter: tacos totals 14.5 and pasta totals 17.75. 14.5 >= 17.75 is false, so it returns second, the pasta order, whose number is 103.
0
3
102
11.0
103
2.5
Every idea from the chapter appears: shared class variables (nextNumber, ordersPlaced) changed by the constructor, a public class constant read with the class name, a final instance variable set once, a class method that reads a class variable, and a class method that works on objects only through its parameters.
Common mistakes
The Watch Out boxes explain each mistake. This table is a lookup for the compiler messages you will see in this topic (wording can vary slightly between JDK versions).
| Message contains | Usual cause | Fix |
|---|---|---|
non-static variable … cannot be referenced from a static context |
a class method uses an instance variable by name alone | pass an object and use param.variable, or remove static |
non-static method … cannot be referenced from a static context |
a class method (or ClassName.method()) calls an instance method with no object |
call it on an object, or add static if it uses only class data |
… has private access in … |
another class uses a private class variable |
use a class method that returns it |
cannot assign a value to … final variable … |
a statement assigns to a final variable after it has its value |
remove the assignment, or do not make the variable final |
cannot find symbol |
another class uses a class variable without the class name | write ClassName.variableName |
A counter declared without static gives no message at all: it compiles and counts only to 1.
Vocabulary
| Term | Definition | Example |
|---|---|---|
| class variable | A variable that belongs to the class, with one copy shared by all objects of the class | private static int memberCount = 0; |
static |
The keyword before a variable’s type or a method’s return type that makes it belong to the class | public static int getTicketsSold() |
final |
The keyword that makes a variable unchangeable once it has its value | private final int idNumber; |
| final variable | A variable declared final; any later assignment to it is a compile error |
final int minutesPerHour = 60; |
| class constant | A public static final variable: one shared, unchangeable value |
PizzaOrder.SLICES_PER_PIZZA |
Chapter summary
- A class variable is declared with
staticbefore its type. It belongs to the class, so every object shares one copy, and it exists even before any object is made. Give it its starting value in the declaration, not in the constructor. - A
publicclass variable is used from another class asClassName.variableName. Inside its own class, its name alone is enough. Data is still usually keptprivate. - A
finalvariable cannot be changed after it gets its value. Apublic static finalvariable is a class constant, written in capital letters, such asInteger.MAX_VALUE. - A class method has
staticin its header, is called through the class name with no object, and can read and change class variables and call other class methods. - A class method cannot use instance variables or instance methods by name alone, because there is no current object. Pass it an object through a parameter and work through that object. Instance methods and constructors may always use class variables.
Review questions
Question 11 · Multiple choice
Which statement is true?
- Each object of a class has its own copy of every class variable.
- A class variable can be used from another class as
ClassName.variableNameonly if it ispublic. - A
finalclass variable can be changed by the class’s own methods, but not by other classes. - A class method can use any instance variable of its class by name alone.
Check your reasoning
B. A public class variable is reached from outside through the class name; a private one cannot be reached from outside at all (has private access).
- A is wrong: that describes instance variables. A class variable has exactly one copy, shared by all objects.
- C is wrong:
finalstops everyone from changing the variable, including code inside its own class. - D is wrong: a class method has no current object, so it can use an instance variable only through an object passed as a parameter.
Reread 3.7.2 Public Class Variables and the Class Name if you chose differently.
Question 12 · Tracing
Write the exact output. The loop is from Topic 2.8.
class Visit
{
private static int visitCount = 0;
private static int totalPeople = 0;
private int groupSize;
public Visit(int people)
{
groupSize = people;
visitCount++;
totalPeople += people;
}
public static double averageGroup()
{
return (double) totalPeople / visitCount;
}
public static int getVisitCount()
{
return visitCount;
}
}
public class GroupVisits
{
public static void main(String[] args)
{
for (int i = 1; i <= 4; i++)
{
Visit v = new Visit(i * 2);
}
System.out.println(Visit.getVisitCount());
System.out.println(Visit.averageGroup());
}
}Check your reasoning
4
5.0Each pass of the loop makes a new Visit with i * 2 people. Only one copy of each class variable exists, so every constructor adds to the same totals:
i |
people | visitCount |
totalPeople |
|---|---|---|---|
| 1 | 2 | 1 | 2 |
| 2 | 4 | 2 | 6 |
| 3 | 6 | 3 | 12 |
| 4 | 8 | 4 | 20 |
The variable v is replaced on each pass, but that does not matter: the totals live in the class, not in any object. averageGroup casts totalPeople to double before dividing, so the result is 20.0 / 4, which is 5.0.
Reread 3.7.1 Class Variables Are Shared and 3.7.4 Writing Class Methods if your output differed.
Question 13 · Short answer
A classmate is tired of “non-static” errors and suggests: “In the Student class, just make every variable static, including each student’s gpa. Then every method can use every variable.” Explain what would go wrong with the program’s data.
Check your reasoning
Model answer: If gpa is static, there is only one gpa for the whole Student class, shared by every student object. Setting one student’s GPA would change it for all students, and every student would report the same value, whichever was stored last. The error messages are not the real problem; they point out that a method needs a particular object’s data. The right fix is to keep gpa an instance variable and either call the method on a student object or pass the student to a class method as a parameter.
A complete answer must:
- say that a
staticvariable has only one shared copy, so every student would have the same GPA, and - explain that values that differ from object to object must stay instance variables.
Reread 3.7.1 Class Variables Are Shared and 3.7.5 What Class Methods Cannot Reach if your answer differed.
Question 14 · Debugging
Each badge should get the next ID number: 1, 2, 3. The program compiles but prints 1, 1, 1. Find the error and write the corrected line.
class Badge
{
private int nextId = 1;
private int id;
public Badge()
{
id = nextId;
nextId++;
}
public int getId()
{
return id;
}
}
public class BadgeBug
{
public static void main(String[] args)
{
Badge first = new Badge();
Badge second = new Badge();
Badge third = new Badge();
System.out.println(first.getId());
System.out.println(second.getId());
System.out.println(third.getId());
}
}Check your reasoning
Line 3 should be:
private static int nextId = 1;What was wrong: nextId is meant to be one counter for the whole class, but without static it is an instance variable. Each new Badge gets its own nextId starting at 1, copies that 1 into id, and then raises only its own nextId to 2, which no other badge ever sees. With static, all badges share one nextId, so the first badge takes 1 and leaves 2, the second takes 2 and leaves 3, and the third takes 3. The program then prints 1, 2, 3.
id must stay an instance variable, because each badge needs its own.
Reread 3.7.1 Class Variables Are Shared if you found a different error.
Question 15 · Multiple choice
A Lamp class has private static int lampsOn and private boolean isOn. Which method, written inside Lamp, does not compile?
public void turnOn() { isOn = true; lampsOn++; }public static int getLampsOn() { return lampsOn; }public static boolean check(Lamp someLamp) { return someLamp.isOn; }public static void turnOn() { isOn = true; lampsOn++; }
Check your reasoning
D. It is a class method, and it assigns to the instance variable isOn by name alone. With no object, Java reports non-static variable isOn cannot be referenced from a static context.
- A compiles: an instance method may use both its own object’s instance variables and the class variables.
- B compiles: a class method may read a class variable.
- C compiles: a class method may use an instance variable through a parameter, and
someLamp.isOnis allowed even though it is private becausecheckis insideLamp.
Reread 3.7.5 What Class Methods Cannot Reach if you chose differently.
Question 16 · Tracing
Write the exact output. Pay attention to line 35.
class Quiz
{
public static final int BONUS = 5;
private static int quizzesGraded = 0;
private int score;
public Quiz(int startingScore)
{
score = startingScore;
quizzesGraded++;
}
public int getScore()
{
return score;
}
public static void addBonus(Quiz target)
{
target.score += BONUS;
}
public static int getQuizzesGraded()
{
return quizzesGraded;
}
}
public class ScoreBoost
{
public static void main(String[] args)
{
Quiz first = new Quiz(80);
Quiz second = new Quiz(91);
Quiz same = first;
Quiz.addBonus(first);
Quiz.addBonus(same);
Quiz.addBonus(second);
System.out.println(first.getScore());
System.out.println(second.getScore());
System.out.println(Quiz.getQuizzesGraded());
}
}Check your reasoning
90
96
2- Lines 33 and 34 make two
Quizobjects, soquizzesGradedbecomes 2. - Line 35 makes no new object. As in Topic 3.6,
samegets a copy of the reference infirst, so both variables refer to the same quiz. The constructor does not run, andquizzesGradedstays 2. addBonusis a class method, so it changesscoreonly through its parameter. Line 36 adds 5 to the first quiz (85). Line 37 passessame, which is that same quiz, so it becomes 90. Line 38 adds 5 to the second quiz (96).
A common wrong answer is 85 and 3, which treats same as a separate quiz.
Reread 3.7.5 What Class Methods Cannot Reach and 3.7.1 Class Variables Are Shared if your output differed.
Reflection
Check each statement. If the answer is “not yet,” reread the linked subsection.
- I can declare a class variable with static and explain why all objects share one copy. Reread
- I can use a public class variable from another class with the class name and a dot. Reread
- I can explain what final does and write a class constant. Reread
- I can write a class method that reads or changes class variables and calls other class methods. Reread
- I can explain why a class method needs an object parameter to use instance data, and fix code that breaks this rule. Reread