The static
keyword can be confusing at first, but is important
for understanding object-oriented systems and is especially key to some of the
design patterns we'll look at later in the class.
Imagine we have a simple class for representing cars and various properties of them:
public class Car {
private String make;
private String model;
private int year;
private int mileage;
public Car(String make, String model, int year, int mileage) {
this.make = make;
this.model = model;
this.year = year;
this.mileage = mileage;
}
// ...
}
This class could also have other constructors and methods too, but we'll just talk
about the instance variables for now. Every time we make a Car
object, it will get its own copies of make
, model
,
year
, and mileage
. Let's say we make a couple Car
objects:
Car c1 = new Car("Honda", "Accord", 2006, 78000);
Car c2 = new Car("Ford", "Focus", 2014, 27500);
Both of these cars have different values for each of the four variables in the class. They are instance variables meaning they are associated with each instance, or object, of the class.
If we make a variable in a class static, then it doesn't work this way. Instead static variables are associated with the class itself, and only one variable is shared amongst all instances.
This is not often useful, and the great majority of variables in a class will not be
static. One example where a static variable makes sense is if we want to keep track of
how many objects of a class have been created. Let's say we want to know how many Car
objects we have made in our program thus far. We can do that with a static variable:
public class Car {
private String make;
private String model;
private int year;
private int mileage;
// the static variable is shared amongst all instances
private static int numCars = 0;
public Car(String make, String model, int year, int mileage) {
this.make = make;
this.model = model;
this.year = year;
this.mileage = mileage;
// increment the count of all cars
numCars++;
}
// ...
}
Here we have added the static variable numCars
. There is only
one copy of this variable that all Car
objects share. If it is
changed anywhere, it affects all cars.
It is initialized in the class body itself as opposed to in the constructor.
The reason is that the constructor is called for every object and so
if we set numCars
to 0 there, then it would be reset each time a
car is made. By initializing it in the class statement, it will only be set to
0 once, when the program starts.
Then the value is incremented in the constructor of the class. That way,
every time we make a new Car
object, we will add one to this
value.
Now that we are keeping track of how many cars have been made, we can create a method to access this information. It makes sense to do this as a static method. Static methods, like static variables, are associated with the class itself rather than any particular object. Getting the number of cars that exist doesn't have to do with a specific Ford Focus or Honda Accord, but rather the Car class in general.
We could write this method simply like this:
public static int getNumCars() {
return numCars;
}
Now calling this method will work differently than other methods of the class. Most methods are called on a particular object of a class. For example:
c1.getMake();
c2.addToMileage(100);
If these are both regular, non-static methods, they are called on particular Car
objects like this. However, our static method is not. It's called on the class itself:
Car.getNumCars();
You have probably seen other examples of static methods that come with Java. For example, this code sorts an ArrayList:
Collections.sort(myList);
Here, the sort
method is from a class called Collections
and
is called on the class itself. The
Math class is a class that groups together static methods for computing various things. It
doesn't make sense to make a "Math object". We just call these methods statically on the class
itself.
Of course the main
method is another example of a static class. The Java
VM calls this method for us when it starts our programs.
One important thing to keep in mind when writing static methods is that they can not
reference any specific object. For example, when we call the getNumCars
method, we do it on the Car
class overall, not on any specific car. That
means it doesn't make sense to refer to any attribute of a specific car like the make, model,
or year.
The compiler enforces this by stopping you from referencing any non-static variables or methods inside of a static method. If we try something like this:
public static int getNumCars() {
System.out.println("Make = " + make);
return numCars;
}
Then we will get an error like this:
java: non-static variable make cannot be referenced from a static context
If you think about it for a second, this should make sense. We call the getNumCars
method on the class Car
in general, not on any specific car object. So how could
it possibly know which make
variable we are talking about? In fact getNumCars
can be called before we ever even make a car.
The rule to keep in mind then is this: static methods can only call other static methods, and can only reference static variables.
Copyright © 2024 Ian Finlayson | Licensed under a Creative Commons BY-NC-SA 4.0 License.