What are the key method modifiers, and how do they affect the way a method can be invoked?
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.
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).
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.
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.
In a class, an abstract method must include the abstract
modifier in its declaration, and must not include an implementation. In place of an implementation enclosed in braces, the declaration is terminated by a semicolon (;
).
A class containing an abstract method—whether declared in the class or inherited (and not overridden and implemented) from a superclass or interface—must itself be declared with the abstract
modifier. Such a class cannot be directly instantiated, but must be extended by a concrete subclass (i.e. a class with all inherited abstract methods overridden and implemented, and without any new abstract
methods declared) if instances are to be created.
Since an abstract method must be overridden and implemented, if it is to be invoked, a private
method cannot also be declared as abstract
.
A method in a class may be declared with the abstract
modifier, and without an access-level modifier; however, this effectively means that a concrete subclass must be defined in the same package, since absence of an access-level modifier on a method in a class means that the package-private access level is applied.
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.
static
) methodsAn 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.
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
methodsA 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.
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.
A static method must be explicitly declared with the static
modifier; any method without that modifier is implicitly declared as an instance (non-static) method.
Since static
methods are not, strictly speaking, inherited (and overridable) when extending a class (or implementing an interface), and since abstract
methods must be overridden and implemented if they are to be invoked, the combination of static
and abstract
is not allowed.
For more information, see “Packages in Java”. ↩