java如何解析不在方法声明中的泛型类型参数?

xfb7svmp  于 2021-07-13  发布在  Java
关注(0)|答案(2)|浏览(303)

在试图解决一个问题时,我用一个类型参数编写了一个方法,这个参数在参数和返回类型中都没有提到,即 <T> void authenticate(Credentials credentials) 方法。唯一依赖于 T 在方法体中(前面有详细信息)。所以我的问题是:这个泛型类型是如何解决的?我找不到任何其他具有这种泛型类型参数的示例代码。
所以这个方法的主体是

public <T extends AuthResponse> void authenticate(Credentials credentials) {
    Call<T> call = getAuthCall(credentials);
    Response<T> response = call.execute();

    // doSomething is an AuthResponse method
    response.body().doSomething();
}

它调用一个只有泛型返回类型的方法,如下所示:

private Call<T extends AuthResponse> getAuthCall(Credentials credentials) {
    if (credentials instanceof CredentialsA)
        return (Call<T>) service.authenticate((CredentialsA) credentials);
    else if (credentials instanceof CredentialsB)
        return (Call<T>) service.authenticate((CredentialsB) credentials);
    else
        throw new IllegalArgumentException();
}

所以这两种方法的类型参数似乎是相关的。但我不明白怎么回事。还有 (Call<T>) cast似乎不是解决我问题的好办法- service 是这样的改装界面:

public interface AuthServiceInterface {
    @POST("auth/a") Call<AuthResponseA> authenticate(CredentialsA credentials);
    @POST("auth/b") Call<AuthResponseB> authenticate(CredentialsB credentials);
}
vshtjzan

vshtjzan1#

编译器能够推断类型参数 T 返回类型 <T extends A> 基于目标变量。例如,编译器可以理解这一点 TString ,当你写的时候

List<String> empty = Collections.emptyList();

在您的示例中,类型为 <T extends AuthResponse> 在两边。
你应该理解那种类型 T 有两种方法可能不同:

private Call<T extends AuthResponse> getAuthCall(Credentials credentials) {
    return (Call<T>) new BadAuthCall<BadResponse>(); // unchecked warning
}

public <T extends AuthResponse> void authenticate(Credentials credentials) {
    Call<T> call = getAuthCall(credentials);
    ...

// then somewhere in your code
Call<GoodResponse> response = service.authenticate(credentials);
// this code compiles, but will throw ClassCastException in runrime

第一个方法给出未检查的警告,因为返回值被强制转换为 Call<T> 可以是来电端的任何东西。编译器试图阻止我们从这种情况下,当我们投 Call<BadResponse>Call<GoodResponse> .
p、 别担心,在你的例子中,石膏很可能是安全的。
最后一件事:因为 T 在authenticate方法中未知,只允许调用类的方法 AuthResponse . 严格地说, extends 关键字在方法中不起很大作用,它只影响对变量的返回值赋值。

olqngx59

olqngx592#

当您调用泛型方法而不提供显式类型见证时,“推断”的目的是找出是否至少存在一个可以为其选择的类型 T 这将使调用编译。你可以有多种选择 T 那就行了,在这种情况下,它不需要关心选择了哪一个——编译器不需要选择类型参数,因为它没有编译成字节码——它只需要满足至少有一个有效的选择,然后它的工作就完成了。
如果类型参数未用于任何参数或返回类型,则根据定义,可以选择 T 不会影响调用是否编译。这意味着编译器可以完全忽略类型参数,因为它与调用的类型检查无关。
或者,换一种方式来说,编译器可以任意选择任何类型的边界内的 T ,例如,它可以选择 AuthResponse ,或 YourSubclassOfAuthResponse ,或 MadeUpSubclassOfAuthResponseThatDoesntExistInYourCode . 没关系。这个选择并不影响调用是否编译。
这种谬论指出,泛型方法的类型参数如果没有出现在参数或结果类型中,则完全没有意义,也没有可能的用途。
为什么您的方法需要是泛型的?如果您的泛型方法已编译,则意味着我可以接受它,并替换所有出现的 TAuthResponse (甚至是新定义的 UselessSubclassOfAuthResponse 我添加到你的代码中),它也将编译并成为你的方法的一个完全有效的非泛型版本。请考虑一下。如果我这样做了,那么第一行将是 Call<UselessSubclassOfAuthResponse> call = getAuthCall(credentials); . 你的 getAuthCall() 方法返回a Call<UselessSubclassOfAuthResponse> (或 Call<WhateverTheCallerWantsWithoutKnowingWhatItIs> )? 可能不会。如果 Call 以及 Response 可以任意更改而不影响代码的有效性,那么要么1)它们是未使用的并且不是必需的,要么2)您的代码在某个地方基本上是类型不安全的。

相关问题