Community
Participate
Working Groups
// Puzzle 71 from "Java Puzzlers" by Joshua Bloch and Neal Gafter 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)); } } This program does compile within Eclipse 3.1.2 using JRE 1.5.0_02 but it does not compile using the JDK 1.5.0_02 directly. The output of the JDK is: javac ImportDuty.java ImportDuty.java:9: toString() in java.lang.Object cannot be applied to (java.lang.Object[]) System.out.println(toString(args)); ^ 1 error The OS used in both cases is Windows XP.
So the question is: do we search static import methods after we have found a method that is not applicable or just report the non-applicable error? Here's another testcase: [ImportTest] import static p.DefinesFoo.foo; class ImportTest extends SuperImportTest { void test() { foo("fails?"); } } class SuperImportTest { private void foo() {} } [DefinesFoo] package p; public class DefinesFoo { public static void foo(String s) {} } This compiles without error on javac but fails if SuperImportTest.foo() is visible.
From the spec in section 7.5.3: A single-static-import declaration d in a compilation unit c of package p that imports a method named n with signature s shadows the declaration of any static method named n with signature s imported by a static-import-on-demand declaration in c, throughout c. Why specify the signature s if it just shadows the method name n?
This is part of the explanation from the book: "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." They further mention that "one consequence is that static methods with the same name as Object methods cannot be used with the static import facility."
Ok - but then I would expect the non-visible case of: class SuperImportTest { private void foo(String s) {} } to report that SuperImportTest.foo(String) is not visible instead of searching the static imports and finding a match in the static import. It seems strange that a complete argument mismatch is an error, but a visibility problem on an exact match is not & must be skipped over.
Here is another case to consider, start with: package p; public class Y { public int foo(int i) {return i;} } then define: class X extends p.Y { void foo() {} void test() { class L { int i = foo(2); } } } So if javac chooses the smallest enclosing scope that has a method with the right name, why does this example compile without errors?
Your comment#2 does not apply here as it describes the "precedence" of single-static-import declarations (like import static p.DefinesFoo.foo;) and static-import-on-demand declarations (like import static p.DefinesFoo.*;). This is how I see the two cases: In my example (ImportDuty) when identifying potentially applicable methods for toString(args) in the scope of class ImportDuty the compiler finds as candidates A1) public ImportDuty.toString() A2) public static java.util.Arrays.toString(Object[]) Both methods are accessible since they are public. However, A2) from the static import is shadowed by A1). Then, by the statement [JLS 15.12.2.1, p.444] "In addition, if the method invocation has, before the left parenthesis, a MethodName of the form Identifier, then the search process also examines all methods that are (a) imported by single-static-import declarations [JLS 7.5.3]and static-import-on-demand declarations [JLS 7.5.4] within the compilation unit [JLS 7.3] within which the method invocation occurs, and (b) not shadowed [JLS 6.3.1] at the place where the method invocation appears." the second possibility A2) is ruled out. Later on, the compiler rejects A1) due to the signature mismatch. In your example (DefinesFoo & ImportTest) we have the methods B1) public static void p.DefinesFoo.foo(String s) B2) <modifier> void (SuperImportTest).foo( <signature> ) Case#1: <modifier> is not private and <signature> is empty: Both javac and Eclipse complain that "foo() in SuperImportTest cannot be applied to (java.lang.Strng)". B1) is ruled out since it is shadowed by B2). Case#2: <modifier> is not private and <signature> is String s: Both javac and Eclipse compile and choose method B2) since it has the appropriate signature. B1) is ruled out since it is shadowed by B2). Case#3: <modifier> is private and <signature> is empty: Here, javac compiles and chooses method B1) since B2) is not accessible from ImportTest. Eclipse, however, incorrectly complains that "foo() in SuperImportTest cannot be applied to (java.lang.String)". Case#4: <modifier> is private and <signature> is String s: Both javac and Eclipse compile and choose method B1) since B2) is not accessible from ImportTest. Concerning your new example, class X inherits the method foo(int i) from p.Y and defines the method foo(). Therefore, we have method overloading here, not shadowing.
Added StaticImport test042
Verified with I20060427-1600 for 3.2RC2
Created attachment 53214 [details] Exporter.java demonstrates bug
Created attachment 53215 [details] Importer.java demonstrates bug
Created attachment 53216 [details] Base.java demonstrates bug
It seems that this bug is not fixed and should be re-opened. The attached classes compile in Eclipse, but javac complains: error\Importer.java:10: getName() in error.Base cannot be applied to (java.lang.Class<error.Importer>) getName(Importer.class); ^ 1 error I'm using javac 1.5.0_06 and Eclipse Version: 3.2.0 Build id: M20060629-1905. From the Eclipse Configuration Details: org.eclipse.jdt (3.2.0.v20060609m-F7snq1fxia-Z4XP) "Eclipse Java Development Tools" org.eclipse.jdt.source (3.2.0.v20060609m-F7snq1fxia-Z4XP) "Eclipse Java Development Tools SDK" As expected, Eclipse finds the errors in the class ImportDuty above.
Please log a separate bug rather than touching a closed one. It is a different scenario.
Sorry - false alarm. I just ran an update - Eclipse finds the error in Importer.java with Version: 3.2.1 Build id: M20060921-0945 org.eclipse.jdt (3.2.1.r321_v20060905-R4CM1Znkvre9wC-) "Eclipse Java Development Tools" org.eclipse.jdt.source (3.2.1.r321_v20060905-R4CM1Znkvre9wC-) "Eclipse Java Development Tools SDK" Sorry for any confusion.
(In reply to comment #9) > Created an attachment (id=53214) [edit] > Exporter.java > > demonstrates bug Could you please reattach Exporter.java? This is Base.java. I'd like to add a regression test with your test case.
Never mind. I believe I got it. Added org.eclipse.jdt.core.tests.compiler.regression.StaticImportTest#test046
Created attachment 53767 [details] Exporter.java (for real!) just for the record... here's the real Exporter.java.