Just by experiment I discovered that Java non static methods overrides all same named methods in scope even at static context. Even without allowing parameter overloading. Like
import java.util.Arrays;
import static java.util.Arrays.toString;
public class A {
public static void bar(Object... args) {
Arrays.toString(args);
toString(args); //toString() in java.lang.Object cannot be applied to (java.lang.Object[])
}
}
I can't find anything about this in spec. Is this a bug? If it isn't, are there any reasons to implement language like that?
UPD: Java 6 do not compile this example. The question is - why?
The explanation is simple although it doesn't change the fact that the behavior is highly unintuitive:
When resolving the method to be invoked the first thing the compiler does is find the smallest enclosing scope that has a method of the right name. Only then come other things like overload resolution and co in game.
Now what is happening here is that the smallest enclosing scope that contains a toString() method is class A which inherits it from Object. Hence we stop there and don't search farther. Sadly next the compiler tries to find the best fit of the methods in the given scope and notices that it can't call any of those and gives an error.
Which means never statically import methods with a name that is identical to a method in Object, because methods that are naturally in scope take precedence over static imports (the JLS describes method shadowing in detail, but for this problem I think it's much simpler to just remember that).
Edit: #alf kindly submitted the right part of the JLS that describes the method invocation for those who want the whole picture. It's rather complex, but then the problem isn't simple either so that's to be expected.
It is not an override. If it did work, this.toString() would still access the method of A instead of Arrays.toString as would be the case if overriding had occurred.
The language specification explains that static imports only affect the resolution of static methods and types:
A single-static-import declaration d in a compilation unit c of package p that imports a field named n shadows the declaration of any static field named n imported by a static-import-on-demand declaration in c, throughout c.
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.
A single-static-import declaration d in a compilation unit c of package p that imports a type named n shadows the declarations of:
any static type named n imported by a static-import-on-demand declaration in c.
any top level type (§7.6) named n declared in another compilation unit (§7.3) of p.
any type named n imported by a type-import-on-demand declaration (§7.5.2) in c.
throughout c.
Static imports do not shadow non-static methods or inner types.
So the toString does not shadow the non-static method. Since the name toString can refer to a non-static method of A, it does cannot refer to the static method of Arrays and thus toString binds to the only method named toString that is available in scope, which is String toString(). That method cannot take any arguments so you get a compile error.
Section 15.12.1 explains method resolution and would have to have been completely rewritten to allow shadowing of unavailable method names within static methods but not inside member methods.
My guess is that the language designers wanted to keep method resolution rules simple, which means that the same name means the same thing whether it appears in a static method or not, and the only thing that changes is which are available.
If you try following similar looking code then you will not get any compiler error
import static java.util.Arrays.sort;
public class StaticImport {
public void bar(int... args) {
sort(args); // will call Array.sort
}
}
The reason this compiles and yours doesn't is that the toString() (or any other method defined in class Object) are still scoped to Object class because of Object being the parent of your class. Hence when compiler finds matching signature of those methods from Object class then it gives compiler error. In my example since Object class doesn't have sort(int[]) method hence compiler rightly matches it with the static import.
I do not think it is a bug or something different from normal import. For example, in case of normal import, if you have a private class with the same name as imported one the imported one will not be reflected.
Related
This question already has answers here:
Why is it that we cannot override static and final methods? [duplicate]
(5 answers)
Closed 1 year ago.
In Java, what is the actual reason behind the inability to write a method in a sub class which has the same name as a final method in the super class? (Please note that I am not trying to override the method, this is why I have put the keyword final.)
Please see the example below:
class A {
public final void method() {
System.out.println("in method A");
}
}
class B extends A {
public void method() {
System.out.println("in method B");
}
}
The problem is expressed as "'method()' cannot override 'method()' in 'A'; overridden method is final" in the IDE; however, I would like to understand what it is about this situation that leads the compiler to fail.
Because in java, overriding isn't optional.
Names of methods at the class level.
At the class level (as in, what is in a class file, and what a JVM executes), method names include their return type and their parameter types (and, of course, the name). At the JVM level, varargs doesn't exist (it's an array instead), generics do not exist (they are erased for the purposes of signature), and the throws clause isn't a part of the story. But other than that, this method:
public void foo(String foo, int bar, boolean[] baz, long... args) throws Exception {}
turns into this name at the class file level:
foo(Ljava/lang/String;I[Z[J)V
which seems like gobbledygook, but [ is 'array of', the primitives get one letter each (Z for boolean, J for longs, I for integer), V is for void, and L is for: Object type. Now it makes sense.
That really is the method name at the class level, effectively (well, we call this its signature). ANY invocation of a method in java, at the class level, always uses the complete signature. This means javac simply cannot compile a method call unless it actually knows the exact method you're invoking, which is why javac doesn't work unless you have the full classpath of everything you're calling available as you compile.
Overriding isn't optional!
At the class level, if you define a method whose full signature matches, exactly, a signature in your parent class, then it is overriding that method. Period. You can't not. #Override as an annotation doesn't affect this in the slightest (That annotation merely causes the compiler to complain if you aren't overriding anything, it's compiler-checked documentation, that's all it is).
javac goes even further
As a language thing, javac will make bridges if you want to tighten the return type. Given:
class Parent {
Object foo() { return null; }
}
class Child extends Parent {
String foo() { return null; }
}
Then at the class level, the full signature of the one method in Parent is foo()Ljava/lang/Object; whereas the one in Child has foo()Ljava/lang/String; and thus these aren't the same method and Child's foo would appear not to be overriding Parent's foo.
But javac intervenes, and DOES make these override. It does this by actually making 2 methods in Child. You can see this in action! Write the above, compile it, and run javap -c -v on Child and you see these. javac makes 2 methods: Both foo()Ljava/lang/String; and foo()Ljava/lang/Object; (which does have the same signature and thus overrides, by definition, Parent's implementation). That second one is implemented as just calling the 'real' foo (the one returning string), and gets the synthetic flag.
Final is what it is
Which finally gets to your problem: Given that final says: I cannot be overridden, then, that's it. You've made 2 mutually exclusive rules now:
Parent's foo cannot be overriden
Child's foo, by definition (because its signatures match), overrides Parent's foo
Javac will just end it there, toss an error in your face, and call it a day. If you imagined some hypothetical javac update where this combination of factors ought to result in javac making a separate method: But, how? At the class level, same signature == same method (it's an override), so what do you propose? That java add a 0 to the end of the name?
If that's the plan, how should javac deal with this:
Parent p = new Child();
p.foo();
Which foo is intended there? foo()Ljava/lang/Object; from Parent, or foo0()L/java/Object; from child?
You can write a spec that gives an answer to this question (presumably, here it's obvious: Parent's foo; had you written Child c = new Child(); c.foo(); then foo0 was intended, but that makes the language quite complicated, and for what purpose?
The java language designers did not think this is a useful exercise and therefore didn't add this complication to the language. I'm pretty sure that was clearly the right call, but your opinion may of course be different.
Final means not just that you can’t override it, it means you can’t work around having that method get called.
When you subclass the object, if you could make a method that shadows that final method, then you could prevent the superclass method from functioning, or substitute some other functionality than what the user of the object would expect. This would allow introducing malicious code and would defeat the purpose of making methods final.
In your case it sounds like making the superclass method final may not have been the best choice.
I am a bit confused when inheritance and type casting is mixed. I want to understand the rules which java compiler follows when choosing correct methods and variables in inheritance.
I have read something like
Variables are bound at compile time and methods are bound at run time.
The second one is from stackoverflow (#John Skeet)
Overload resolution (which method signature is called) is determined at compile-time, based on the compile-time types of both the method target and the argument expressions
The implementation of that method signature (overriding) is based on the actual type of the target object at execution time.
But the problem is that they are explanations of specific situations and do not give the general process to be followed when other factors (like exception handling) are taken into consideration.
This may be bad practice but assume that both methods and variables are overridden(hidden in case of static variables).
Now if java compiler has to choose at compile time which method/variable needs to be invoked then what algorithm will it follow? Similarly at run time what is the algorithm that java compiler will use(based on the actual type of the object whose reference is being used)?
All method signatures and variables are verified during compile-time but the actual method calls are done / resolved during run-time.
For example :
class A {
int i=5;
public void doSomething(){
//print "in A"
}
}
class B extends A{
int i=10;
public void doSomething(){
// print "in B"
}
public static void main(String[] args){
A a = new B();
a.doSomething();
}
}
Now, when you call a.doSomething(); , during compilation, the compiler just checks whether doSomething() is defined for class A (lhs reference). It is not even bothered about whether the method is also defined for class B. Even if the method were not present in B, the program would compile fine.
Next, during runtime, the JVM dynamically decides which method to call based on type of Object (B in your case.).
So, "in B" is printed.
Now, coming back to fields. Access to fields are resolved during compile time. So, if a field doesn't exist during compile-time, then the compilation fails. The fields are called based on the reference type. So, a.i will print 5 (A's value of i) because the field was resolved during compile-time. Thus, the difference is, method calls are resolved during runtime, their signatures are needed / checked during compile-time where-as fields are checked / resolved during compile-time.
say I have the following code
public class A {
int x;
public boolean is() {return x%2==0;}
public static boolean is (A a) {return !a.is();}
}
and in another class...
List<A> a = ...
a.stream().filter(b->b.isCool());
a.stream().filter(A::is);
//would be equivalent if the static method is(A a) did not exist
the question is how do I refer to the instance method version using the A::is type notation? Thanks a lot
In your example, both the static and the non-static method are applicable for the target type of the filter method. In this case, you can't use a method reference, because the ambiguity can not be resolved. See §15.13.1 Compile-Time Declaration of a Method Reference for details, in particular the following quote and the examples below:
If the first search produces a static method, and no non-static method is applicable [..], then the compile-time declaration is the result of the first search. Otherwise, if no static method is applicable [..], and the second search produces a non-static method, then the compile-time declaration is the result of the second search. Otherwise, there is no compile-time declaration.
In this case, you can use a lambda expression instead of a method reference:
a.stream().filter(item -> A.is(item));
The above rule regarding the search for static and non-static methods is somewhat special, because it doesn't matter, which method is the better fit. Even if the static method would take an Object instead of A, it's still ambiguous. For that reason, I recommend as a general guideline: If there are several methods with the same name in a class (including methods inherited from base classes):
All methods should have the same access modifiers,
All methods should have the same final and abstract modifiers,
And all methods should have the same static modifier
We can not use not static methods or non-global methods by using className::methodName notation.
If you want to use methods of a particular class you have to have an instance of the class.
So if you want to access is() method then you can use :
A a = new A();
a.is();
OR
(new A()).is();
Thanks.
OK, here's a very curious Java 7 language puzzle for the JLS specialists out there. The following piece of code won't compile, neither with javac nor with Eclipse:
package com.example;
public class X {
public static X com = new X();
public void x() {
System.out.println(com.example.X.com);
// cannot find symbol ^^^^^^^
}
}
It appears as though the member com completely prevents access to the com.* packages from within X. This isn't thoroughly applied, however. The following works, for instance:
public void x() {
System.out.println(com.example.X.class);
}
My question(s):
How is this behaviour justified from the JLS?
How can I work around this issue
Note, this is just a simplification for a real problem in generated code, where full qualification of com.example.X is needed and the com member cannot be renamed.
Update: I think it may actually be a similar problem like this one: Why can't I "static import" an "equals" method in Java?
This is called obscuring (jls-6.4.2).
A simple name may occur in contexts where it may potentially be
interpreted as the name of a variable, a type, or a package. In these
situations, the rules of §6.5 specify that a variable will be chosen
in preference to a type, and that a type will be chosen in preference
to a package. Thus, it is may sometimes be impossible to refer to a
visible type or package declaration via its simple name. We say that
such a declaration is obscured.
Your attribute com.example.X.com is not static so it can't be accessed via your X class in a static way. You can access it only via an instance of X.
More than that, each time you will instanciate an X, it will lead to a new X : I can predict a memory explosion here.
Very bad code :)
How can I work around this issue?
Using a fully qualified class name here can be a problem because, in general, package names and variable names both start with lower case letters and thus can collide. But, you do not need to use a fully qualified class name to gain a reference a class's static member; you can reference it qualified just by the class name. Since class names should start with an upper case character, they should never collide with a package name or variable. (And you can import an arbitrary class with its fully qualified class name without issue, because the import statement will never confuse a variable name for a package name.)
public void x() {
// System.out.println(com.example.X.com);
// cannot find symbol ^^^^^^^
System.out.println(X.com); // Works fine
}
Suppose I have class A
public class A
{
public void method()
{
//do stuff
}
}
Also another class B
public class B extends A
{
public void method()
{
//do other stuff
}
}
Now I have the following statements:
A a = new B();
a.method();
Is this an example of run time polymorphism? If yes, then is no binding is done for the reference a at compile time?
The compiler will tell you that this can't work, because there's no relationship between A and B that will allow you to write A a = new B();
B either has to extend A or both have to implement a common interface with void method() in it.
You could have answered this very quickly by trying it with the compiler. Be an experimentalist - it's faster than forums.
UPDATE:
It works, now that B extends A. The binding that you care about, dynamic binding, is done at runtime. The static compile time type for the variable "a" is class A; at runtime it is dynamically bound to a reference of type B. Yes, I would consider this to be an example of polymorphism.
I was waiting to put my answer to another post, into a more correctly classified problem. Your question fits the concept, I've tried to explain in detail. but, since I don't know how link answers, I'll just copy/paste the complete script here .... Kindly go through it, you'll understand everything that there is to understand about your problem, you've asked
let's say compiler has to resolve a call like this : *
A a = new AA(); // Assume AA to be some subclass of class A
a->someFunc(); // and we're invoking a method "someFunc()' on a
*.
Now, compiler will go over following steps methodically.
1.) Firstly, compiler knows the declared type of variable a, so it will check whether the declared type of object a (lets call this, class A for time being), have a method with the name someFunc() and that it must be public. This method could either be declared in class A, or it could be a derived method from one of the base class(es) of class A, but it doesn't matter to compiler and it just checks for it's existence with it's access specifier being public.
Needless to say any error in this step will invite a compiler error.
2.) Secondly, once the method is validated to be a part of the class A, compiler has to resolve the call to the correct method, since many methods could be there with same name (thanks to function overloading). This process of resolving correct method is called overloading resolution. Compiler achieves this by matching the signatures of the called method with all the overloaded methods that are part of the class. So, of all the someFunc() s only the correct someFunc() (matching the signatures with called method) will be found and considered further.
3.) Now comes the difficult part, It may very well happen that someFunc() may have been overridden in one of the subclasses of the class A (lets call this class AA and needless to say it is some subclass of A), and that variable a (declared to be of type A) may actually be referring to an object of class AA, (this is permissible in C++ to enable polymorphism). Now, if the someFunc() method is declared to be of type virtual, in base class (i.e. Class A) and someFunc() has been overriden by subclass(es) of A (either in AA or classes between A and AA), the correct version of someFunc() have to be found out by the compiler.
Now, imagine you're the compiler and you have this task of finding whether the class AA has this method. Obviously, class AA will have this method since, it is a subclass of A and public access of A in class A has already been validated in Step 1 by the compiler !!! . But Alternatively, as mentioned in previous paragraph, someFunc() may be overriden by class AA (or any other class between A and AA), which is what compiler needs to catch. Therefore, you (since, your'e playing the compiler) could do a systematic check to find the bottom-most (lowest in the inheritance tree) overridden method someFunc() starting from class A and ending at class AA. In this search, you'll look for same method signatures as was validated in overloading resolution. This method will be the method which will be invoked.
Now, you may be wondering, "What the heck", is this search done everytime ? ... Well, Not really. The compiler knows the overhead of finding this everytime, and as such, maintains a data-structure called Virtual Table for every class type. Think of virtual table, as mapping from method signatures (which are publicly accessible) to the function pointers. This virtual table is made by compiler during compilation process and is maintained in-memory during program execution. In our example, class A and class AA will both have their own virtual tables. And when compiler has to be find someFunc() in class AA (since actual object pointed by variable a is of type AA), it will simply find the function pointer through the virtual table of Class AA. This is as simple has hashing into the table and is a constant time operation.
Regards
AViD
The code example you've given isn't legal, so I guess the answer is that it's not a kind of polymorphism.
You can't assign a class to a variable of an unrelated type like that. I'm guessing that you might be intending for B to derive from A?
Is this an example of run time polymorphism?
As of the edit: yes that would be runtime polymorphism, since which method is actually executed depends on what is assigned to a.
Edit:
If method() would be static, then calling a.method() would always result in the version of A being called. However, you'd then just write A.method() and if you don't do that any decent IDE would warn you about that (because it might be misleading to call a static method on an instance).
End Edit.
Compile time polymorphism would be the overloading mechanism, i.e. the compiler decides whether to use someMethod(Number) or someMethod(Integer) depending on what it knows about the parameter that is passed (if you pass a Double or just a Number it would be the first one, if you pass an Integer it would be the second).
If yes, then is no binding is done for the reference a at compile time?
What do you mean exactly? Note that the type of a will be A so you can assign everything that extends A at runtime. The compiler will just complain if the assigned value is not an A (you might trick the compiler with a cast, but this is just evil and if this breaks your program, you have been warned ;) )
It should be
public class B extends A {
public void method()
{
//do other stuff
} }
If it were compiling, it would be the B::method() that would be called. (only if you changed your code to make the B class inherit the A class).
In this case your use your object like it was only an A, but if some methods are overidden in B, then these methods are called, instead of A's methods.