Methods in Java Classes: Modifiers

What are the key method modifiers, and how do they affect the way a method can be invoked?

Overview

The declaration of a method may include one or more modifiers; if present, these must precede the return type and name of the method in the declaration. These modifiers affect where a method is visible and invocable, whether a separate method implementation is required beyond the current declaration, and what constitutes a valid invocation context for the method.

Access levels

All methods defined (or just declared) in a class are accessible—and can be invoked—by other code in that same class. However, access-level modifiers can affect whether a class member is accessible by code outside the class.

These access-level modifiers—and the access level in effect when no such modifier is used—are summarized below. They are listed in order, from most restrictive to least restrictive.

private

A method with this modifier is accessible only within the class where it’s defined (and within the enclosing class or interface, if the method is defined in a nested class).

package-private (default)

If no access-level modifier is included in a given method declaration, the default access level is called package-private: the method may be accessed by code in that class (and within the enclosing class or interface, if the method is defined in a nested class), and by code outside the class but inside the package where that class is located.1

protected

A protected method is accessible within the class where it’s declared (and within the enclosing class or interface, if the method is defined in a nested class), within the package where that class is located, and in any subclasses of the that class.

public

A method that is public is accessible throughout the entire Java virtual machine—unless that access is restricted by an access-level modifier on the entire class where it’s declared.

Abstract vs. concrete

As noted previously, a method may be declared with the abstract modifier, and without an accompanying implementation; such a method is abstract, while a fully-defined method (i.e. with an implementation) is concrete.

Requirements & restrictions

Static vs. instance

When a Java method executes, it does so either in the context of an instance (object) of a class, or in the context of the entire class in which the method is defined. This distinction isn’t made at runtime, based on the way the method is invoked, but at compile-time, through the use (or absence) of the static modifier in the method definition.

Instance (non-static) methods

An instance (non-static) method can only be invoked in the context of an instance of the class (or, if the access level is protected or public, an instance of a subclass of the class). This can be from another instance method in the same class, or by qualifying the invocation with a reference to such an instance.

Example

Continuing with the temperature conversion example, consider this class definition:

public class Temperature {

  public double convertC2F(double c) {
    return (1.8 * c + 32);
  }

}

In the Temperature class above, the convertC2F method is non-static; therefore, it can only be invoked in the context of an instance of Temperature, e.g.

Temperature t = new Temperature();
double f = t.convertC2F(100);

After execution of the above code fragment, the variable f contains 212, which is the Fahrenheit scale-based value for the temperature expressed in Celsius as 100 degrees (100°C).

this

We can think of an instance method as having an implicit parameter named this; its type is the class in which the method is defined. When an instance method is invoked, a reference to the instance context is passed into the method as an implicit argument, and becomes the value of this. Access to this instance context permits the code of the method implementation to access instance fields of the class, and to invoke other instance methods in the class; in both cases, the context passed in to the method is used (whether explicitly—i.e. qualified with this—or implicitly) as the context for field access and method invocation.

In the invocation example above, t is a variable that refers to an instance of Temperature; when convertC2F is invoked, qualified with this reference (in the expression t.convertC2F(100)), the instance of Temperature referenced by t may be accessed using the this reference, in the method implementation.

static methods

A static method is not invoked in the context of an instance of the class; instead, it is invoked in the context of the entire class (or interface) itself.

Example

Consider an alternative definition of the Temperature class:

public class Temperature {

  public static double convertC2F(double c) {
    return (1.8 * c + 32);
  }

}

In the above definition, the convertC2F method is static; therefore, it is invoked in the context of the entire Temperature class, not a single instance. One implication of this is that we can invoke it without having to create an instance of Temperature; we simply qualify the invocation with the Temperature class itself:

double f = Temperature.convertC2F(100);

As in the non-static example, execution of the above line of code results in the variable f containing 212, which is the Fahrenheit scale-based value for the temperature expressed in Celsius as 100 degrees (100°C). In this case, however, we didn’t have to create an instance of Temperature in order to invoke the method.

this?

A static method does not have an implicit this parameter, and does not receive such a reference as an implicit argument, even if the invocation is qualified in that way. For example, we could invoke the static version of convertC2F in exactly the same fashion as the non-static version:

Temperature t = new Temperature();
double f = t.convertC2F(100);

However, even when invoked in this fashion, the Temperature instance reference t is not passed as an implicit argument, and cannot be referenced (implicitly or via this) in the method body.

Requirements & restrictions

  1. For more information, see “Packages in Java”