Skip to content
HopperHopper

Course navigation

Unit 3 · Class CreationTopic 3.7

Class Variables and Methods

  • About 55 minutes
  • 5 sections
  • Runnable Java examples
  • Practice questions

Before you start

About 55 minutes

Section 1 of 5

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.

MemberCount.java
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 Member has its own name.
  • Line 4 declares a class variable: one memberCount for the whole class, starting at 0.
  • 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
3

Line 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:

TeamScore.java
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.

MemberNoStatic.java
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
1

Without 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?

  1. private int totalPrinted = 0;
  2. private static int totalPrinted = 0;
  3. private int static totalPrinted = 0;
  4. 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, each Ticket gets its own totalPrinted, so the objects would not share a total.
  • C is wrong: static must come before the type int, 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.

BikeRides.java
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
8

rides 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.

Section 2 of 5

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.

RaffleSales.java
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
0

Two things to notice:

  • Line 17 works before any Raffle object 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 says 0 even though two tickets exist. This is why Topic 3.3 recommends private for 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:

RafflePrivate.java
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.

RaffleNoClassName.java
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?

VisitorCount.java
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);
    }
}
  1. 1
  2. 2
  3. 3
  4. Nothing; Museum.visitors does not compile because visitors must 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: 1 is how many times dinosaurs called enter, as if each object had its own count.
  • B is wrong: 2 is how many times space called enter; it ignores the call made through dinosaurs.
  • D is wrong: a public class variable is reached through the class name, which is exactly what Museum.visitors does.

Reread 3.7.2 Public Class Variables and the Class Name if you chose differently.

Section 3 of 5

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

PizzaParty.java
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 prints 8, and no PizzaOrder object exists yet.
  • Line 22 makes an order of 4 pizzas, and line 23 prints 4 * 8, which is 32.
8
32

final 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.

StudentId.java
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:

FinalChange.java
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?

StudentIdChange.java
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);
    }
}
  1. Line 8, idNumber = id;
  2. Line 14, nickname = newNickname;
  3. Line 19, idNumber = newId;
  4. 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 final instance variable with no value in its declaration must get its value in the constructor. Line 8 is that one allowed assignment.
  • B is wrong: nickname is not final, 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 setIdNumber method (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 static to “one value shared by all objects, belonging to the class,”
  • connect final to “cannot be changed,” and
  • explain that public is safe here because final prevents changes.

Reread 3.7.3 Final Variables Cannot Change if your answer differed.

Section 4 of 5

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.

RaffleReport.java
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: getTicketsSold is a class method that reads a class variable. It is an accessor, as in Topic 3.5, but because it is static it needs no object.
  • Lines 17 to 20: resetSales is 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
0

Compare 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.

GradeCheck.java
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) computes 100.0 * earned / possible. Starting with 100.0 makes the arithmetic double, so no integer division happens.
  • passed (lines 10 to 13) calls another class method, percent, without a class name because both are in GradeScale. It compares the result with the class constant PASSING.

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():

RaffleMissingStatic.java
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 context

Without 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.

ParkingLot.java
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
true

Every 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?

  1. public void checkOut() { booksOut++; }
  2. public static void checkOut() { booksOut++; }
  3. public static checkOut() { booksOut++; }
  4. 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 static it is an instance method, so Library.checkOut() gives non-static method checkOut() cannot be referenced from a static context.
  • C is wrong: there is no return type. Every method header needs one (void here).
  • 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.

Section 5 of 5

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:

StaticReadsInstance.java
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:

MemberDescribe.java
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: describe calls the instance method getName on the parameter, someone.getName(). Now Java knows whose name to get.
  • Line 22: rename changes an instance variable through its parameter. someone.name is private, but rename is inside Member and someone is a Member, so it is allowed (Topic 3.6).
  • Line 33 passes ben, so someone refers to Ben’s object and his name becomes "Benji".
Member: Ana
Member: Benji

Now vary the number of objects. A class method can receive two objects of its class and compare them:

HigherScorer.java
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.

ThermostatBug.java
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?

  1. Read isOn
  2. Call turnOn()
  3. Call getLampsOn()
  4. Set isOn to false
Check your reasoning

C. A class method may call another class method; neither one needs an object.

  • A is wrong: isOn is an instance variable. With no parameter, the method has no lamp whose isOn it could read, so this is a non-static variable error.
  • B is wrong: turnOn is an instance method and must be called on a particular lamp. With no object, this is a non-static method error.
  • 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.

Wrap-up · 1 of 6

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.

OrderNumbers.java
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.

Wrap-up · 2 of 6

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.

Wrap-up · 3 of 6

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
Wrap-up · 4 of 6

Chapter summary

  • A class variable is declared with static before 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 public class variable is used from another class as ClassName.variableName. Inside its own class, its name alone is enough. Data is still usually kept private.
  • A final variable cannot be changed after it gets its value. A public static final variable is a class constant, written in capital letters, such as Integer.MAX_VALUE.
  • A class method has static in 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.
Wrap-up · 5 of 6

Review questions

Question 11 · Multiple choice

Which statement is true?

  1. Each object of a class has its own copy of every class variable.
  2. A class variable can be used from another class as ClassName.variableName only if it is public.
  3. A final class variable can be changed by the class’s own methods, but not by other classes.
  4. 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: final stops 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.

GroupVisits.java
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.0

Each 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 static variable 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.

BadgeBug.java
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?

  1. public void turnOn() { isOn = true; lampsOn++; }
  2. public static int getLampsOn() { return lampsOn; }
  3. public static boolean check(Lamp someLamp) { return someLamp.isOn; }
  4. 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.isOn is allowed even though it is private because check is inside Lamp.

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.

ScoreBoost.java
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 Quiz objects, so quizzesGraded becomes 2.
  • Line 35 makes no new object. As in Topic 3.6, same gets a copy of the reference in first, so both variables refer to the same quiz. The constructor does not run, and quizzesGraded stays 2.
  • addBonus is a class method, so it changes score only through its parameter. Line 36 adds 5 to the first quiz (85). Line 37 passes same, 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.

Wrap-up · 6 of 6

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