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.
privateA 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
protectedA 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.
publicA 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).
thisWe 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”. ↩