What wrong in last row?
interface I1<T>{}
class Class1 implements I1{}
class Class2 extends Class1 implements I1{} //valid
class Class3 implements I1<Number>{}
class Class4 extends Class3 implements I1<Number>{} //valid
class Class5 implements I1<Number>{}
class Class6 extends Class5 implements I1<Integer>{} //not valid
class Class7 implements I1{}
class Class8 extends Class7 implements I1<Number>{} // not valid
class Class9 implements I1<Number>{}
class Class10 extends Class9 implements I1{} // not valid !!!
Why I cannot make so?
I saw it in book, but there are not explanation of this thing - only for information.
P.S.
exception text:
java: GenericsTest.I1 cannot be inherited with different arguments:
<java.lang.Integer> and <java.lang.Number>
There are two points to understanding this:
I1<Number> and an I1<Integer> are distinct types. For most purposes, they are unrelated, despite that Integer extends Number.Now, what is not allowed is implementing an interface twice, where the generic type of the interface is different.
For example, this is not allowed:
class NotAllowed implements I1<String>, I1<Integer> {}
The types of I1 are erased at run time so you cannot do that. At run time there is not really a difference between an I1<String> and an I1<Integer>. Both of them become just I1.
Your example with Class5 and Class6 is not allowed for the same reason as the above NotAllowed is not allowed. It implements the same interface twice but with different generic types.
If it were allowed, it would be paradoxical, because for example given the following:
interface Face<T> {
public void method(T t);
}
If I then implement this twice with different types, it would imply there must be two generically-typed implementations of method:
class Implementation
implements Face<String>, Face<Integer> {
@Override
public void method(String s) {}
@Override
public void method(Integer i) {}
}
This is paradoxical because erasure also dictates that both implementations of method will become identical at run time. You cannot have methods with identical signatures declared in the same class so it's not allowed.
class Class1 implements I1{}
class Class2 extends Class1 implements I1{}
This one is obvious, it means that Class2 implements I1{}. It does it explicitly by saying implements I1{} but also implicitly by extending Class1, which implements I1{} as well. There's no problem since they both implement the same interface, it's not ambiguous.
class Class3 implements I1<Number>{}
class Class4 extends Class3 implements I1<Number>{}
This is the same flavor as above. It says Class4 implements I1<Number>. It's specified implicitly and explicitly as above. But it's not ambiguous, it's I1<Number>
Of course, it's redundant because it uses two way simultaneously to define that Class4 implements I1<Number>. You could just do class Class4 extends Class3 and it'd be exactly the same.
Now with this one it's different:
class Class5 implements I1<Number>{}
class Class6 extends Class5 implements I1<Integer>{}
It says Class6 is implementing both I1<Integer> (explicitly) and I1<Number> (implicitly through extending Class5). It can't be at the same time. Imagine for example that I1 has a method: public X something(). It's signature in I1<Number> would be public Number something() and in I1<Integer> it would be public Integer something(). This would lead to a duplicate method. It's therefore invalid. If you implement a generic interface, you can only implement it once, no matter the generic type.
I hope this helps illustrate why it's invalid.
EDIT
First, understand that I1 is semantically the same as I1<Object>.
Then, understand that I1<A> is not the same as I1<B>
Also, understand that all your invalid examples can be summarized (for reasons explained above) with:
class X implements I1<A>, I1<B>
Why is that invalid? Because it may create ambiguity in the signatures. If I1 looked like this:
public interface I1<T> {
public T something();
}
Then X would have to look something like:
class X implements I1<A>, I1<B> {
public A something() { return null; }
public B something() { return null; }
}
Now, if I did:
X x = new X();
x.something();
Which of the two methods is is calling? You can't tell, because it is ambiguous. The Java language just doesn't give you the opportunity to define ambiguous APIs. Therefore, you can't implement both I1<A> and I1<B>.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With