Does a method's signature in Java include its return type?
Quoting from Oracle Docs:
Definition: Two of the components of a method declaration comprise the method signature—the method's name and the parameter types.
Since the question was edited to include this example:
public class Foo {
public int myMethod(int param) {}
public char myMethod(int param) {}
}
No, the compiler won't know the difference, as their signature: myMethod(int param)
is the same. The second line:
public char myMethod(int param) {}
will give you can error: method is already defined in class, which further confirms the above statement.
The return type / return value is part of the signature of the method?
The return value of a method must strictly follow the return type of its method so you could technically use the two terms interchangeably when talking about method signatures which it looks like they've done in the excerpt, albeit confusing.
In the case of method overloading the return type is not considered part of the method signature as the compiler cannot determine on return type alone which methods to use and as such the return type is not included in the method signature. For example consider the following overloaded methods where only the return type differs:
public int GetResult() { }
public double GetResult() { }
If we were to call this method, how would the compiler know which method to use?
var result = GetResult();
However as the language definition states: the method name, number of generic types, number of and type of each formal parameter and out/ref/value parameters are part of the method signature when overloading so for example if you wanted to overload then you could do:
public int GetResult() { }
public int GetResult(int x) { }
There are cases where the return type of a method is considered part of the signature such as delegates since the method must have the same return type as the delegate declaration. As per the C# specification:
In the context of method overloading, the signature of a method does not include the return value. But in the context of delegates, the signature does include the return value. In other words, a method must have the same return type as the delegate.
Why is the return type of method not included in the method-signature?
This is done because the compiler would not be able to figure out the overload in all contexts.
For example, if you call
String x = method1("aaa");
the compiler knows that you are looking for the second overload. However, if you call
method1("aaa");
like this, the compiler has no idea which one of the two methods you wanted to invoke, because it is OK to call a method returning String
and discard the result. To avoid ambiguities like this, Java prohibits overloads that differ solely on the return type.
Why does java allow for overriding methods with subclass return types but not subclass parameters?
When parameters allow doing this, they are called contravariant parameters. When you do it with return types, they are called covariant return types. Java supports covariant return types but not contravariant parameters.
That would change the method signature and it will no longer be an override. Return types are not part of the method signature but the type and the number of parameters of the method are part of the signature, hence this would interfere with overloading.
Moreover, if Java allowed you to do that, that would cause unexpected behavior in some cases and break runtime polymorphism with virtual methods because you are narrowing down what the method could accept.
Imagine a scenario where some code or an API only exposes the base class to you. You call someMethod()
to receive a person:
public Person someMethod()
{
Child child = new Child();
return child;
}
This is how it would look like at the calling site:
Person receivedPerson = someMethod();
Person myPerson = new Person();
Person result = receivedPerson.getPerson(myPerson); // This will fail
Here, the caller does not know that someMethod()
has actually returned a Child
instead of a Person
. I would think the Person
class has a method called getPerson()
accepting an object of type Person
and therefore, I can call receivedPerson.getPerson(myPerson)
. But, as the derived type Child
which you don't even know about has changed the parameter type of getPerson()
to Child
, it will not be able to accept myPerson
because you cannot convert an object of the base class to an object of a derived class.
This will never happen with covariant return types because if a method returns a more specific type, say Child
instead of Person
, it can be easily stored in a Person
variable and child will always have all the state and behavior as that of its parent.
Can someone explain to me this method signature
Here's a complete runnable example.
package org.example;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.Future;
import java.util.function.Function;
import static java.util.stream.Collectors.toList;
public class SO62737345 {
public static void main(String... args) {
ForkJoinPool forkJoinPool = ForkJoinPool.commonPool();
List<Callable<String>> tasks = Collections.singletonList(() -> "fish");
List<String> result = forkJoinPool.invokeAll(tasks)
.stream()
.map(rethrowFunction(Future::get))
.collect(toList());
}
public static <T, R> Function<T, R> rethrowFunction(WithExceptionsIF<T, R> function) {
return t -> {
try {
return function.apply(t);
}
catch (Exception exception) { throwAsUnchecked(exception); return null; }
};
}
@FunctionalInterface
public interface WithExceptionsIF<T, R> {
R apply(T t) throws Exception;
}
@SuppressWarnings ("unchecked")
private static <E extends Throwable> void throwAsUnchecked(Exception exception) throws E { throw (E)exception; }
}
The
get()
method doesn't execute whenrethrowFunction
is called. The call torethrowFunction
just transforms the function passed in from one which throws a checked exception to one which doesn't (because any exception inwrapped in an unchecked exception). Thecollect()
method actually calls the function, once for eachFuture
in the Stream.Think about passing
Future::get
using a lambda rather than a method reference. It would bef -> f.get()
. because we are passing a member function it takes the object it belongs to as a parameter. SO we are passing a function, and as the signature of get() isV get() throws InterruptedException, ExecutionException
it matchesWithExceptionsIF
. In fact it is an instance ofWithExceptionsIF<Future,String>
in this particular case.If you expand this by substituting the lambda above, you get:
return (f -> f.get()).apply(t)
soget is being applied to the parameter being passed when the function which
rethrowFunction` returns is evaluated.This is explained here A peculiar feature of exception type inference in Java 8
Java is performing 'type inference'. The compiler has been told thatthrowAsUnchecked
throws an object whose class is a subclass of Throwable. Because the return type ofrethrowFunction
does not declare a checked exception, the compiler decides thatthrowAsUnchecked
must be throwing aRuntimeException
. Another way of looking at it is that the type parameter in this case has its value inferred from the context the function is invoked in, rather than from its parameters. At least I think that's how it works, it is not that easy to understand!
Explaining that generic syntax more generally, often a method is part of a parameterised type, e.g. List<A>
, so the type parameter can appear in the signature of member functions, e.g. A get(int i)
. You can also have a generic function whose signature has type parameters which do not appear in the class (or a static function which is not associated with an instance of the class), and here they are declared before the return type.
If an instance method in the subclass has the same signature and a DIFFERENT return type, is it a overriding method or a new method?
No when you have DIFFERENT return type, that is completely a new method. Not overridden.
Return type is also part of method signature. You need to obey all the rules to override.
And interesting part to note here is Covariance
Consider you have Parent and Child relationship and trying to override the methods of Parent in Child, Co-variance means that the overriding method returning a more specific type. Below example shows you the same, Parent method returning Object and where as the Child method decided to return a specific type (String) where String is child of Object class. Hence covariance existed here.
Covariant return types :
public class Parent{
public Object doSomething(){}
}
public class Child extends Parent{
public String doSomething() {}
}
If you are interested give a read on my blog post : http://codeinventions.blogspot.in/2014/11/covariant-contravariant-and-class-invariant-example-and-difference-in-java.html
Related Topics
Google Gson Linkedtreemap Class Cast to Myclass
"Hello World" Android App with as Few Files as Possible, No Ide, and Text Editor Only
Android: Cannot Perform This Operation Because the Connection Pool Has Been Closed
Should I Strictly Avoid Using Enums on Android
How to Print to the Console in Android Studio
Tm.Getdeviceid() Is Deprecated
PDF Library to Rendering the PDF Files in Android
How to Check If Class Exists Somewhere in Package
Android Runtime Permissions- How to Implement
Listview Viewholder Checkbox State
Does Proguard Work to Obfuscate Static String Constants
Custom Progress Bar in Android
How to Use Flood Fill Algorithm in Android
Multiple Dex Files Define Landroid/Support/Annotation/Animres
How to Change the Edittext Text Without Triggering the Text Watcher