I have this two interfaces and classes:
public interface Identifiable {
T getId();
}
public interface GenericRepository
Why you cannot remove second K from,
public interface GenericRepository<T extends Identifiable<K>, K> {
So rather than having it as above, can we have it as
public interface GenericRepository<T extends Identifiable<K>> {
By this we can do what you want to do.
I don't think you can omit it. With T extends Identifiable<K>
you want to say that the generic type parameter must be an Identifiable
. Since Identifiable
is a generic class, you need to mention its generic type parameter too (if you want to play by the rules that is - if you omit it, you lose all generic type safety for GenericRepository
, due to backward compatibility rules). Note also that K
is actually used as the parameter type of GenericRepository.get
. And since that type may be different from T
, you need to satisfy the compiler by declaring it as another generic type parameter of GenericRepository
. Otherwise the compiler has no way of knowing what K
is.
Not much you can do, other than introduce an interface that just refines GenericRepository
public interface LongKeyedRepository<T extends Identifiable<Long>>
extends GenericRepository<T, Long> { {
//No new methods need to be defined
}
Then you can have
private LongKeyedRepository<MyEntity> myEntityRepository;
etc.
It's not redundant from the standpoint of the GenericRepository class. When it has methods like T get(K id)
, it can't know which types of the id
argument it can accept otherwise. You can write the following:
interface GenericRepository<T extends Identifiable<?>> {
T get(Object id);
}
Now you don't have to write Long
as a type parameter, but you lose the possibility to check if the get
method is used properly at compile time. So the type variable serves a specific purpose.
And as for the field declaration, when you have a generic type, you have to specify all the type variables it uses. Of course, you could argue that it would be neat if the language could understand that one of the parameter values can be inferred from the other one, but it is debatable.
It would work with (i.e. compile)
public interface GenericRepository<T extends Identifiable> {
T get(T id);
}
but it says nonetheless that Identifiable is a raw type and that it should be parametrized.
Hope it helps.
If I am not mistaken generics will all be compiled as if they were just Object
. Now the syntax is (hard) checked to ensure that you are not putting apple with oranges because generics were added after the initial design of Java. this is why generics are so constrained...