在试图解决一个问题时,我用一个类型参数编写了一个方法,这个参数在参数和返回类型中都没有提到,即 <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);
}
2条答案
按热度按时间vshtjzan1#
编译器能够推断类型参数
T
返回类型<T extends A>
基于目标变量。例如,编译器可以理解这一点T
是String
,当你写的时候在您的示例中,类型为
<T extends AuthResponse>
在两边。你应该理解那种类型
T
有两种方法可能不同:第一个方法给出未检查的警告,因为返回值被强制转换为
Call<T>
可以是来电端的任何东西。编译器试图阻止我们从这种情况下,当我们投Call<BadResponse>
至Call<GoodResponse>
.p、 别担心,在你的例子中,石膏很可能是安全的。
最后一件事:因为
T
在authenticate方法中未知,只允许调用类的方法AuthResponse
. 严格地说,extends
关键字在方法中不起很大作用,它只影响对变量的返回值赋值。olqngx592#
当您调用泛型方法而不提供显式类型见证时,“推断”的目的是找出是否至少存在一个可以为其选择的类型
T
这将使调用编译。你可以有多种选择T
那就行了,在这种情况下,它不需要关心选择了哪一个——编译器不需要选择类型参数,因为它没有编译成字节码——它只需要满足至少有一个有效的选择,然后它的工作就完成了。如果类型参数未用于任何参数或返回类型,则根据定义,可以选择
T
不会影响调用是否编译。这意味着编译器可以完全忽略类型参数,因为它与调用的类型检查无关。或者,换一种方式来说,编译器可以任意选择任何类型的边界内的
T
,例如,它可以选择AuthResponse
,或YourSubclassOfAuthResponse
,或MadeUpSubclassOfAuthResponseThatDoesntExistInYourCode
. 没关系。这个选择并不影响调用是否编译。这种谬论指出,泛型方法的类型参数如果没有出现在参数或结果类型中,则完全没有意义,也没有可能的用途。
为什么您的方法需要是泛型的?如果您的泛型方法已编译,则意味着我可以接受它,并替换所有出现的
T
与AuthResponse
(甚至是新定义的UselessSubclassOfAuthResponse
我添加到你的代码中),它也将编译并成为你的方法的一个完全有效的非泛型版本。请考虑一下。如果我这样做了,那么第一行将是Call<UselessSubclassOfAuthResponse> call = getAuthCall(credentials);
. 你的getAuthCall()
方法返回aCall<UselessSubclassOfAuthResponse>
(或Call<WhateverTheCallerWantsWithoutKnowingWhatItIs>
)? 可能不会。如果Call
以及Response
可以任意更改而不影响代码的有效性,那么要么1)它们是未使用的并且不是必需的,要么2)您的代码在某个地方基本上是类型不安全的。