THINK FIRST·CODE LATER

← Java Programming
Chapter 12 · Week 6

Class Members, Utility Classes, and Program Design

Before You Start: What You Must Be Able to Do

Before the questions, make sure you can: explain what a static (class) variable is and why it is shared; predict the output of a program that mixes static counters with instance data; state precisely what a static method may and may not touch; design a utility class and a public static final constant; decide, for a given member, whether it should be static; and describe a program's decomposition into classes and methods using the vocabulary of cohesion and coupling.

Instance members versus class members

Instance member Class (static) member
Belongs to one object the class itself
Copies one per object exactly one, shared by all objects
Accessed through an object: obj.field the class: ClassName.field
Created when the object is created the class is loaded, before any object exists
public class Student {
    private static int count = 0;        // ONE counter for the whole class
    private final int id;                // one id per object

    public Student() { count++; id = count; }
    public static int getCount() { return count; }   // no object needed
    public int getId() { return id; }                // needs an object
}

After creating three students, Student.getCount() is 3 while each object reports its own id. A static field is the right tool for exactly this: information about the class as a whole (how many exist, a shared rate, a next-available number).

What a static method may touch

A static method runs without a calling object, so:

  • it may use static fields and call other static methods directly;
  • it may not use instance fields or call instance methods directly, and it has no this;
  • it may use an object it is given or creates: s.getId() inside main is fine, because s supplies the missing object.

An instance method, on the other hand, may use both instance and static members. This asymmetry — instance to static is allowed, static to instance is not — is worth writing on the first page of your revision notes.

Constants and utility classes

public class TaxUtil {
    public static final double VAT = 0.19;              // class constant
    private TaxUtil() { }                               // prevent instantiation (optional)
    public static double withVat(double amount) { return amount * (1 + VAT); }
    public static double vatOf(double amount)   { return amount * VAT; }
}
// used as TaxUtil.withVat(100), never new TaxUtil()

public static final is the standard way to write a constant that belongs to a class: one copy, readable everywhere, impossible to modify. Math is the archetype of a utility class, and the reason you never write new Math().

main is static, and what follows from it

main is static because the JVM must call it before any object of the class exists. That is why a program that puts real work in instance methods must begin with new SomeClass().run(); or equivalent, and why calling an instance method directly from main does not compile.

Designing the classes themselves

  • Top-down decomposition. Write the main task as a sequence of named steps, then implement each step as a method, splitting again whenever a method stops fitting on a screen or stops doing one thing.
  • Cohesion (high is good): every member of a class belongs to the same idea. A class that stores a student and formats HTML and reads files has low cohesion.
  • Coupling (low is good): classes depend on each other as little as possible, and through methods rather than through exposed fields.
  • One responsibility per class, one job per method. A method whose comment needs the word “and” is usually two methods.
  • Driver separation. Keep main thin: it creates objects and calls methods.

Documenting and testing

Javadoc comments (/** ... */ with @param, @return) document the contract of a method: what it expects and what it guarantees. Test each method as soon as it is written, with ordinary values, boundary values (0, 1, the first and last index) and invalid values. Debugging by println is legitimate; debugging by guessing is not.

Remember
  • One static field exists per class, whatever the number of objects.
  • static cannot reach instance members directly; instance can reach static.
  • public static final declares a class constant.
  • A utility class has no state worth instantiating.
  • High cohesion, low coupling, thin main.
Common Pitfalls
  • Making a field static “to fix” a compile error in main: every object then shares one value, which is almost never what was intended.
  • Using this inside a static method.
  • Declaring a counter as an instance variable and wondering why it is always 1.
  • Writing new Math() or new TaxUtil().

Ready? Close the notes and practise.

36 questions. Predict the output before you check — that is the skill the exam measures.