简体   繁体   中英

Class<T> for a generic in Java?

I've just moved over to using Java generics, so I'm not sure if I'm even asking the right question.

I am trying to make use of the following method:

public <T> ResponseEntity<T> exchange(String url,
                                  HttpMethod method,
                                  HttpEntity<?> requestEntity,
                                  Class<T> responseType,
                                  Object... uriVariables)
                           throws RestClientException

For type <T> I have provided Response<MyDTO> , so my method call looks like:

ResponseEntity<Response<MyDTO>> re = exchange(...)

I cannot work out how to provide the correct value to the Class<T> responseType parameter?

I do know that generics in java undergo type erasure so you shouldn't be able to determine types at runtime via reflection, but I know the exact type I want to provide.

I have seen many variations of How to get a class instance of generics type T that talk about passing the class type as a constructor parameter.

But I cannot work out how to make an instance of Class<Response<MyDTO>> .

Is there a way to do this? Or is there a restriction in generics that prohibits this?

The class of Response<whatever> is Response.class . However, to tell the compiler you want it to be the class of Response<MyDTO> specifically you have to cast it: (Class<Response<MyDTO>>) (Object) Response.class . If the cast strikes you as suspicious... well, it's a suspicious thing to want to do.

This will work as expected is if the argument is used to create a new instance of Response and does not need to create a new instance of MyDTO (eg the user is supposed to set it after calling exchange ). But I can't think of any other case.

Or is there a restriction in generics that prohibits this?

Yes. Due to type erasure, all instances of a generic type share the same runtime class, ie

new Response<FooDto>().getClass() == new Response<BarDto>().getClass()

Because the same class object is used for both type parameters, its type can not constrain that parameter, ie

new Response<FooDto>().getClass() 

is of type

Class<? extends Response>

Likewise, Response<FooDto>.class does not compile, because there is no class object for that particular type, only a class object shared among all Response instances.

Theoretically, you could lie to the compiler about the type of the class object:

Class c = Response.class
Class<Response<FooDto>> clazz = (Class<Response<FooDto>>) c

which would compile, but is very unlikely to do what you want at runtime, because the called method would be unable to determine the type parameter of Response .

This leaves us with two possibilites: Either the API designer screwed up and made this API unusable for your use case, or you are using the API wrong. Look for an overload of that method that accepts the value of the type parameter in a different way, and verify that you really need generics here.

For some reason, the usual approach of taking an instance of Response<MyDTO> and using getClass() does not compile:

Response<MyDTO> response = new Response<MyDTO>(...);
Class<Response<MyDTO>> clazz = response.getClass(); 

As mentioned by @meriton it leads to cannot convert from Class<capture#1-of ? extends Response> to Class<Response<MyDTO>> cannot convert from Class<capture#1-of ? extends Response> to Class<Response<MyDTO>> .

PS: It is really unusual to expect Class as a parameter, I wonder what they need it for.

PPS: I tested it and both @AlexeyRomanov's and my solution don't seem to produce the "generified" class:

import java.util.ArrayList;

class Main
{
    public static void main (String [] args)
    {
        System.out.println((Class<ArrayList<String>>)(Object)(ArrayList.class));
        System.out.println((new ArrayList<String>()).getClass()); 
    }
}

Output

class java.util.ArrayList
class java.util.ArrayList

It seems like both times the generic type gets lost. In case this is not just a problem with Class.toString, you could get the same result by just using Response.class .

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