In release 5.0, the Java platform
introduced a number of facilities that make it easier to work with arrays. This
program uses varargs, autoboxing, static import (see http://java.sun.com/j2se/5.0/docs/guide/language [Java-5.0]) and the convenience
method Arrays.toString (see Puzzle 60). What does the program
print?
import static java.util.Arrays.toString; class ImportDuty { public static void main(String[] args) { printArgs(1, 2, 3, 4, 5); } static void printArgs(Object... args) { System.out.println(toString(args)); } }
Solution 71: Import Duty
You might expect
the program to print [1, 2, 3, 4, 5], and indeed it would, if only it
compiled. Sadly, the compiler just can't seem to find the right
toString method:
ImportDuty.java:9:Object.toString can't be applied to (Object[]) System.out.println(toString(args)); ^
Is the compiler just being dense? Why would it try to apply
Object.toString(), which doesn't match the call's parameter list, when
Arrays.toString(Object[]) matches perfectly?
The first thing the compiler does when selecting a method to be
invoked at run time is to choose the scope in which the method must be found
[JLS 15.12.1]. The compiler chooses the smallest enclosing scope that has a
method with the right name. In our program, this scope is the class
ImportDuty, which contains the toString method inherited from
Object. This scope has no applicable method for the invocation
toString(args), so the compiler must reject the program.
In other words, the desired toString method isn't in
scope at the point of the invocation. The imported toString method is
shadowed by a method with the same name inherited
into ImportDuty from Object [JLS 6.3.1]. Shadowing is a lot
like obscuring (Puzzle
68). The key distinction is that a declaration can shadow another
declaration only of the same kind: One type declaration can shadow another, one
variable declaration can shadow another, and one method declaration can shadow
another. By contrast, variable declarations can obscure type and package
declarations, and type declarations can obscure package declarations.
When one declaration shadows another, the simple name refers to
the entity in the shadowing declaration. In this case, toString refers
to the toString method from Object. Simply put, members that are naturally in scope take precedence over
static imports. One consequence is that static methods with the same name
as Object methods cannot be used with the static import facility.
Since you can't use static import with
Arrays.toString, use a normal import declaration instead. This is the
way Arrays.toString was meant to be used:
import java.util.Arrays; class ImportDuty { static void printArgs(Object... args) { System.out.println(Arrays.toString(args)); } }
If you are desperate to avoid
qualifying Arrays.toString invocations explicitly, you can write your
own private static forwarding method:
private static String toString(Object[] a) { return Arrays.toString(a); }
The static import facility was intended for situations in which
static members of another class are used repeatedly, and qualifying each use
would seriously clutter a program. In such situations, the static import
facility can significantly enhance readability. It is far safer than
implementing interfaces to inherit their constants, which you should never do
[EJ Item 17]. Overuse of the static import facility can, however, harm
readability by making the class of a static member unclear at the point of use.
Use the static import facility sparingly and only when
there is a compelling need.
For API designers, be aware that the static import facility
cannot be used effectively on a method if its name is already in scope. This
means that static import can seldom be used on static methods that share names
with methods in common interfaces, and it can never be used on static methods
that share names with methods found in Object. Once again, this puzzle
demonstrates that name reuse other than overriding is generally confusing. We
have seen this with overloading, hiding, and obscuring, and now we see it with
shadowing
No comments:
Post a Comment
Your comments are welcome!