public class PageResult<T> {
private int total;
private List<T> data;
public static <T> PageResult<T> of(Page<T> page) {
return new PageResult<>(page.getSize(), page.getContent());
}
}
1
zongren 2021-11-09 10:24:55 +08:00
好像获取不到吧,只能把 class 传进来
|
2
chendy 2021-11-09 10:35:42 +08:00
看你的需求
如果只是想看看 List 里面是啥,取第一个元素看一眼类型就行了(对空 List 无效) |
3
v2lf 2021-11-09 10:37:02 +08:00
通过继承, 设置一个抽象的超类 ,实现这个需求
|
4
wolfie 2021-11-09 10:37:03 +08:00
泛型是编译期,反射是运行时。
|
5
orangie 2021-11-09 10:40:59 +08:00
话说,为什么当初添加泛型功能的时候,没有给添加一个字段用于保存编译时能确定的这个泛型类型呢?比如给加一个 getGenericClass()方法,编译器实现内部代码让他返回 T 的真实类型。虽然这么做好像不能用于协变和逆变,不过再加一个方法用来返回协变、逆变、准确泛型?
|
6
kiotech 2021-11-09 10:45:22 +08:00
泛型 T 可以为 interface ,即 PageResult<PageInterface>,这样就可以拿到 page.getSize(), page.getContent()
|
7
youkiiiiiiiiiiiI 2021-11-09 10:47:24 +08:00
GG
|
8
leeg810312 2021-11-09 10:47:38 +08:00 via Android
@orangie JAVA 历史遗留问题,很难改了,你说的特性只有运行时真泛型才能做到,反射是运行时,编译时泛型是做不到的
|
9
clf 2021-11-09 11:25:04 +08:00 1
SpringBoot 下泛型接口:
public interface IService<T> { ... default Class<T> getClazz() { return (Class<T>) GenericTypeResolver.resolveTypeArgument(getClass(), IService.class); } ... } |
10
clf 2021-11-09 11:26:10 +08:00
@clf #9 能拿到的是 public class XXXService extends IService<XXX> {} 的 XXX.class
|
11
ZoteTheMighty 2021-11-09 11:30:30 +08:00
T 里面的类继承一个抽象类,抽象类里放一个抽象方法 getClassInfo , 然后子类实现该接口。
|
12
guyuesh2 2021-11-09 11:30:53 +08:00 2
Class#getDeclaredField
Field#getGenericType ParameterizedType 和 Type 的一些子类了解一下,泛型反射是 Gson FastJson 的基础吧 ! |
13
0xZhangKe 2021-11-09 13:09:33 +08:00
可以看看 Gson 是怎么做的,就是上面说的继承会保存范型类型。
|
14
passerbytiny 2021-11-09 13:17:41 +08:00 via Android
首先给答案,不能。原因:Java 泛型仅在编译时有效,编译之后任何泛型信息都被擦除了。
|
15
passerbytiny 2021-11-09 13:24:46 +08:00 via Android
当然有折衷的方法。继承关系中会残留一些泛型信息到运行时,可以用来变相获取 T 。你不能在运行时获取 List<T>中 T 的实际类型,但是可以获取 List<T extend SomeAbstractClass/Interface>中 T 的实际类型。
|
16
passerbytiny 2021-11-09 13:28:59 +08:00 via Android
上面说错了一点,是可以获取 List<T extend SomeAbstractClass/Interface<T>>中 T 的实际类型。
|
17
INCerry 2021-11-09 13:40:20 +08:00 2
如果是 C#的话 直接即可
public Type GetListType<T>(List<T> list) { return list.GetType().GetGenericArguments()[0]; } |
18
thetbw 2021-11-09 13:54:28 +08:00
无解,我用的就是楼上的方法,当用 aop 对参数处理的时候,遇到 list 就把 list 中的数据取出来判断类型,如果没数据,跳过
|
19
geligaoli 2021-11-09 14:02:59 +08:00
可以有变通的方式,
1. 在 PageResult<T> 的子类中获取。2. 直接 new 对象时传递 T 的类型。 public class PageResult<T> { private Class<T> entityClass; /** * 子类中获取 entityClass */ public PageResult() { this.entityClass = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0]; } /** * new 对象的时候传递 * * @param entityClass */ public PageResult(Class<T> entityClass) { this.entityClass = entityClass; } |
20
Edsie 2021-11-09 17:03:50 +08:00
3 楼正解
|
21
xingda920813 2021-11-09 17:17:34 +08:00
对 3 楼思路的一个具体实现, 支持嵌套泛型. https://gist.github.com/xingda920813/6d01c009242b168796aa318d287a7f58
|
22
wjploop 2021-11-09 20:46:28 +08:00
@guyuesh2 感谢,又涨知识了,附上一篇查到的博文。https://www.cxyzjd.com/article/sai_simon/98663284
另外,我能不能这么理解?泛型擦除只是为了兼容以前无泛型的代码,运行时不去检验类型,而泛型信息还是保留着。 |
23
humpy 2021-11-09 21:11:08 +08:00
我之前尝试过
/** * 获取集合的元素类型 * * @param type 集合类型 * @param genericType 集合的泛型类型信息 */ public static Type resolveCollectionElementType(Class<?> type, Type genericType) { if (genericType instanceof ParameterizedType) { ParameterizedType pt = (ParameterizedType)genericType; return pt.getActualTypeArguments()[0]; } else { return type; } } |
24
learningman 2021-11-09 21:34:59 +08:00
@wjploop #22 擦除了就是没了,楼上那些实现方法是自己加了个成员标记类型
|
25
john6lq 2021-11-09 21:38:21 +08:00 via iPhone
三楼方法是可以,安卓封装 viewbinding 了解到的。
|
26
sagaxu 2021-11-09 21:40:54 +08:00
最好不要拿,拿了就跟调用方耦合了
|
27
v2lf 2021-11-09 23:10:29 +08:00
补充下, 基本原理实现, 使用的话,最好按照需求,封装层级继承,并且需要添加其他逻辑,处理边界情况
```java static class Person extends TypeWrap<String> { } static abstract class TypeWrap<T>{ private final Type type; protected TypeWrap(){ Type genericSuperclass = getClass().getGenericSuperclass(); Type raw = ((ParameterizedType)genericSuperclass).getActualTypeArguments()[0]; //todo 需要处理范型作为类型参数 type = raw; } public Type getType() { return type; } } ``` |
28
v2lf 2021-11-09 23:12:16 +08:00
@wjploop 我理解哈,raw class 是没有类型信息的,ParameterizedType 的类型信息实现,是通过读取文本解析出来的, 可以看下源码哈,jdk 中的
|
29
xarthur 2021-11-10 00:11:04 +08:00 via iPhone
这个就是类型擦除啊……
|
30
wjploop 2021-11-10 10:33:34 +08:00 1
@v2lf 你提到的文本应该指的是编译后的字节码,而非*.java 源文件吧,不太明白提到的
“raw class 是没有类型信息的,ParameterizedType 的类型信息实现”。 既然在字节码中保留着参数类型的信息,自然就有办法提取出来,提取方法涉及到了 ParameterizedType 。 验证字节码中仍保留着参数类型可以使用 javap 查看,具体参考 https://wiyi.org/type-erasure.html 。 另外,若是泛型信息在字节码不存在了,那么 Gson 没法正确转换 json 数据包,这也是如 12 楼提到的。 |
31
scruel 2021-11-10 13:58:05 +08:00
v2ex 现在是国内的 stackoverflow 了吗?
|
33
guyuesh2 2021-11-10 16:59:33 +08:00 1
@wjploop 可以去看一下 <<JAVA 虚拟机规范>> 这本书,泛型信息在 Class 文件中是通过签名(Class 文件的常量池中泛型类型标记的字符串)保留的. 泛型擦除我认为是运行时存储这个泛型变量的机制(即全部通过 Object 进行存储,而不是通过泛型的具体类型进行存储,如果通过 具体类型存储,那么 ArrayList 这个类会存在多少类型? ArrayList#get 之后好像会根据泛型类型,插入强制类型转换的代码,用于转换成为用户指定的 ArrayList 类型)
额外扩展一下,泛型类型之间也存在父子关系,可以了解一下 PECS 法则和 协变逆变 最重要的是,我很久没看这一块,这些只是我很早以前看得一个大概记忆和理解,可能有错误的地方,请批评指正 |
34
dbpe 2021-11-10 17:19:48 +08:00
我在想一个问题...如果 aot 和类似 native image 的推广..那些反射有什么办法解决呢?
|
35
Aresxue 2021-11-17 13:30:35 +08:00
泛型擦除会擦除到类的上界,普通的对象的上界就是 Object ,一般是拿不到的,如果 method 里有声明可以依赖 ParameterizedType 去获取,不然就取里面的对象的类型,如果还是空的那 jvm 就感知不到了,需要你手动设一个上界或者传进去
|