Generic Method Covariance - valid restriction or compiler oversight? - java

Does anyone know the definitive answer to why the following isn't allowed by the java compiler?
class BaseClass {
public <T extends Number> T getNumber(){
return null;
}
}
class SubClass extends BaseClass{
#Override
public <T extends Integer> T getNumber(){
return null;
}
}
this causes the compiler to complain with:
"The method getNumber() of type SubClass must override a superclass method"
Now, when I put this to my colleagues some have tried to explain that it will cause confusion with the compiler. However, as was also pointed out the following, which is conceptually similar, is compilable.
class BaseClass<T extends Number> {
public T getNumber(){
return null;
}
}
class SubClass<T extends Integer> extends BaseClass<T>{
#Override
public T getNumber(){
return null;
}
}
This can be abused if the subclass calls the super implementation, but the compiler provides a warning to this effect. My only conclusion is that this is a compiler oversight on the part of folks at Sun (can't bring myself to say Oracle :-S).
Anyone have the definitive answer to this one?

Suppose it would indeed be allowed to add more restrictions to the type parameter on a derived class.
Then what if your class also had a <T extends Number> void setNumber(T number) method?
BaseClass foo = new SubClass();
long longValue = 42;
foo.<Long>setNumber(longValue);
The above would be accepted by the compiler because BaseClass.setNumber accepts any type parameter derived from Number. But the actual instance only accepts integers!
You could argue that if the type parameter is only used for the return value, it should automatically be considered covariant. But then the compiler would have to make sure that you don't use the type parameter inside the method body in a non-covariant way.
(In C# 4.0 this was actually solved, but it involves explicitly marking your type parameters as covariant or contravariant with the out and in keywords. It was not something that could simply be allowed by the compiler without changing the language.)

Because there is no covariance here. Covariance means 'varies with', and it refers to the return type varying as the containing class type. That's not happening here. There is no 'co' in your covariance.

#Wim Coenen provided a good answer.
Here is a small clarification.
If this would compile, what would you expect happened:
import java.math.BigInteger;
class BaseClass {
public <T extends Number> T getNumber(T n) {
System.out.println("Int value: " + n.intValue());
return n;
}
}
class SubClass extends BaseClass {
#Override
public <T extends BigInteger> T getNumber(T n) {
System.out.println("Int value: " + n.intValue());
// BigInteger specific!
System.out.println("Bit count: " + n.bitCount());
return n;
}
}
public class Main {
public static void main(String[] args) {
BaseClass sub = new SubClass();
// sub looks like a BaseClass...
// ...but since it's a SubClass it expects a BigInteger!
sub.getNumber(new Integer(5));
}
}

I don't quite follow your issue:
When I implemented your first portion of source code and compiled using javac *.java, it compiled fine. However, if I changed your SubClass.getNumber() method to do this...
/* (non-Javadoc)
* #see constraint.base.BaseClass#getNumber()
*/
#Override
public <T extends Number> T getNumber() {
// TODO Auto-generated method stub
return super.getNumber();
}
I get the following error:
SubClass.java:18: type parameters of <T>T cannot be determined; no unique maximal instance exists for type variable T with upper bounds T,java.lang.Number
return super.getNumber();
^
1 error
The reason for the code above is that by calling super.getNumber(), the compiler doesn't have any input that infer type T hence it cannot determine what T will be returned by super.getNumber() and, thus it can't satisfy the return type with SubClass.getNumber()
Now, in order to have obtained the error from the compiler, "The method getNumber() of type SubClass must override a superclass method", your BaseClass should have been abstract along with it's getNumber() method.
As for the 2nd piece of code you've provided, the subclass can, in effect, call super.getNumber() as the compiler will know (on compiling) that the SubClass's Generic Parameter Type is inferred to the Parameter Type of BaseClass.
Besides that, I really didn't know what you were trying to ask.

Related

why implementing interface's methods is same as overriding? [duplicate]

What is a covariant return type in Java? In object-oriented programming in general?
Covariant return, means that when one overrides a method, the return type of the overriding method is allowed to be a subtype of the overridden method's return type.
To clarify this with an example, a common case is Object.clone() - which is declared to return a type of Object. You could override this in your own class as follows:
public class MyFoo
{
...
// Note covariant return here, method does not just return Object
public MyFoo clone()
{
// Implementation
}
}
The benefit here is that any method which holds an explicit reference to a MyFoo object will be able to invoke clone() and know (without casting) that the return value is an instance of MyFoo. Without covariant return types, the overridden method in MyFoo would have to be declared to return Object - and so calling code would have to explicitly downcast the result of the method call (even thought both sides "know" it can only ever be an instance of MyFoo).
Note that there's nothing special about clone() and that any overridden method can have a covariant return - I used it as an example here as it's a standard method where this is often useful.
Here is another simple example :
Animal class
public class Animal {
protected Food seekFood() {
return new Food();
}
}
Dog class
public class Dog extends Animal {
#Override
protected Food seekFood() {
return new DogFood();
}
}
It’s possible to modify the return type of the Dog’s seekFood() method to DogFood - a subclass of Food, as shown below:
#Override
protected DogFood seekFood() {
return new DogFood();
}
That’s perfectly a legal overriding, and the return type of Dog’s seekFood() method is known as covariant return type.
From the release of JDK 1.5, covariant types were introduced in Java. and I'll explain it to you with a simple case, : When we override a function the function is allowed to make changes to it's behaviour that's what you get to read in most of the books, but what they { authors } miss out on is that we can change the return type too.
check below link for clarification we can change the return type as long as it can be assigned to return type of Base version of the method.
So this feature of returning derived types is called COVARIANT...
Can overridden methods differ in return type?
covariant Return types simply means returning own Class reference or its child class reference.
class Parent {
//it contain data member and data method
}
class Child extends Parent {
//it contain data member and data method
//covariant return
public Parent methodName() {
return new Parent();
or
return Child();
}
}
To add to the above answers, overriding is possible among co-variant return types, with the constraint that the return type of the overriding method (subclass method) should be a subclass of the return type of the overridden method (superclass method). This is valid from Java 5 onwards.
Covariant return type specifies that the return type may vary in the same direction as the subclass
class One{
One get(){return this;}
}
class Two extends One{
Two get(){return this;}
void message(){
System.out.println("After Java5 welcome to covariant return type");
}
public static void main(String args[]){
new Two().get().message();
}
}
Before Java 5, it was not possible override any method
by changing the return type. But now, since Java5,
it is possible to override method by changing the return type
if subclass overrides any method
whose return type is Non-Primitive
but it changes its return type to subclass type.
It helps to avoid confusing type casts present in the class hierarchy
and thus making the code readable, usable and maintainable.
We get a liberty to have more specific return types when overriding
methods.
Help in preventing run-time ClassCastExceptions on returns
reference:
www.geeksforgeeks.org
The covariant return type in java, allows narrowing down return type
of the overridden method.
This feature will help to avoid down casting
on the client side. It allows programmer to program without the need
of type checking and down casting.
The covariant return type always
works only for non-primitive return types.
interface Interviewer {
default Object submitInterviewStatus() {
System.out.println("Interviewer:Accept");
return "Interviewer:Accept";
}
}
class Manager implements Interviewer {
#Override
public String submitInterviewStatus() {
System.out.println("Manager:Accept");
return "Manager:Accept";
}
}
class Project {
public static void main(String args[]) {
Interviewer interviewer = new Manager();
interviewer.submitInterviewStatus();
Manager mgr = new Manager();
mgr.submitInterviewStatus();
}
}
Other example is from Java,
UnaryOperator.java
#FunctionalInterface
public interface UnaryOperator<T> extends Function<T, T> {
/**
* Returns a unary operator that always returns its input argument.
*
* #param <T> the type of the input and output of the operator
* #return a unary operator that always returns its input argument
*/
static <T> UnaryOperator<T> identity() {
return t -> t;
}
}
Function.java
#FunctionalInterface
public interface Function<T, R> {
........
........
........
........
static <T> Function<T, T> identity() {
return t -> t;
}
}
Before Java5, it was not possible to override any method by changing the return type. But now, since Java5, it is possible to override method by changing the return type if subclass overrides any method whose return type is Non-Primitive but it changes its return type to subclass type.

Java automatic return type covariance with generic subclassing

I have two interfaces that look like this:
interface Parent<T extends Number> {
T foo();
}
interface Child<T extends Integer> extends Parent<T> {
}
If I have a raw Parent object, calling foo() defaults to returning a Number since there is no type parameter.
Parent parent = getRawParent();
Number result = parent.foo(); // the compiler knows this returns a Number
This makes sense.
If I have a raw Child object, I would expect that calling foo() would return an Integer by the same logic. However, the compiler claims that it returns a Number.
Child child = getRawChild();
Integer result = child.foo(); // compiler error; foo() returns a Number, not an Integer
I can override Parent.foo() in Child to fix this, like so:
interface Child<T extends Integer> extends Parent<T> {
#Override
T foo(); // compiler would now default to returning an Integer
}
Why does this happen? Is there a way to have Child.foo() default to returning an Integer without overriding Parent.foo()?
EDIT: Pretend Integer isn't final. I just picked Number and Integer as examples, but obviously they weren't the best choice. :S
This is based on ideas of #AdamGent .
Unfortunately I am not fluent with JLS enough to prove the below from the spec.
Imagine public interface Parent<T extends Number> was defined in a different compilation unit - in a separate file Parent.java.
Then, when compiling Child and main, the compiler would see method foo as Number foo(). Proof:
import java.lang.reflect.Method;
interface Parent<T extends Number> {
T foo();
}
interface Child<R extends Integer> extends Parent<R> {
}
public class Test {
public static void main(String[] args) throws Exception {
System.out.println(Child.class.getMethod("foo").getReturnType());
}
}
prints:
class java.lang.Number
This output is reasonable as java does type erasure and is not able to retain T extends in the result .class file plus because method foo() is only defined in Parent. To change the result type in the child compiler would need to insert a stub Integer foo() method into the Child.class bytecode. This is because there remains no information about generic types after compilation.
Now if you modify your child to be:
interface Child<R extends Integer> extends Parent<R> {
#Override R foo();
}
e.g. add own foo() into the Child the compiler will create Child's own copy of the method in the .class file with a different but still compatible prototype Integer foo(). Now output is:
class java.lang.Integer
This is confusing of course, because people would expect "lexical visibility" instead of "bytecode visibility".
Alternative is when compiler would compile this differently in two cases: interface in the same "lexical scope" where compiler can see source code and interface in a different compilation unit when compiler can only see bytecode. I don't think this is a good alternative.
The Ts aren't exactly the same. Imagine that the interfaces were defined like this instead:
interface Parent<T1 extends Number> {
T1 foo();
}
interface Child<T2 extends Integer> extends Parent<T2> {
}
The Child interface extends the Parent interface, so we can "substitute" the formal type parameter T1 with the "actual" type parameter which we can say is "T2 extends Integer":
interface Parent<<T2 extends Integer> extends Number>
this is only allowed because Integer is a subtype of Number. Therefore, the signature of foo() in the Parent interface (after being extended in the Child interface) is simplified to:
interface Parent<T2 extends Number> {
T2 foo();
}
In other words, the signature is not changed. The method foo() as declared in the Parent interface continues to return Number as the raw type.

Instantiate and apply generic method with unknown generic type - Java

I need to instantiate an object with an unknown generic type and then apply a generic method to it. Here is where I stand :
public static void main(String[] args)
{
BarIf bar = newRandomBarImpl();
Foo foo1 = newFooBar(bar.getClass()); // warning
Foo<?> foo2 = newFooBar(bar.getClass()); // error
Foo<? extends BarIf> foo3 = newFooBar(bar.getClass()); // error
foo1.doSomething(bar); // warning
foo2.doSomething(bar); // error
foo3.doSomething(bar); // error
}
static <T extends FooIf<S>, S extends BarIf> T newFooBar(Class<S> barClass){}
static <T extends BarIf> T newRandomBarImpl(){}
interface FooIf<T extends BarIf>
{
public void doSomething(T t);
}
interface BarIf{}
class Foo<T extends BarIf> implements FooIf<T>
{
public void doSomething(T t){}
}
The strange thing is that for foo2 and foo3, the newFooBar() method returns FooIf rather than Foo. I guess the type inference is messy. But I can't pass the method generic parameters since I don't know the Bar type.
What I would need is Foo<bar.getClass()>. Is there a way to do it?
I tried using TypeToken but I end up with a T type rather than the actual Bar type. Any chance using that?
First of all, a declaration like
static <T extends BarIf> T newRandomBarImpl(){}
is nonsense. It basically says “whatever the caller substitutes for T, the method will return it”. In other words, you can write
ArbitraryTypeExtendingBarIf x=newRandomBarImpl();
without getting a compiler warning. Obviously, that can’t work. newRandomBarImpl() doesn’t know anything about ArbitraryTypeExtendingBarIf. The method name suggests that you actually want to express that newRandomBarImpl() can return an arbitrary implementation of BarIf, but that’s an unnecessary use of Generics,
BarIf newRandomBarImpl(){}
already expresses that this method can return an arbitrary subtype of BarIf. In fact, since BarIf is an abstract type, this method must return a subtype of BarIf and it’s nowhere specified which one it will be.
The same applies to the declaration
static <T extends FooIf<S>, S extends BarIf> T newFooBar(Class<S> barClass){}
It also claims that the caller can choose which implementation of FooIf the method will return. The correct declaration would be
static <S extends BarIf> FooIf<S> newFooBar(Class<S> barClass){}
as the method decides which implementation of FooIf it will return, not the caller.
Regarding your other attempts to deal with FooIf, you can’t work this way using a type parametrized with a wildcard, nor can you fix it using Reflection. But you can write generic code using a type parameter:
public static void main(String[] args)
{
BarIf bar = newRandomBarImpl();
performTheAction(bar.getClass(), bar);
}
static <T extends BarIf> void performTheAction(Class<T> cl, BarIf obj) {
FooIf<T> foo=newFooBar(cl);
foo.doSomething(cl.cast(obj));
}
static <S extends BarIf> FooIf<S> newFooBar(Class<S> barClass){}
static BarIf newRandomBarImpl(){}
interface FooIf<T extends BarIf> {
public void doSomething(T t);
}
interface BarIf{}
The method performTheAction is generic, in other words, works with an unknown type expressed as type parameter T. This method can be invoked with an unknown type ? extends BarIf as demonstrated in the main method.
However, keep in mind, that every reference to a type X implies that the referred object might have a subtype of X without the need to worry about it.
You can simply use the base class BarIf here, regardless of which actual subtype of BarIf the object has:
BarIf bar = newRandomBarImpl();
FooIf<BarIf> foo=newFooBar(BarIf.class);
foo.doSomething(bar);
Note that when you want to use methods of the actual implementation type Foo, not specified in the interface, you will have to cast the FooIf to Foo. You can cast a FooIf<BarIf> to Foo<BarIf> without a warning as the generic type conversion is correct if Foo<X> implements FooIf<X>.
However, it can fail at runtime as the method newFooBar is not required to return an instance of Foo rather than any other implementation of FooIf. That’s why an explicit type cast is the only correct solution as it documents that there is an assumption made about the actual runtime type of an object. All other attempts will generate at least one compiler warning somewhere.

Can overridden methods differ in return type?

Can overridden methods have different return types?
Java supports* covariant return types for overridden methods. This means an overridden method may have a more specific return type. That is, as long as the new return type is assignable to the return type of the method you are overriding, it's allowed.
For example:
class ShapeBuilder {
...
public Shape build() {
....
}
class CircleBuilder extends ShapeBuilder{
...
#Override
public Circle build() {
....
}
This is specified in section 8.4.5 of the Java Language Specification:
Return types may vary among methods that override each other if the return types are reference types. The notion of return-type-substitutability supports covariant returns, that is, the specialization of the return type to a subtype.
A method declaration d1 with return type R1 is return-type-substitutable for another method d2 with return type R2, if and only if the following conditions hold:
If R1 is void then R2 is void.
If R1 is a primitive type, then R2 is identical to R1.
If R1 is a reference type then:
R1 is either a subtype of R2 or R1 can be converted to a subtype of R2 by unchecked conversion (§5.1.9), or
R1 = |R2|
("|R2|" refers to the erasure of R2, as defined in §4.6 of the JLS.)
* Prior to Java 5, Java had invariant return types, which meant the return type of a method override needed to exactly match the method being overridden.
Yes it may differ but there are some limitations.
Before Java 5.0, when you override a method, both parameters and return type must match exactly. Java 5.0 it introduces a new facility called covariant return type. You can override a method with the same signature but return a subclass of the object returned.
In another words, a method in a subclass can return an object whose type is a subclass of the type returned by the method with the same signature in the superclass.
Yes, if they return a subtype. Here's an example:
package com.sandbox;
public class Sandbox {
private static class Parent {
public ParentReturnType run() {
return new ParentReturnType();
}
}
private static class ParentReturnType {
}
private static class Child extends Parent {
#Override
public ChildReturnType run() {
return new ChildReturnType();
}
}
private static class ChildReturnType extends ParentReturnType {
}
}
This code compiles and runs.
Broadly speaking yes return type of overriding method can be different. But it's not straight forward as there are some cases involved in this.
Case 1: If the return type is a primitive data type or void.
Output: If the return type is void or primitive then the data type of parent class method and overriding method should be the same.
e.g. if the return type is int, float, string then it should be same
Case 2: If the return type is derived data type:
Output: If the return type of the parent class method is derived type then the return type of the overriding method is the same derived data type of subclass to the derived data type.
e.g. Suppose I have a class A, B is a subclass to A, C is a subclass to B and D is a subclass to C; then if the super class is returning type A then the overriding method in subclass can return either A, or B/C/D type i.e. its sub types. This is also called as covariance.
yes It is possible.. returns type can be different only if parent class method return type is
a super type of child class method return type..
means
class ParentClass {
public Circle() method1() {
return new Cirlce();
}
}
class ChildClass extends ParentClass {
public Square method1() {
return new Square();
}
}
Class Circle {
}
class Square extends Circle {
}
If this is the then different return type can be allowed...
The other answers are all correct, but surprisingly all leaving out the theoretical aspect here: return types can be different, but they can only restrict the type used in the super class because of the Liskov Substitution Principle.
It is super simple: when you have "client" code that calls some method:
int foo = someBar.bar();
then the above has to work (and return something that is an int no matter which implementation of bar() is invoked).
Meaning: if there is a Bar subclass that overrides bar() then you still have to return something that doesn't break "caller code".
In other words: assume that the base bar() is supposed to return int. Then a subclass could return short - but not long because callers will be fine dealing with a short value, but not a long!
well, the answer is yes... AND NO.
depends on the question. everybody here answered regarding Java >= 5, and some mentioned that Java < 5 does not feature covariant return types.
actually, the Java language spec >= 5 supports it, but the Java runtime does not. in particular, the JVM was not updated to support covariant return types.
in what was seen then as a "clever" move but ended up being one of the worst design decisions in Java's history, Java 5 implemented a bunch of new language features without modifying the JVM or the classfile spec at all. instead all features were implemented with trickery in javac: the compiler generates/uses plain classes for nested/inner classes, type erasure and casts for generics, synthetic accessors for nested/inner class private "friendship", synthetic instance fields for outer 'this' pointers, synthetic static fields for '.class' literals, etc, etc.
and covariant return types is yet more syntactic sugar added by javac.
for example, when compiling this:
class Base {
Object get() { return null; }
}
class Derived extends Base {
#Override
#SomeAnnotation
Integer get() { return null; }
}
javac will output two get methods in the Derived class:
Integer Integer:Derived:get() { return null; }
synthetic bridge Object Object:Derived:get() { return Integer:Derived:get(); }
the generated bridge method (marked synthetic and bridge in bytecode) is what actually overrides Object:Base:get() because, to the JVM, methods with different return types are completely independent and cannot override each other. to provide the expected behavior, the bridge simply calls your "real" method. in the example above, javac will annotate both bridge and real methods in Derived with #SomeAnnotation.
note that you cannot hand-code this solution in Java < 5, because bridge and real methods only differ in return type and thus they cannot coexist in a Java program. but in the JVM world, method return types are part of the method signature (just like their arguments) and so the two methods named the same and taking the same arguments are nonetheless seen as completely independent by the JVM due to their differing return types, and can coexist.
(BTW, the types of fields are similarly part of the field signature in bytecode, so it is legal to have several fields of different types but named the same within a single bytecode class.)
so to answer your question fully: the JVM does not support covariant return types, but javac >= 5 fakes it at compile time with a coating of sweet syntactic sugar.
The return type must be the same as, or a subtype of, the return type declared
in the original overridden method in the superclass.
Overriding and Return Types, and Covariant Returns the subclass must define a method that matches the inherited version exactly. Or, as of Java 5, you're allowed to change the return type in the sample code
class Alpha {
Alpha doStuff(char c) {
return new Alpha();
}
}
class Beta extends Alpha {
Beta doStuff(char c) { // legal override in Java 1.5
return new Beta();
}
} } As of Java 5, this code will compile. If you were to attempt to compile this code with a 1.4 compiler will say attempting to use incompatible return type – sandeep1987 1 min ago
class Phone {
public Phone getMsg() {
System.out.println("phone...");
return new Phone();
}
}
class Samsung extends Phone{
#Override
public Samsung getMsg() {
System.out.println("samsung...");
return new Samsung();
}
public static void main(String[] args) {
Phone p=new Samsung();
p.getMsg();
}
}
YES it can be possible
class base {
base show(){
System.out.println("base class");
return new base();
}
}
class sub extends base{
sub show(){
System.out.println("sub class");
return new sub();
}
}
class inheritance{
public static void main(String []args) {
sub obj=new sub();
obj.show();
}
}
Yes. It is possible for overridden methods to have different return type .
But the limitations are that the overridden method must have a return type that is more specific type of the return type of the actual method.
All the answers have given examples of the overridden method to have a return type which is a subclass of the return type of the actual method.
For example :
public class Foo{
//method which returns Foo
Foo getFoo(){
//your code
}
}
public class subFoo extends Foo{
//Overridden method which returns subclass of Foo
#Override
subFoo getFoo(){
//your code
}
}
But this is not only limited to subclass.Even classes that implement an interface are a specific type of the interface and thus can be a return type where the interface is expected.
For example :
public interface Foo{
//method which returns Foo
Foo getFoo();
}
public class Fizz implements Foo{
//Overridden method which returns Fizz(as it implements Foo)
#Override
Fizz getFoo(){
//your code
}
}

Java Generics Class Parameter Type Inference

Given the interface:
public interface BasedOnOther<T, U extends BasedList<T>> {
public T getOther();
public void staticStatisfied(final U list);
}
The BasedOnOther<T, U extends BasedList<T>> looks very ugly in my use-cases. It is because the T type parameter is already defined in the BasedList<T> part, so the "uglyness" comes from that T needs to be typed twice.
Problem: is it possible to let the Java compiler infer the generic T type from BasedList<T> in a generic class/interface definition?
Ultimately, I'd like to use the interface like:
class X implements BasedOnOther<Y> {
public SomeType getOther() { ... }
public void staticStatisfied(final Y list) { ... }
} // Does not compile, due to invalid parameter count.
Where Y extends BasedList<SomeType>.
Instead:
class X implements BasedOnOther<SomeType, Y> {
public SomeType getOther() { ... }
public void staticStatisfied(final Y list) { ... }
}
Where Y extends BasedList<SomeType>.
Update: ColinD suggested
public interface BasedOnOther<T> {
public T getOther();
public void staticSatisfied(BasedList<T> list);
}
It is impossible to create an implementation such as:
public class X implements BasedOnOther<SomeType> {
public SomeType getOther() { ... }
public void staticStatisfied(MemoryModel list);
} // Does not compile, as it does not implement the interface.
Where MemoryModel extends BasedList<SomeType>, which is needed (as it provides other methods).
It looks as if you don't actually need the type parameter U extends BasedList<T>, if you don't actually need to do anything in the class that requires some specific subclass/implementation of BasedList<T>. The interface could just be:
public interface BasedOnOther<T> {
public T getOther();
public void staticSatisfied(BasedList<T> list);
}
Edit: Based on your update, I don't think there's any way you can do this. I think you'll have to either just go with your original declaration or make some intermediate type that specifies T, like:
public interface BasedOnSomeType<U extends BasedList<SomeType>>
extends BasedOnOther<SomeType, U>
{
}
public class X implements BasedOnSomeType<MemoryModel> { ... }
That seems like kind of a waste though, and I don't really think the original declaration looks that bad.
What about this?
public interface BasedOnOther<T> {
public T getOther();
public <U extends BasedList<T>> void staticStatisfied(final U list);
}
ColinD is almost correct. What you probably want is this:
public interface BasedOnOther<T> {
public T getOther();
public void staticSatisfied(BasedList<? extends T> list);
}
That's because method arguments are covariant but the generics are invariant. Look at this example:
public test() {
Number n1;
Integer n2; //Integer extends Number. Integer is a more-specific type of Number.
n1 = n2; //no problem
n2 = n1; //Type mismatch because the cast might fail.
List<Number> l1;
List<Integer> l2;
List<? extends Number> l3;
l1 = l3; //No problem.
l1 = l2; //Type mismatch because the cast might fail.
}
Why:
Trying to put an Integer where a Number belongs is covariance and it's usually correct for function arguments.
Trying to put a Number where an Integer belongs is the opposite, contravariance, and it's usually correct for function return values. For example, if you defined a function to return a Number, it could return an Integer. If you defined it to return an Integer, however, you couldn't return a Number because that might be a floating-point, for example.
When you're dealing with generics, the compiler can't tell if the generic parameter (in your case, T) is going to be covariant or contravariant. In your code, for example, T is once a return value and once part of an argument. For that reason, generic parameters are invariant by default.
If you want covariance, use <? extends T>. For contravariance, use <? super T>. As a rule of thumb, you probably always want to specify the covariance/contravariance on all public functions. For private functions it doesn't matter as much because you usually already know the types.
This isn't specific to java, other object-oreiented languages have similar issue.
I recently had a very similar problem.
I would suggest, if you are do not need to specifically refer to MemoryModel, i.e. if U extends BasedList<T> is enough, then I would definitely do what Pepe answered.
However, if you must type check for at least two methods that both methods must use MemoryModel specifically and the type inferencing in Pepe's answer is not enough, then the only way to make the use of the clumsy/verbose parameterized constructor more simplistic, is to exploit the generic method parameter inferencing. You would need to create generic static factory methods for each constructor, where the factory methods do the type inferencing (constructors can't type inference in Java).
How to do this is covered in
Effective Java, by Joshua Block; Item 27: Favor generic methods
I also explained this and quoted the solution (with code) here.

Categories

Resources