Reputation: 43
class GenericBase<T> {
private T baseVariable;
public T get() {
return baseVariable;
}
public void set(T t){
baseVariable = t;
}
}
class GenericSubTwo<T, V> extends GenericBase<T>{
private V subVariable2;
public V get2(){
return subVariable2;
}
}
public TestClass{
public static void main(String[] args){
GenericBase<Integer> sub2 = new GenericSubTwo<>();
}
}
Is it true that diamond operator in this situation actually make new GenericSubTwo<Integer, Integer>(); or maybe something else.. I do not understand what is going on, because in GenericSubTwo I need two parameters..
Upvotes: 3
Views: 423
Reputation: 122429
This is kind of a philosophical question, because in the compiled bytecode, there is no difference between new GenericSubTwo<Integer, Object>()
, new GenericSubTwo<String, String>()
, and new GenericSubTwo()
. So if you say it uses a particular type argument, but it doesn't affect the result, does it really exist?
Remember that objects do not know their generic type arguments at runtime, so when creating an object at runtime, you do not need to know the generic type arguments. The generic type arguments provided in the new
are only used at compile-time for type checking purposes (e.g. to check consistency with argument types, if any, and to check if that return type works). After the type checking, those type arguments don't matter anymore, as they are not emitted into the compiled bytecode. In this particular case, since the constructor has no parameters, and the return values is assigned to a GenericBase<Integer>
where the V
of GenericSubTwo<T, V>
is not used, there are no constraints on what V
can be.
So we can think of different ways the compiler thinks about an object creation expression with the diamond:
Upvotes: 0
Reputation: 1964
„Is it true that diamond operator in this situation actually make new GenericSubTwo<Integer, Integer>();“
No. That's untrue.
„or maybe something else“
Yes. Something else. And that „something else“ is Object
. That's because of Type Erasure.
So, the actual parameterized type you'd have would be as if you did GenericSubTwo<Object, Integer>()
GenericBase<Integer> sub2 = new GenericSubTwo<Integer, Object>()
.
Upvotes: 1
Reputation: 159086
It really doesn't matter, because you cannot see what V
is anyway.
V
inferred to be Object
, since that is the bound on V
.
UPDATE
Actually, it seems V
is inferred to be ?
, because it can be cast to anything.
GenericBase<Integer> sub2 = new GenericSubTwo<>();
// Valid cast: T must be Integer, but V can be anything
GenericSubTwo<Integer, String> x = (GenericSubTwo<Integer, String>) sub2;
Upvotes: 4