Static Members

  • Core Java: Volume I—Fundamentals

    • Chapters 4.4

Static Fields

You've used the static modifier only sparingly in your programs. The main method, of course, is always static. And once or twice, you declared a Scanner as static. Now, you'll see why and how to declare and use static fields. More importantly, you'll see the difference between static and non-static fields.

Student.java
public class Student {
    private int id;
    private static int nextId = 1;

    // some implementation details not shown
}

The difference between a static and non-static variable is simple. Every instance of the Student class will have a separate id variable with a unique value. However, the nextId variable is shared among all instances. Changing its value from any instance changes it for all instances.

Student.java
public class Student {
    private int id;
    private static int nextId = 1;

    public Student() {
        id = nextId++;
    }
}

nextId will always represent a value one greater than the largest id currently in use across all instances of the Student class. The constructor uses this value to set the id of any object it creates, then increments the nextId value.

The nextId variable is private, and therefore, only available from within the Student class. static variables accessible from other classes typically are referenced using the name of the class in which it is defined.

Teacher.java
public class Teacher {
    public static int id = 1;
}
Student.java
public class Student {
    private int id;
    private static int nextId;

    // some implementation details not shown

    public void someMethod() {
        int teacherId = Teacher.id;    // syntax: ClassName.staticVariableName
    }
}

You can reference all static variables in this manner, it's just not necessary when doing so from within the same class in which they're defined.

Static Constants

static variables aren't incredibly common, but static constants certainly are. The Math class uses several static constants, which you've seen already.

Math.PI    // Math is the name of the class, and PI is the static constant

You've also been using System.out.println since the very beginning of the course. System is a class, and out is a static variable (referring to a PrintStream object) declared in that class. It is tagged with a public access modifier, which is why you can reference it in the way you do.

public class System {
    public final static PrintStream out = /* ... */;

    // some implementation details not shown
}

Since it is marked as final, you're free to make it public. And since it's static, you can reference it through the class itself (as opposed to through an object of that class).

We've touched on the final keyword in a few different places, and there are a few more still that we haven't gotten to yet. We'll table the conversation on method overriding and subclassing, as we'll be covering those topics in a later section.

Static Methods

A static method is one that doesn't operate on an object. There's no implicit parameter, though there can be zero or more explicit parameters. The Math class is a great example of static methods you've used in your programs.

Math.max(a, b)
Math.min(a, b)
Math.pow(a, b)

These are all static methods. There is no Math object on which they're invoked.

When you write your own static methods, it's important to remember that these methods cannot access your instance variables. You should have very few static methods. If you find yourself converting fields or methods to static to satisfy compilation problems, there's probably a deeper issue with your code.

Student.java
public class Student {
    private static int nextId = 1;

    private int id;
    private double gpa;
    private String name;

    public Student(double gpa, String name) {
        this.id = Student.nextId++;    // assign id and increment nextId
        this.gpa = gpa;
        this.name = name;
    }

    public static int getNextId() {
        // you'll get a compilation error if you try to
        // access non-static fields from a static method

        return Student.nextId;
    }
}

Using Static Methods

There are three primary scenarios in which a static method might be a good design choice.

  • If a method never needs to access an object's state because all required information is supplied via explicit parameters.

An example of this would be the Math.pow method (or any of the static methods of the Math class). It doesn't need to access the state of any Math object, because all of the information it needs is supplied through the explicit parameters.

Math.pow(a, b)

This method computes ab, and information hypothetically contained in the state of a Math object doesn't change how this is done or assist in doing it.

  • If a method only needs to access static fields of the class in which it is defined.

An example of this would be the getNextId method of the Student class. It is a simple method, serving only to return the value of the static variable nextId.

public static int getNextId() {
    return Student.nextId;
}

It doesn't need to know about or access any of the instance variables.

  • If you want to create a factory method.

Factory methods are something you haven't used too much, but they are an important design pattern to understand. Certain classes opt for static factory methods (rather than constructors) to construct objects. An example of this would be the NumberFormat class.

NumberFormat currencyFormatter = NumberFormat.getCurrencyInstance();
NumberFormat percentFormatter = NumberFormat.getPercentInstance();

double x = 0.78;   // this is what you'll be formatting

System.out.println(currencyFormatter.format(x));    // $0.78
System.out.println(precentFormatter.format(x));     // 78%

Constructors impose a few restrictions on how objects are created, which gives rise to the use case of static factory methods as an alternative.

  • You can't name your constructors. They must take on the name of the class.

If you're the author of the NumberFormat class, you'd want to distinguish between the currency and percent instances. This can be done by adding a parameter that aligns to one instance or another. However, it is much more clear to specify the requested instance right in the name of the method. Constructors cannot do this, but static factory methods can.

  • Constructors can't vary the type of the constructed object.

The factory methods of the NumberFormat class sometimes return instances of the DecimalFormat class, which is a specialized subclass that extends the NumberFormat class. This allows for more customized formatting, as needed, but is not something a constructor can do.

Now that we have a better understand of static members, let's take a look at some of the differences between static and non-static methods.

Last updated

Was this helpful?