Is method overloading is an example of runtime polymorphism or compile time polymorphism?
There is no operator overloading in Java.
Method overriding enables run-time polymorphism; method overloading enables compile-time polymorphism.
You can read more about this in your textbook.
See also
Polymorphism vs Overriding vs Overloading
Polymorphism: define in two sentences
Wikipedia: Polymorphism in OOP
Method overloading and polymorphism are two completely different concepts. Polymorphism relates to inheritance and determines from which level of the class hierarchy the method is called. Method overloading is creating two methods in the same location with the same name that take different arguments. For instance:
class A{
public void doSomething(){
System.out.println("A method");
}
//method overloaded with different arguments-- no polymorphism
//or inheritance involved!
public void doSomething(int i){
System.out.println("A method with argument");
}
}
class B extends A{
//method polymorphically overridden by subclass.
public void doSomething(){
System.out.println("B method");
}
}
//static type is A, dynamic type is B.
A a = new B();
a.doSomething(); //prints "B method" because polymorphism looks up dynamic type
//for method behavior
Method overloading is example for compile time binding or static binding
method overloading results in polymorphic methods, a method can be defined more than one time having the same name and varying number either method parameters or parameter types (java allows to do this) , when this happens the linkage between method call and actual definition is resolved at compile time thus overloading is called compile time binding or static binding. OO Program language features call it has compile time Polymorphism.
Method overloading is example of complie time binding. Compiler resolves which method needs to be called at compile time only, So it is compile time polymorphism or you can say static binding, But Method overriding is Runtime polymorphism, bcz at run time , depending on the object reference , method call is resolved.
Related
When I was analyzing a simple java code related with overloading and inheritance I expected to recieve an output that overloads matching the argument's data types. But it doesn't work that way.
Code:
class A {
public int calc (double num){
System.out.println("calc A");
return (int)(num+1);}
}
class B extends A{
public int calc (long num){
System.out.println("calc B");
return (int)(num+2);}
}
class C extends B{
public int calc (int num){
System.out.println("calc C");
return num+3;}
}
class D extends C{
public int calc (float num){
System.out.println("calc D");
return (int)(num+4);}
}
class Program{
public static void main(String[] args){
int num1=10;
long num2 = num1;
Object o1 = num1;
System.out.println("num1 Type: "+o1.getClass().getName());
Object o2 = num2;
System.out.println("num2 Type: "+o2.getClass().getName());
A a1=new D();
A a2=new D();
System.out.println("a1 Type: "+a1.getClass().getName());
System.out.println("a2 Type: "+a2.getClass().getName());
int result = a1.calc(num1)+a2.calc(num2);
System.out.println("Number: "+result);
}
}
Output:
num1 Type: java.lang.Integer
num2 Type: java.lang.Long
a1 Type: D
a2 Type: D
calc A
calc A
Number: 22
I was testing the code here:
ideone
Your main question seems to be about why the type outputs don't match with the formal types. This is entirely intentional, and it's what makes object oriented programming so powerful.
When a method is invoked on an instance, the runtime system looks at the actual type of the instance, and looks up the method to call based on its actual type, rather than on its formal type.
If this weren't the case, you wouldn't be able to get anything useful done. You want to be able to declare an abstract class A, with concrete classes B and C hanging off it that implement the details in different ways. But you also want to be able to declare variables of type A, without caring where they've come from, and whether they're actually of type B or type C. You can then invoke methods that are part of the contract of A, and it'll do the right thing: something that's really a B will invoke B's implementation, and likewise for C.
As for why you end up invoking A's calc method rather than D's, this is again because of the way polymorphism works. The formal type of the variables is A; so when you invoke .calc(), the type system will:
find the most appropriate method in class A to match the call at compile time;
see whether that has been overridden between A and the actual type at runtime;
call the overridden version if there is one, or A's version if not.
But you haven't overridden the calc() method at all: you've supplied methods with different signatures. So in step 1 (at compile time) the type system finds A.calc(double); in step 2 (at runtime) it discovers that this hasn't been overridden further down the class hierarchy; in step 3 (runtime) it therefore invokes A's version.
Overloads are resolved at compile time based on formal types; overrides are resolved at runtime based on actual types.
This is because those methods are overloads, not overrides of the original calc method. Therefore, if you are using a reference of type A, all that can be seen are methods that originally belonged to A. All the other methods are hidden in the object, just as if you had written them with new names.
So when the compiler has to decide which method to call for each calculation, it doesn't have all the options that you think it has. It just has the original calc(double), so it compiles the call as "convert the value to double and call calc(double)". At compile time, it doesn't know that the actual class is not A. It can't compile into code that says "check at runtime if there is a method called calc(int), if so, use it, if not, convert to double and use calc(double). It needs to know what instructions to put there at compile time. And at that time, all it knows about this reference is that it's an A.
EDIT in response to comments:
The compiler always chooses which method is going to be invoked using the contract of the reference's type. That is, the type of your variable, which is A in this case.
This happens whether or not the actual object has an overriding method. At this point the compiler doesn't know about it. What it does is tell the runtime environment: "When you get to this point, take the actual object, and run the method with this signature: calc(double)".
So, if at runtime, the actual object has also calc(int) and calc(long) and other methods named calc, it doesn't matter, because the compiler said "use calc(double)".
Now, if the runtime object has an overriding calc(double), the runtime environment will take that instead of the original calc(double) because that's the nature of overriding.
To sum up:
The compiler only knows about method signatures that exist in the reference type - your variable, in this case.
The compiler puts instructions that mean "use the method with this specific signature or any override (with the same signature).
The runtime environment looks at the actual object, and checks what kind of calc(double) it has. If it has an override, it will use that. If it has only the original, it will use that.
I'm reading about type inference for generics, and this code was provided as an example that fails to compile.
import java.io.*;
class LastError<T> {
private T lastError;
void setError(T t){
lastError = t;
System.out.println("LastError: setError");
}
}
class StrLastError<S extends CharSequence> extends LastError<String>{
public StrLastError(S s) {
}
void setError(S s){
System.out.println("StrLastError: setError");
}
}
class Test {
public static void main(String []args) {
StrLastError<String> err = new StrLastError<String>("Error");
err.setError("Last error");
}
}
And the explanation given in the book was:
"(It looks like the setError() method in StrLastError is overriding setError() in the LastError class. However, it is not the case. At the time of compilation, the knowledge of type S is not available. Therefore, the compiler records the signatures of these two methods as setError(String) in superclass and setError(S_extends_CharSequence) in subclass—treating them as overloaded methods (not overridden). In this case, when the call to setError() is found, the compiler finds both the overloaded methods matching, resulting in the ambiguous method call error."
I really don't understand why type S can't be inferred at compile time.
String is passed when invoking the constructor of class StrLastError,
and from the API docs, String does implement interface CharSequence,
so doesn't that mean that S for <S extends CharSequence> actually is of type String?
I've read the Java online tutorial on the topic of generics several times. I've checked "Type Inference", and Inheritance, I just don't know how the whole thing works. I really need an explanation on this question.
The points I'm stuck at are:
If the subtype can't decide S, how come the super type can decide T, because the superclass does not have an upper bound? Or does it infer that T is String because the subtype calls the supertype's constructor first?
I understand that if the Constructor is invoked as:
StrLastError<CharSequence> err = newStrLastError<>((CharSequence)"Error");
there will be no ambiguity, since it's plain method overriding then. (Or am I even wrong here?)
However, like I said in the beginning, if String is passed, why can't S be inferred to be String?
You have to remind yourself that the classes are compiled one by one. Java generics are not templates as in other languages. There will only be one compiled class and not one class per type it is used with.
This way you can see that the class StrLastError will need to be compiled in a way such that it can also be used with other classes implementing CharSequence as generic type S.
Thats why the compiler gets you two different methods instead of an overridden one. Now it would be a runtime-job to see that the subclass may have wanted to override the method in the parent just in those cases where the types suggest it. Since this behaviour is hard to understand for the developer and would possibly lead to programming mistakes, it raises an exception.
If you use CharSequence as the generic type parameter of the class StrLastError, you will call the setError method in the parent class, since the type of "Last Error" is String, which is more specific than CharSequence and Java always chooses the most specific method in case it is overloaded. (I hope it is clear the the method was not overridden in this case either)
If the subtype can't decide S, how come the super type can decide T, because the superclass does not have an upper bound? Or does it infer that T is String because the subtype calls the supertype's constructor first?
The super type isn't deciding or inferring what T is; you're explicitly telling it what T is by this declaration:
class StrLastError<S extends CharSequence> extends LastError<String>
T is now bound to String for LastError, which makes every reference to T in the parent class a concrete String.
Your child class now has a bound S extends CharSequence attached to it, but this is independent to the bounds applied to the parent class.
What happens now is that Java will compile your child class, and the result of your child class is that two methods with a signature that matches String will be created. (Key note here: A String is-a CharSequence.)
In your child class, setError(Ljava/lang/CharSequence;)V is generated as the signature for setError. Because of the way generics work, LastError#setError will be treated as if it has a signature of setError(Ljava/lang/String;)V. This is also why when you go to actually override the method, it will place a String type as your parameter instead of anything else.
So, what we arrive at are two methods that have override-equivalent signatures.
void setError(CharSequence s)
void setError(String s)
JLS 8.4.8.4. applies here.
It is possible for a class to inherit multiple methods with
override-equivalent signatures (§8.4.2).
It is a compile-time error if a class C inherits a concrete method
whose signature is a subsignature of another concrete method inherited
by C. This can happen if a superclass is generic, and it has two
methods that were distinct in the generic declaration, but have the
same signature in the particular invocation used.
I understand that if the Constructor is invoked as StrLastError err = new StrLastError<>((CharSequence)"Error"); there will be no ambiguity, since its plain method overriding then.(Or I'm even wrong here)
No, now you're messing with raw types. Interestingly enough it will work, primarily because the signatures for the two methods has become:
void setError(Object s)
void setError(String s)
You want to use generics to avoid a scenario like this; you may want to invoke the super class method at some point, but in this scenario with these bindings, it's very difficult to accomplish.
This is a tricky example, to fix it you need to change the following line:
class StrLastError<S extends CharSequence> extends LastError<S>
The following code is considered invalid by the compiler:
class Foo {
void foo(String foo) { ... }
}
class Bar extends Foo {
#Override
void foo(Object foo) { ... }
}
I think that this is described in the JLS 8.4.8.1: "The signature of m1 is a subsignature (§8.4.2) of the signature of m2." and in 8.4.2: "the bounds of corresponding type variables are the same".
My question is: why can't the parameter in the subtype (Bar) be a supertype of the parameter in the supertype (Foo). In the example Object is a supertype of String. As far as I can see allowing this wouldn't violate the Liskov Substitution Principle.
Is there a scenario in which allowing this would break the code or is it a limitation of the current JLS?
Suppose you could do that. Now your superclass looks like this:
class Foo {
void foo(String foo) { ... }
void foo(Number foo) { ... }
}
and your subclass now:
class Bar extends Foo {
#Override
void foo(Object foo) { ... }
}
The language probably could allow such a thing (and just dispatch both Foo.foo(String) and Foo.foo(Number) to Bar.foo(Object)), but apparently the design decision for Java here is that one method only can override exactly one other method.
[Edit]
As dasblinkenlight said in his answer, one can have a foo(Object) without the #Override, but this just overloads the foo functions, and does not override them. When calling, java chooses the most specific method, so foo("Hello World") would always get dispatched to the foo(String) method.
(A rewrite, from a different angle ... my original answer contained an error. :( )
why can't the parameter in the subtype (Bar) be a supertype of the parameter in the supertype (Foo).
I believe that technically it could, and it wouldn't break ancestor contracts following type substition (Liskov Substitution Principle).
Types are passed-by-value (including reference types).
The caller can never be forced to deal with different parameter types than what it passes in.
A method body can swap a parameter type, but can't return it back to the caller (no such thing as 'output parameter types').
If your proposal was allowed, and a call was made to the ancestor method signature, a decendent class could override the method with broader types, but it's still impossible to return a broader type than what the caller sets.
The override could never break a client that uses the narrow ancestor method contract.
From my analysis below, I surmise/guess the rationale for not allowing your scenario:
Performance-related: allowing broader types in override would impact runtime performance, a major issue
Functionality-related: it only adds a minor amount of functionality. As it stands, you could add your 'broader method' as an overloaded method without overriding. Then you could additionally override the original method with an exact signature match. The net result: you achieve something quite similar, functionally.
Compiler Requirements for Method Override - JLS 7
The compiler's required to act accordancing to your experience. 8.4 Method Declarations:
A method in a subclass can override a method in an ancestor class iff:
the method names are identical (8.4.2 and 8.4.8.1)
the method parameters have identical types, after erasure of generic type parameters (8.4.2 and 8.4.8.1)
the return type is type-substitutable for the return type in the ancestor class, i.e. the same type or narrower (8.4.8.3)
Note: subsignature does not mean the overriding method uses subtypes of the overridden method. The overriding method is said to have a subsignature of the overridden method when the overriding method has exactly the same type signature except that generic types and the corresponding raw types are considered equivalent.
Compiler v Runtime Processing for Method Matching & Invocation
There's a performance hit matching method signatures via polymorphic type matching. By restricting override method signatures to exact match of ancestor, the JLS moves much of this processing to compile time. 15.12 Method Invocation Expressions - summarised:
Determine Class or Interface to Search (Compile-Time Determination)
Obtain the base type T, on which the method is being invoked.
This is the reference type declared to the compiler and not the runtime type (where a subtype may be substituted).
Determine Method Signature (Compile-Time Determination)
Search the compile-time base type T, for applicable methods matching the name and parameter & return types consistent with the call.
resolve generic parameters for T, either explicitly passed or implicitly inferred from the types of invocation method arguments
stage 1: methods applicable via consistent types/subtypes ('subtyping')
stage 2: methods applicable via automatic boxing/unboxing plus subtyping
stage 3: methods applicable via automatic boxing/unboxing plus subtyping plus variable 'arity' parameters
determine the most specific matching method signature (i.e. the method signature that could successfully be passed to all other matching method signatures); if none: compiler/ambiguity error
Check: Is the Chosen Method Appropriate? (Compile-Time Determination)
Evaluation of Method Invocation (Runtime Determination)
Determine runtime target reference type
Evaluate arguments
Check accessibility of method
Locate method - an exact signature match against the compile-time matched signature
Invoke
Performance Hit
The breakdown, in terms of text in the JLS:
Step 1: 5%
Step 2: 60%
Step 3: 5%
Step 4: 30%
Not only is Step 2 volumous in text, it's surprisingly complex. It has complex conditions and many expensive test conditions/searches. It's advantageous to maximise the compiler's execution of the more complex and slower processing here. If this was done at runtime, there would be a drag on performance, because it would occur for each method invocation.
Step 4 still has significant processing, but it is as streamlined as possible. Reading through 15.12.4, it contains no processing steps that could be moved to compile time, without forcing the runtime type to exactly match the compile-time type. Not only that, but it does a simple exact match on the method signature, rather than a complex "ancestor type match"
Java annotations cannot change the way the compiler generates byte code from your classes. You use annotations to tell the compiler how you think your program should be interpreted, and report errors when compiler's interpretation does not match your intentions. However, you cannot use annotations to force the compiler to produce code with different semantics.
When your subclass declare a method with the same name and parameter count as in its superclass, Java must decide between two possibilities:
You want the method in the subclass to override the method in the superclass, or
You want the method in the subclass to overload the method in the superclass.
If Java allowed foo(Object) to override foo(String) the language would have to introduce an alternative syntax for indicating an intent to overload a method. For example, they could have done it in a way similar to C#'s new and override in method declarations. For whatever reason, however, the designers decided against this new syntax, leaving the language with the rules specified in JLS 8.4.8.1.
Note that the current design lets you implement the functionality of an override by forwarding the call from the overloaded function. In your case, that would mean calling Bar.foo(Object) from Foo.foo(String) like this:
class Foo {
public void foo(String foo) { ... }
}
class Bar extends Foo {
#Override
public void foo(String foo) { this.foo((Object)foo); }
public void foo(Object foo) { ... }
}
Here is a demo on ideone.
The answer is plain simple, in Java, for method overriding, you must have the exact signature of the super type. However, if you remove the #Override annotation, your method would be overloaded and your code won't break. This is a Java implementation that ensures that you mean the method implementation should override the implementation of the super type.
Method overriding works in the following way.
class Foo{ //Super Class
void foo(String string){
// Your implementation here
}
}
class Bar extends Foo{
#Override
void foo(String string){
super(); //This method is implied when not explicitly stated in the method but the #Override annotation is present.
// Your implementation here
}
// An overloaded method
void foo(Object object){
// Your implementation here
}
}
The methods shown above are both correct and their implementation can vary.
I hope this helps you.
To answer the question in the title of the post What is the reasoning behind not allowing supertypes on Java method overrides?:
The designers of Java wanted a simple object oriented language and they specifically rejected features of C++ where, in their opinion, the complexity/pitfalls of the feature wasn't worth the benefit. What you describe may have fallen into this category where the designers chose to design/specify out the feature.
The problem with your code is that you are telling compiler that foo method in Bar class is overridden from parent class of Bar, i.e. Foo. Since overridden methods must have same signature, but in your case, according to syntax it is an overloaded method as you have changed the parameter in foo method of Bar class.
If you can override with superclasses, why not with subclasses as well?
Consider the following:
class Foo {
void foo(String foo) { ... }
}
class Bar extends Foo {
#Override
void foo(Object foo) { ... }
}
class Another extends Bar {
#Override
void foo(Number foo) { ... }
}
Now you have succesfully overriden an method whose original parameter was a String to accept a Number. Inadvisable to say the least...
Instead, the intended results may be replicated by using overloading and the following, more explicit, code:
class Foo {
void foo(String foo) { ... }
}
class Bar extends Foo {
#Override
private void foo(String foo) { ... }
void foo(Object foo) { ... }
}
class Another extends Bar {
#Override
private void foo(Object foo) { ... }
void foo(Number foo) { ... }
}
Say you have an Interface A, and an Interface B. Let's say the Sprite class implements both interfaces.
Say there's another class that has a method foo(A object), and also has a method foo(B object).
Do both get called when I pass an instance of Sprite to the method foo()? If not, which has precedence?
With method overloading (as is in use here), the method to call is resolved at compile time, based on the (declared) type of the variable holding the Sprite.
Since the method call is ambiguous, this will fail to compile until you manually downcast the reference to resolve the ambiguity.
It's ambiguous. You'll need to cast to one of the interfaces.
interface A {}
interface B {}
class Sprite implements A,B {}
class Test{
void foo(A a){}
void foo(B b){}
void test(){
Sprite s = new Sprite();
foo(s); // <-- compile time error (The method foo(A) is ambiguous for the type Test)
}
}
The general answer requires several pages to explain; see the relevant section in the language specification.
In the specific case you present, it just won't compile. But in other cases there are rules by which the compiler may prefer one overload to another and resolve the conflict.
The most important rule is that, in general, if one method is more specific than the others, that method is picked. Method A is more specific than method B if all possible invocations of method A would also compile if calling method B. This usually means that some of the formal parameter(s) of method A are subclassed from the corresponding formal parameter(s) in method B. There are a few cases where this won't apply, such as when auto-boxing or other "method conversion" would be required to make an argument fit in the otherwise "more specific" case. For specifics, see the spec.
During navigation of the java.lang.reflect.Method class I came across the method isBridge. Its Javadoc says that it returns true only if the Java spec declares the method as true.
Please help me understand what this is used for! Can a custom class declare its method as a bridge if required?
A bridge method may be created by the compiler when extending a parameterized type whose methods have parameterized arguments.
You can find in this class BridgeMethodResolver a way to get the actual Method referred by a 'bridge method'.
See Create Frame, Synchronize, Transfer Control:
As an example of such a situation, consider the declarations:
class C<T> { abstract T id(T x); }
class D extends C<String> { String id(String x) { return x; } }
Now, given an invocation
C c = new D();
c.id(new Object()); // fails with a ClassCastException
The erasure of the actual method being invoked, D.id(String) differs in its signature from that of the compile-time method declaration, C.id(Object). The former takes an argument of type String while the latter takes an argument of type Object. The invocation fails with a ClassCastException before the body of the method is executed.
Such situations can only arise if the program gives rise to an unchecked warning (§5.1.9).
Implementations can enforce these semantics by creating bridge methods. In the above example, the following bridge method would be created in class D:
Object id(Object x) { return id((String) x); }
This is the method that would actually be invoked by the Java virtual machine in response to the call c.id(new Object()) shown above, and it will execute the cast and fail, as required.
See also Bridge:
as mentioned in the comment, bridge methods are also needed for covariant overriding:
In Java 1.4, and earlier, one method can override another if the signatures match
exactly.
In Java 5, a method can override another if the arguments match exactly but the return type of the overriding method, if it is a subtype of the return type of the other method.
Typically, a method Object clone() can be overridden by a MyObject clone(), but a bridge method will be generated by the compiler:
public bridge Object MyObject.clone();
The example shown there (quoted from the JLS) makes it sound like bridge methods are only used in situations where raw types are used. Since this is not the case, I thought I'd pipe in with an example where bridge methods are used for totally type-correct generic code.
Consider the following interface and function:
public static interface Function<A,R> {
public R apply (A arg);
}
public static <A, R> R applyFunc (Function<A,R> func, A arg) {
return func.apply(arg);
}
If you use this code in the following way, a bridge method is used:
Function<String, String> lower = new Function<String, String>() {
public String apply (String arg) {
return arg.toLowerCase();
}
};
applyFunc(lower, "Hello");
After erasure, the Function interface contains the method apply(Object)Object (which you can confirm by decompiling the bytecode). Naturally, if you look at the decompiled code for applyFunc you'll see that it contains a call to apply(Object)Object. Object is the upper bound of its type variables, so no other signature would make sense.
So when an anonymous class is created with the method apply(String)String, it doesn't actually implement the Function interface unless a bridge method is created. The bridge method allows all generically typed code to make use of that Function implementation.
Interestingly, only if the class implemented some other interface with the signature apply(String)String and only if the method was called via a reference of that interface type would the compiler ever emit a call with that signature.
Even if I have the following code:
Function<String, String> lower = ...;
lower.apply("Hello");
The compiler still emits a call to apply(Object)Object.
There is actually one other way to get the compiler to call apply(String)String, but it takes advantage of the magical type assigned to an anonymous class creation expression which cannot otherwise be written down:
new Function<String, String>() {
public String apply (String arg) {
return arg.toLowerCase();
}
}.apply("Hello");
Another case I stumbled across has nothing to do with generics:
protected abstract class Super {
public void m() {}
}
public class Sub extends Super {}
assert Sub.class.getMethod("m").isBridge();