简体   繁体   中英

Unspecified type parameter when calling generic method

Imagine we have the following generic class:

public class GenericClass<U> {
    private U value;

    public GenericClass(U value) {
        this.value = value;
    }
}

and the following generic method in some other class MyClass:

public <T extends BT, BT> void genericMethod(T arg) {
    Object genericClass = new GenericClass<BT>(arg);
}

Which value will BT type parameter obtain if we call

genericMethod("text");

?

Some notes:

The above code compiles without errors or warnings, which seems strange for me. Decompiling (by means of IntelliJ IDEA 2016) shows the following code:

public <T extends BT, BT> void genericMethod(T arg) {
    new MyClass.GenericClass(arg);
}

Notice that new GenericClass<BT>(arg) is not the same as new GenericClass(arg) because the latter is equivalent of new GenericClass<T>(arg) (type deduction), and although T extends BT , these are different types, and GenericClass may have internal logic where the exact type name plays an important role (eg is used as a string key in some map etc). So for me it is strange why the compiler silently uses type deduction instead of producing some warning (or maybe even error) stating that BT type parameter is not specified. Maybe I'm missing smth. important about generics in Java, however...

The first part of this answer will address the type inference part of your question

The only place where a type is automatically inferred in your example is when calling the genericMethod .

The definition of genericMethod declares two generic type parameters: an unbound BT and T which should be a subclass of BT .

Type T will be inferred according to the rules specified in Java language specification section 18.2.4 :

A constraint formula of the form ‹S = T›, where S and T are types, is reduced as follows:

...

Otherwise, if T is an inference variable, α, and S is not a primitive type, the constraint reduces to the bound S = α.

In your example you provide an object of type String as an argument of type T . According to the rule above, T will be inferred to be equal to String .

Now that T is fixed, the inference will proceed with BT . This type is inferred by following section 18.3.1 which says that an expression of type:

T extends BT, T == String

implies

String extends BT

This relationship allows the compiler to bind BT to String , thus you end up with the following implied call:

genericMethod<String,String>("text")

Hope this clears things up a bit.

To answer the second part of your question:

and although T extends BT, these are different types, and GenericClass may have internal logic where the exact type name plays an important role (eg is used as a string key in some map etc) .

Without adding more constraints, the compiler will treat T as equivalent to BT and will allow you to call only the methods defined as part of the BT type.

Unless you're doing something very weird using reflection, the code should not depend on the runtime value of type argument. The current GenericClass as it stands isn't very useful because U doesn't have any constraints so the compiler will allow you to do only things that are valid for all objects. You can consider U in that context the same as Object .

Based on this part of your question

GenericClass may have internal logic where the exact type name plays an important role (eg is used as a string key in some map etc).

I think there may be some confusion, about how these types are inferred. It is important to realize, that the type that GenericClass will contain is the runtime type of whatever you pass in. Anything dependent on the exact type, that you might be doing inside (although generally you really shouldn't be) will work just fine.

Overall the type checks done at compile time may seem bit loose to you (especially if you come from C++ for example). There is interesting discussion about some of it in the answers to this question. Java generics - type erasure - when and what happens

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM