Questw
Questw

Reputation: 43

What does diamond operator do when we need one more parameter in generic class?

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

Answers (3)

newacct
newacct

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:

  • The compiler could try to "infer" some exact type argument for each of the type parameters, and check that that choice works with the arguments and return context; or
  • The compiler could try to prove that there exists at least one choice of type argument that would make it compile and make the type checking work, and as long as it can prove that there exists at least one, it does not need to choose which one of them it is, since the actual type argument is not used when emitting the bytecode.

Upvotes: 0

deduper
deduper

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 GenericSubTwo<Object, Integer>() as if you did GenericBase<Integer> sub2 = new GenericSubTwo<Integer, Object>().

Upvotes: 1

Andreas
Andreas

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

Related Questions