FAQ

Java

JSP

Servlet


Advertisement



What is a most-specific method?

Resolving a method name at compile time is more complicated than resolving a field name because of the possibility of method overloading. Invoking a method at run time is also more complicated than accessing a field because of the possibility of instance method overriding.

Suppose that more than one version of an overloaded method applies to a particular call. When evaluating a method invocation expression that invokes an overloaded method, the compiler must determine which of the overloaded methods is the most specific (referred to as the "most specific method"). The same rules apply to constructors, however, which means the most specific method actually may be the most specific constructor.

Determining the method that will be invoked by a method invocation expression involves several steps:

Step1. Determine Class or Interface to Search

The first step in processing a method invocation at compile time is to figure out the name of the method to be invoked and which class or interface to check for definitions of methods of that name. There are several cases to consider, depending on the form that precedes the left parenthesis, as follows:

  • If the form is Name, then there are three sub-cases:
    • If it is a simple name, that is, just an identifier, then the name of the method is the identifier and the class or interface to search is the one whose declaration contains the method invocation. A pointer to this class type descriptor is set in the this field of the method invocation syntax tree node.
    • If it is a qualified name of the form Name . identifier, and the Name is labeled as a type name then the name of the method is the identifier and the class to search is the one named by the Name. If Name is the name of an interface rather than a class, then a compile-time error occurs, because this form can invoke only static methods and interfaces have no static methods.
    • In all other cases, the qualified name has the form Name . identifier and the Name is labeled as an expression name; then the name of the method is the identifier and the class or interface to search is the declared type of the field named by the Name.
  • If the form is Primary . identifier, then the name of the method is the identifier and the class or interface to be searched is the type of the Primary expression.
  • If the form is super . identifier, then the name of the method is the identifier and the class to be searched is the superclass of the class whose declaration contains the method invocation. A compile-time error occurs if such a method invocation occurs in an interface, or in the class Object, or in a static method, a static initializer, or the initializer for a static variable. It follows that a method invocation of this form may appear only in a class other than Object, and only in the body of an instance method, the body of a constructor , or an initializer for an instance variable.
  • If the form is ClassName.super. Identifier, then the name of the method is the Identifier and the class to be searched is the superclass of the class C denoted by ClassName. It is a compile-time error if C is not a lexically enclosing class of the current class. A compile-time error occurs if such a method invocation occurs in an interface, or in the class Object, or in a static method, a static initializer, or the initializer for a static variable. It follows that a method invocation of this form may appear only in a class other than Object, and only in the body of an instance method, the body of a constructor , or an initializer for an instance variable.
  • If the form is TypeName.Identifier, then the name of the method is the Identifier and the class to be searched is the class C denoted by TypeName. If TypeName is the name of an interface rather than a class, then a compile-time error occurs, because this form can invoke only static methods and interfaces have no static methods

Step 2. Determine Method Signature

The second step searches the class or interface determined in the previous step for method declarations. This step uses the name of the method and the types of the argument expressions to locate method declarations that are both applicable and accessible, that is, declarations that can be correctly invoked on the given arguments.

A method declaration is applicable to a method invocation if and only if both of the following are true:

  • The number of parameters in the method declaration equals the number of argument expressions in the method invocation.
  • The type of each actual argument can be converted by method invocation conversion to the type of the corresponding parameter.

If more than one member method is both accessible and applicable to a method invocation, it is necessary to choose one to provide the descriptor for the run-time method dispatch. The Java programming language uses the rule that the most specific method is chosen. The informal intuition is that one method declaration is more specific than another if any invocation handled by the first method could be passed on to the other one without a compile-time type error.

The precise definition of the most specific property is as follows. Let m be a name and suppose that there are two declarations of methods named m, each having n parameters. Suppose that one declaration appears within a class or interface T and that the types of the parameters are T1, . . . , Tn; suppose moreover that the other declaration appears within a class or interface U and that the types of the parameters are U1, . . . , Un . Then the method m declared in T is more specific than the method m declared in U if and only if both of the following are true:

  • T can be converted to U by method invocation conversion.
  • Tj can be converted to Uj by method invocation conversion, for all j from 1 to n.

A method is said to be maximally specific for a method invocation if it is applicable and accessible and there is no other applicable and accessible method that is more specific.

If there is exactly one maximally specific method, then it is in fact the most specific method; it is necessarily more specific than any other method that is applicable and accessible.

It is possible that no method is the most specific, because there are two or more maximally specific method declarations. It's not possible to identify a most-specific method from among the applicable methods. In this case, we say that the method invocation is ambiguous, and a compile-time error occurs.

More about more maximally specific methods:

The types of the actual arguments in the method invocation or class instance creation expression are no part of overloaded method matching. This is where the conceptual difficulty arises; overloading method matching begins with a list of applicable methods. Instead of using the types of the actual arguments, overloaded method matching in the Java programming language compares formal parameter types in the list of applicable methods. It is possible that no method is the most specific, because there are two or more maximally specific methods. In this case:

  • If all the maximally specific methods have the same signature, then:
    • If one of the maximally specific methods is not declared abstract, it is the most specific method.
    • Otherwise, all the maximally specific methods are necessarily declared abstract. The most specific method is chosen arbitrarily among the maximally specific methods. However, the most specific method is considered to throw a checked exception if and only if that exception is declared in the throws clauses of each of the maximally specific methods.
  • Otherwise, we say that the method invocation is ambiguous, and a compile-time error occurs.

Example I

In the following example:

public class Test {	
void print(Object o) {
System.out.println("void print(Object o)");
}
void print(String s) {
System.out.println("void print(String s)");
}

public static void main(String[] args) {
new Test().print(null);
}
}

The print() method is overloaded to take either Object or String types as an argument. We call the print method with a "null" literal as the parameter in the main function. Which print method will be invoked with such call? In this situation, Java invokes the "most-specific" method, as detailed in section 15.12.2.2 of the Java Language Specification. In general, one method is considered more specific than another if its argument types are subtypes of the other method's respective argument types.

Any kinds of Java object reference can be null, the special null reference can be passed as the argument for both Object and String argument methods (a null reference can be converted to any type of object). Therefore, calling print(null) could potentially invoke either print(String s) or print(Object o). The type of the null argument is only used to determine the applicable methods. In general, a method declaration is "more specific" than another if its respective arguments could be converted (via method invocation conversion) to those of the other method.

Recall that any classes in Java are direct or indirect subclasses of Object. So String is a subtype of Object, the method overloaded to accept a String is more specific than the method overloaded to accept an Object. A String can be converted (upcast) to Object, but an Object cannot be converted (downcast or upcast) to String, so the method taking the String argument is more specific. Therefore, print(String s) will be invoked by the call print(null).

Example II

Let's look another example:

public class Test {	
void print(StringBuffer sb) {
System.out.println("void print(StringBuffer sb)");
}
void print(String s) {
System.out.println("void print(String s)");
}

public static void main(String[] args) {
new Test().print(null);
}
}

This example results in a compiler error, as expected. Again, a null reference can be converted to any type of object. Therefore, calling print(null) could potentially invoke either print(String s) or print(StringBuffer sb). The both of String and StringBuffer are a subtype of Object, a String cannot be converted to a StringBuffer, nor can a StringBuffer can be converted to a String (since neither extends the other). It's not possible to identify a most-specific method from among the applicable methods, because there are two maximally specific method declarations.  So the method invocation is ambiguous, and a compile-time error occurs.


Printer-friendly version Printer-friendly version | Send this 
article to a friend Mail this to a friend

Previous Next vertical dots separating previous/next from contents/index/pdf Contents

  |   |