When overriding method i return type a subtype of the super method return type.
But why i can't do the same thing with the method parameter list.
Ex.
public class OverrideTest implements CustomersI {
#Override
public ArrayList<Customer> getCustomers(ArrayList<String> names) {
// TODO Auto-generated method stub
return null;
}
}
interface CustomersI{
List<Customer> getCustomers(List<String> names);
}
class Customer{
Customer(String name){
}
}
why i can change return type ArrayList instead of List and can't do the same with param list.
Because you wouldn't respect the contract of the interface. The interface method says: anyone can call me with any kind of List<String>. The class implements this interface, bu says: Anyone can call me, but not with any kind of List<String>: only ArrayList<String>. This is thus invalid, because the method doesn't fulfilled the contract declared in the interface.
Returning a more specific type doesn't have this problem. The interface method says: if you call me, you'll get a List<Customer> as a result. And the class method says: if you call me, you'll have a List as a result, and I can even be more precise: you'll get an ArrayList<Customer> as a result, which is a List<Customer>.
we can declare variable using super type and initialize to sub type.
CustomersI customers = new OverrideTest();
But in runtime, actual object OverrideTest() is acting.
When you you pass params to customers.getCustomers(..) according to your interface, it allows any sub type of List. but actual object (OverrideTest) only allowed ArrayList or its sub type.
for ex. suppose you are going to pass object of LinkedList<Customer>. Now your getCustomers in OverrideTest class is not allowed to pass this object. Therefore your implementation is wrong.
So, You cannot use sub-types as parameters but you can use supper types.
Because the function signature is different if parameter list is changed. For overriding the function signature has to remain same because when calling a function the function signature is matched.
The same idea allows overloading of functions where the called function is decided by the parameters compared with function signature.
Hope this helps
You can't change param list is because of the definition of method overriding.
The implementation in the subclass overrides (replaces) the implementation in the superclass by providing a method that has same name, same parameters or signature, and same return type as the method in the parent class.
You can change return type is because Java introduced Covariant return type in Java 5.
a covariant return type of a method is one that can be replaced by a "narrower" type when the method is overridden in a subclass.
Here is an example of using covariant return type when overriding Object.clone().
// class Object
protected native Object clone() throws CloneNotSupportedException;
// class Customer
#Override
protected Customer clone() throws CloneNotSupportedException {
...
}
Prior to Java 5 your overridden clone() method in Customer would also have to return Object and therefore a cast would be required.
Related
I'm experimenting with this code:
interface Callee {
public void foo(Object o);
public void foo(String s);
public void foo(Integer i);
}
class CalleeImpl implements Callee
public void foo(Object o) {
logger.debug("foo(Object o)");
}
public void foo(String s) {
logger.debug("foo(\"" + s + "\")");
}
public void foo(Integer i) {
logger.debug("foo(" + i + ")");
}
}
Callee callee = new CalleeImpl();
Object i = new Integer(12);
Object s = "foobar";
Object o = new Object();
callee.foo(i);
callee.foo(s);
callee.foo(o);
This prints foo(Object o) three times. I expect the method selection to take in consideration the real (not the declared) parameter type. Am I missing something? Is there a way to modify this code so that it'll print foo(12), foo("foobar") and foo(Object o)?
I expect the method selection to take
in consideration the real (not the
declared) parameter type. Am I missing
something?
Yes. Your expectation is wrong. In Java, dynamic method dispatch happens only for the object the method is called on, not for the parameter types of overloaded methods.
Citing the Java Language Specification:
When a method is invoked (§15.12), the
number of actual arguments (and any
explicit type arguments) and the
compile-time types of the arguments
are used, at compile time, to
determine the signature of the method
that will be invoked (§15.12.2). If
the method that is to be invoked is an
instance method, the actual method to
be invoked will be determined at run
time, using dynamic method lookup
(§15.12.4).
As mentioned before overloading resolution is performed at compile time.
Java Puzzlers has a nice example for that:
Puzzle 46: The Case of the Confusing Constructor
This puzzle presents you with two Confusing constructors. The main method invokes a constructor,
but which one? The program's output depends on the answer. What does the program print, or is it
even legal?
public class Confusing {
private Confusing(Object o) {
System.out.println("Object");
}
private Confusing(double[] dArray) {
System.out.println("double array");
}
public static void main(String[] args) {
new Confusing(null);
}
}
Solution 46: Case of the Confusing Constructor
...
Java's overload resolution process operates in two phases. The first phase selects all the methods or constructors that are accessible and applicable. The second phase selects the most specific of the methods or constructors selected in the first phase. One method or constructor is less specific than another if it can accept any parameters passed to the other [JLS 15.12.2.5].
In our program, both constructors are accessible and applicable. The constructor
Confusing(Object) accepts any parameter passed to Confusing(double[]), so
Confusing(Object) is less specific. (Every double array is an Object, but not every Object is a double array.) The most specific constructor is therefore Confusing(double[]), which explains the program's output.
This behavior makes sense if you pass a value of type double[]; it is counterintuitive if you pass null. The key to understanding this puzzle is that the test for which method or constructor is most specific does not use the actual parameters: the parameters appearing in the invocation.
They are used only to determine which overloadings are applicable. Once the compiler determines which overloadings are applicable and accessible, it selects the most specific overloading, using only the formal parameters: the parameters appearing in the declaration.
To invoke the Confusing(Object) constructor with a null parameter, write new
Confusing((Object)null). This ensures that only Confusing(Object) is applicable. More
generally, to force the compiler to select a specific overloading, cast actual parameters to the declared types of the formal parameters.
Ability to dispatch a call to a method based on types of arguments is called multiple dispatch. In Java this is done with Visitor pattern.
However, since you're dealing with Integers and Strings, you cannot easily incorporate this pattern (you just cannot modify these classes). Thus, a giant switch on object run-time will be your weapon of choice.
In Java the method to call (as in which method signature to use) is determined at compile time, so it goes with the compile time type.
The typical pattern for working around this is to check the object type in the method with the Object signature and delegate to the method with a cast.
public void foo(Object o) {
if (o instanceof String) foo((String) o);
if (o instanceof Integer) foo((Integer) o);
logger.debug("foo(Object o)");
}
If you have many types and this is unmanageable, then method overloading is probably not the right approach, rather the public method should just take Object and implement some kind of strategy pattern to delegate the appropriate handling per object type.
I had a similar issue with calling the right constructor of a class called "Parameter" that could take several basic Java types such as String, Integer, Boolean, Long, etc. Given an array of Objects, I want to convert them into an array of my Parameter objects by calling the most-specific constructor for each Object in the input array. I also wanted to define the constructor Parameter(Object o) that would throw an IllegalArgumentException. I of course found this method being invoked for every Object in my array.
The solution I used was to look up the constructor via reflection...
public Parameter[] convertObjectsToParameters(Object[] objArray) {
Parameter[] paramArray = new Parameter[objArray.length];
int i = 0;
for (Object obj : objArray) {
try {
Constructor<Parameter> cons = Parameter.class.getConstructor(obj.getClass());
paramArray[i++] = cons.newInstance(obj);
} catch (Exception e) {
throw new IllegalArgumentException("This method can't handle objects of type: " + obj.getClass(), e);
}
}
return paramArray;
}
No ugly instanceof, switch statements, or visitor pattern required! :)
Java looks at the reference type when trying to determine which method to call. If you want to force your code you choose the 'right' method, you can declare your fields as instances of the specific type:
Integeri = new Integer(12);
String s = "foobar";
Object o = new Object();
You could also cast your params as the type of the param:
callee.foo(i);
callee.foo((String)s);
callee.foo(((Integer)o);
If there is an exact match between the number and types of arguments specified in the method call and the method signature of an overloaded method then that is the method that will be invoked. You are using Object references, so java decides at compile time that for Object param, there is a method which accepts directly Object. So it called that method 3 times.
I am looking at the Java API from Oracle, particularly at this method that is part of the java.util.Arrays class:
public static <T> List<T> asList(T... a)
But how is it possible that this method is returning a List object when clearly it is an interface?
It is called polymorphism
It means you can refer to a subtype using supertype reference
In this case, the method is returning instances of class that implement the List interface
Source code of Arrays.asList method
public static <T> List<T> More ...asList(T... a) {
return new ArrayList<T>(a);
}
Any method that has an interface type as its return type actually returns an instance of some class that implements that interface. The point of having an interface type as the return type is allowing the developer of the method to change the implementation that the method returns without changing the API.
In the case of Arrays.asList, an instance of Arrays$ArrayList (a nested class inside the Arrays class) is returned.
Method will return the child class object. Check the source code of java
public static <T> List<T> More ...asList(T... a) {
return new ArrayList<T>(a);
}
http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/util/Arrays.java#Arrays.asList%28java.lang.Object%5B%5D%29
Read the polymorphism as well
http://www.tutorialspoint.com/java/java_polymorphism.htm
It is returning a reference to any instance of List. Now, any class that implements the List interface is also a List. example ArrayList is a List.
That being said, the method returns an instance of a List.
Note that the list instance returned cannot be cast explicitly to java.util.ArrayList, the actual instance returned is of type Arrays$ArrayList
I am using reflection APIs to do some queries on Java methods. Below is the code snippet to find out the return type of calling, say new java.lang.StringBuilder().append('a'):
Class<?> c = Class.forName("java.lang.StringBuilder");
Method[] mList = c.getMethods();
for (int i = 0; i < mList.length; i++) {
if (mList[i].getName() == "append"
&& mList[i].getParameterTypes().length == 1
&& mList[i].getParameterTypes()[0].getCanonicalName() == "char") {
System.out.println(mList[i]);
}
}
Oddly, the output gives
public java.lang.AbstractStringBuilder java.lang.StringBuilder.append(char)
public java.lang.Appendable java.lang.StringBuilder.append(char) throws java.io.IOException
public java.lang.StringBuilder java.lang.StringBuilder.append(char)
while the Java API Specification only gives StringBuilder as the return type. Does that mean the method append actually overloads on return type?
From javadocs we have :
Returns an array containing Method objects reflecting all the public
member methods of the class or interface represented by this Class
object, including those declared by the class or interface and those
inherited from superclasses and superinterfaces. Array classes return
all the (public) member methods inherited from the Object class. The
elements in the array returned are not sorted and are not in any
particular order. This method returns an array of length 0 if this
Class object represents a class or interface that has no public member
methods, or if this Class object represents a primitive type or void.
StringBuilder extends AbstractStringBuilder
AbstractStringBuilder implements Appendable
That's why you get 3 methods.
When you invoke c.getMethods() the resulting array will contain all the methods, that are defined in the StringBuilder class and it superclass(es)/superinterface(s).
That's why you get three instead of one.
Does that mean the method append actually overloads on return type?
No. Overloading is a term that is strongly related to the method signature definition. The method signature includes:
the method name
the method parameters
Overloading specifies two or more methods with the name, but different method signature. The return-type is not part of the method signature.
In your example, the three method definitions are not overloaded, but overridden versions of one and the same method abstraction.
Is it possible to invoke a method where the argument object or the argument class is a subclass and the method himself took the superclass as argument?
I trying to invoke this method public void setNewProblem(Problem problem); with a concrete implementation of the abstract class Problem. Unfortunately I get an NoSuchMethodException exception.
I call the invoke like this:
Method method = model.getClass().getMethod("set" + propertyName, new Class[] { newValue.getClass() });
method.invoke(model, newValue);
If I change newValue.getClass() to Problem.class everything works fine. Any idea how to pass a subclass to public void setNewProblem(Problem problem);?
You have to ask for the exact type it is. This is because you can have multiple possible overloaded methods and it needs to know exact what you wanted.
So you can invoke with a sub-class but you cannot ask for a sub-class without be being there.
What you can do is look at all methods and find a match.
If all you need is the setter or getter for a property, I suggest you look at BeanIntrospector which will find you all the properties and the getter/setter methods for that property.
The problem is that newValue.getClass() is a subclass of the class in the declared method.
From Class.getMethod:
To find a matching method in a class C: If C declares exactly one
public method with the specified name and exactly the same formal
parameter types, that is the method reflected.
You could work your way up the inheritance chain until it works:
Method getMethod(Class c1, Class c2) {
if(c2.getSuperClass() == null) {
return c1.getMethod("set" + propertyName, new Class[] { c2 });
}
try {
return c1.getMethod("set" + propertyName, new Class[] { c2 });
} catch(NoSuchMethodException e) {
return getMethod(c1, c2.getSuperClass());
}
}
Usage:
Method method = getMethod(model.getClass(), newValue.getClass());
I hesitate to suggest this, however, since it does not cover 100% of cases (such as if the formal argument class is an interface), and the way you are doing this is bad.
When you call Class.getMethod() you have to specify correctly the formal argument types. Not the types of the actual arguments you are planning to supply. You have to match precisely what it says in the declaration of the method concerned.
"The parameterTypes parameter is an array of Class objects that identify the method's formal parameter types, in declared order."
I really should know this, but for some reason I don't understand the following.
My abstract class contains the following abstract method:
protected abstract RuleDTO createRowToBeCloned(RuleDTO ruleDTO);
I also have another class as follows:
EvaluationRuleDTO extends from RuleDTO
Then in a subclass of my abstract class I have the following implementation which is not allowed due to "must override or implement a supertype method":
protected EvaluationRuleDTO createRowToBeCloned(EvaluationRuleDTO ruleDTO) {
However, the following is allowed:
protected EvaluationRuleDTO createRowToBeCloned(RuleDTO ruleDTO) {
I realize this is probably a basic question but I am a little bemused. How come I can I can return a subclass of RuleDTO in the overridden method, but I can't pass in a subclass?
Thanks
You're breaking the Liskov principle: everything a superclass can do, a subclass must be able to do. The superclass declares a method accepting any kind of RuleDTO. But in your subclass, you only accept instances of EvaluationRuleDTO. What would happen if you did the following?
RuleDTO rule = new EvaluationRuleDTO();
rule.createRowToBeCloned(new RuleDTO());
An EvaluationRuleDTO is a RuleDTO, so it must fulfill the contract defined by RuleDTO.
The method in the subclass may return an instance of EvaluationRuleDTO instead of a RuleDTO, though, because the contract is to return a RuleDTO, and EvaluationRuleDTO is a RuleDTO.
Java allows return type covariance for overrides, so you can specify the return type of an override as a more-derived type. However, Java does not allow parameter type covariance for overrides.
The reason the former is safe is that the object you return will have, at minimum, the functionality of the less-derived type, so a client relying on that fact will still be able to utilize the returned object correctly.
That's not the case for the arguments, though. If it were legal, a user could call the abstract method and pass in a less-derived type (since that's the type declared on the abstract class,) but then your derived override might try to access the argument as a more-derived type (which it isn't) resulting in an error.
In theory, Java could have allowed parameter-type contra-variance, since that is type-safe: if the overriden method only expects a less-derived argument, you can't accidentally utilize a method or field that's not there. Unfortunately, that is not currently available.
It is because when you override a method, you MUST use as parameter type the same type or a more general (wider) type, never a narrower type.
Just think about it. If you could override a method using a narrower type, you would break the polymorphism capability, don't you agree? So, doing this, you would break the Liskov Substitution Principle as JB Nizet said in his answer.
Java 1.5 has co-variant return types which why it is valid
The subclass method's return type R2 may be different from superclass
method's return type R1, but R2 should be a subtype of R1. i.e.,
subclass can return type may be a subtype of superclass return type.
In early java that was not the case, but it was changed in Java 5.0.
You cannot have two methods in the same class with signatures that only differ by return type. Until the J2SE 5.0 release, it was also true that a class could not override the return type of the methods it inherits from a superclass. In this tip you will learn about a new feature in J2SE 5.0 that allows covariant return types. What this means is that a method in a subclass may return an object whose type is a subclass of the type returned by the method with the same signature in the superclass. This feature removes the need for excessive type checking and casting.
Source: http://www.java-tips.org/java-se-tips/java.lang/covariant-return-types.html
This implies that the return types of the overriding methods will be subtypes of the return type of the overridden method.
Please see the following code:
class A {
A foo(A a) {
return new A();
}
}
class B extends A {
#Override
// Returning a subtype in the overriding method is fine,
// but using a subtype in the argument list is NOT fine!
B foo(B b) {
b.bar();
return new B();
}
void bar() {
// B specific method!
}
}
Yes ok, B IS AN A, but what happens if someone does:
B b = new B();
b.foo(new A());
A does not have a bar method.. This is why the argument can not be a subtype of the type of argument in the method being overridden.
Returning A or B in the overriding method is fine. The following snippet will compile and run just fine..
class A {
A foo(A a) {
return new B(); // B IS AN A so I can return B!
}
}
class B extends A {
#Override
B foo(A b) {
return new B(); // Overridden method returns A and
// B IS AN A so I can return B!
}
public static void main(String[] args) {
A b = new B();
final A foo = b.foo(new B());
// I can even cast foo to B!
B cast = (B) foo;
}
}