java - 获取泛型类的属性值
问题描述
我正在使用 Java v1.8,并且我有以下代码:
public <T> ApiResponse<T> execute(Call call, Type returnType) throws ApiException {
try {
Response response = call.execute();
T data = handleResponse(response, returnType);
ApiResponse<T> apiResponse = new ApiResponse<T>(response.code(), response.headers().toMultimap(), data);
return apiResponse;
} catch (IOException e) {
throw new ApiException(e);
}
}
所以这会进行 API 调用并根据Type returnType
. 我知道每个 API 调用都会响应 body 中的参数requestId
。
由于我不知道的类型returnType
,有什么办法可以得到财产requestId
。它应该在data
...
解决方案
您已经定义了一个类型变量T
。这个类型变量没有任何界限;您将其声明为<T>
,这意味着 T 可以是任何东西。甚至对象。特别Object
是,任何 T 可能必须是其子类型的通用类型,并且 Object没有 requestId。因此,您不能调用.getRequestId()
or.requestId
或任何您对requestId
. 解决方案是绑定T:告诉 java T 不能只是“任何东西”,它只能是具有某些属性的类型。具体来说,告诉它它只能是任何抽象类或接口,它是所有 Api 响应返回类型的超类型,.getRequestId()
里面有一个方法:public <T extends ThatSharedSuperType> ....
是你想要的。
这里还有第二个问题——你的泛型刚刚坏了。这段代码没有意义。
泛型是编译器想象的虚构:编译器使用它来将事物联系在一起。这不是“幸存”编译的东西- T 之后就消失了。编译器在编译期间使用它进行一些额外的错误检查和便利,然后它就消失了。因此,您编写的任何泛型都必须为编译过程添加一些有用的东西,否则它会被误导和/或只会让事情变得混乱。
换句话说,任何类型变量都必须至少在两个地方使用——它们的重点是链接事物。例如,在这个方法中:
public <T> T identity(T in) { return in; }
我们T
在两个地方使用了:这个方法将第一个(也是唯一的)参数的类型链接到返回类型,并且说不管这个方法被调用,它在两个地方都是相同的类型。这很有用。在您的代码中, T 仅在一个地方使用:ApiResponse<T>
. 这使它完全无用。
无论您认为它<T>
在做什么(可能)都不是它在做什么。因为它在这里有效地做的是手动放弃类型系统,而你真的不想这样做。
大概Type returnType
是链接到返回的ApiResponse
对象。您的代码不是特别清楚,所以这是一个有根据的猜测,但是,大概Type returnType
是 eg String.class
,这应该会导致返回一个ApiResponse<String>
对象。
这不是这段代码的作用。此代码将适应仅在编译时禁用类型检查。你可以写:
ApiResponse<Integer> thisMakesNoSense = execute(someCall, String.class);
即使您确实想要这样,您也不会从编译器错误中受益。
你不应该Type
在这里使用。除非您正在编写注释处理器或反射库(而且您通常都不想要),否则您几乎不应该使用它。
您在这里有两个选择:
ApiResponse 类型始终是一个简单的类。即它是一个
TwitterMentions
类或aNewTweetResponse
或诸如此类,而不是例如aList<Tweet>
或anint
。在这种情况下,您可以只使用Class<T>
而不是 Type:public <T extends TwitterType> ApiResponse<T> execute(Call call, Class<T> twitterType) {}
。这将 [A] 保证您只能execute
使用作为 TwitterType 的某个子类型的 T 调用,并且 [B] 正确地将事物联系在一起:传递 egTwitterMentions.class
执行意味着它返回 aApiResponse<TwitterMentions>
,而不是可以是 schroedingers cat 响应分配给你想要的任何东西,即使它没有意义。或者,如果 ApiResponse 可以是 a
List<Tweet>
,它应该是一个超级类型令牌(您可以在网上搜索“java 超级类型令牌”,它需要一些解释并且存在许多不错的教程),这样您就可以绑定泛型一起并运行时检索可能需要的类型handleResponse
。
对于更简单Class<T>
的情况:
public interface TwitterType {
public String getRequestId();
}
public class TwitterMentions implements TwitterType {
@Override public String getRequestId() {
..
}
public List<TwitterMention> getMentions() {
..
}
}
public <T extends TwitterType> ApiResponse<T> execute(Call call, Class<?> returnType) throws ApiException { ... }
推荐阅读
- c# - 如何在 RoslynPad 中显示 OpenFileDialog
- flutter - GDPR 和个人数据
- mongodb - Mongo $lookup,哪种方式最快?
- python - 如何在特定位置将句子插入字符串?
- snmp - 打印机 OKI 陷阱含义 (OID)
- android - 构建期间找不到 Github 包
- postgresql - 如何在一行中将所有权限授予在 PostgreSQL 上创建的用户
- python - Numpy 将数组拆分为大小相等且余数相等的块
- javascript - 从 gatsby-source-wordpress-experimental 中排除标签
- node.js - 如何防止节点 js express 中不需要的请求?