使用 class 实例作为通用类型
Use class instance as generic type
有什么方法可以使用 SomeClass.class
作为类型的通用类型吗?
例如我有一个枚举:
enum MyEnum {
FOO(String.class);
private Class fooClass;
private MyEnum(Class fooClass) {
this.fooClass = fooClass;
}
public Class getFooClass(){
return fooClass;
}
}
然后在我的代码中的某处:
List<MyEnum.FOO.getFooClass()> list = new ArrayList<>();
泛型类型在编译时使用,而不是 运行 时间 - 看看 Java 如何使用泛型擦除。因此,您无法执行此操作。
你可以做的是在遍历列表时对枚举中的 class 使用 cast 方法,这有点冗长,但是即便如此,您也无法进行任何动态泛型赋值。
没有。
泛型在编译时求值,而此调用的值:
MyEnum.FOO.getFooClass()
仅在运行时已知。
这是不可能的,因为显而易见的事实:FOO.getFooClass()
表达式的值被计算 runtime
,而所有泛型都被 compile-time
处理并且在 runtime
中没有任何关于通用类型的信息。
正如其他人所说,你不能。
在这里查看更多信息:
How To Instantiate a java.util.ArrayList with Generic Class Using Reflection
实际上,这个 是 可能有一点 hack,这就是为什么 GSON 能够从 JSON 构造 List<T>
- 它使用TypeToken<T>
class 解析匿名类型令牌实现的 "typed generic superclass"。
基于此,我想 应该 可以从 Class<T>
对象中获取 List<T>
实例92=] 反序列化,然后像 so.
一样构建列表本身
//from
private <T> List<T> getList(Class<T> elementType) {
...
TypeToken<List<T>> token = new TypeToken<List<T>>() {}
.where(new TypeParameter<T>() {}, elementType);
List<T> something = gson.fromJson(data, token); //this would have needed to be replaced
...
}
我试图弄清楚 GSON 是如何获得超级class的。
所以我找到了this:
//from
//from subclass
T instance = ((Class)((ParameterizedType)this.getClass().
getGenericSuperclass()).getActualTypeArguments()[0]).newInstance();
然后我尝试了这个:
public static abstract class MyTypeToken<T> {
public T factory() {
try {
Type type = getClass().getGenericSuperclass();
ParameterizedType paramType = (ParameterizedType) type;
return ((Class<T>) paramType.getActualTypeArguments()[0]).newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
}
和
MyTypeToken<String> typeToken = new MyTypeToken<String>() {
};
System.out.println(typeToken.factory().getClass().getName()); //works and prints java.lang.String
但以下崩溃:
public <T> List<T> getList(Class<T> clazz) {
MyTypeToken<ArrayList<T>> token = new MyTypeToken<ArrayList<T>>() {};
return token.factory();
}
和
Exception in thread "main" java.lang.ClassCastException: sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl cannot be cast to java.lang.Class
所以我很确定 Google 运行,正如他们在 TypeToken and more importantly this Canonicalize method in $Gson$Types 中的魔术代码所示,他们使用内部 Sun [=90= 的重新实现版本]例如ParametrizedTypeImpl
之类的(因为他们有私人访问)。
所以如果你像这样制作 "enum":
public static abstract class MyEnum<T> {
public static final MyEnum<String> FOO = new MyEnum<String>(new MyTypeToken<String>() {}) {};
protected MyTypeToken<T> typeToken;
private MyEnum(MyTypeToken<T> typeToken) {
this.typeToken = typeToken;
}
public MyTypeToken<T> getTypeToken() {
return typeToken;
}
}
public void execute() {
String string = MyEnum.FOO.getTypeToken().factory();
System.out.println(string.getClass().getName());
}
然后你得到java.lang.String
,但是如果你将它与ArrayList<String>
一起使用,你会得到
Exception in thread "main" java.lang.ClassCastException: sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl cannot be cast to java.lang.Class
at com.company.Main$TypeToken.factory(Main.java:19)
at com.company.Main.execute(Main.java:49)
at com.company.Main.main(Main.java:55)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:483)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:134)
所以我猜你 可以 做如果你不想窃取GSON内部代码是这个(使用 GSON 和它自己的 TypeToken):
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import java.util.ArrayList;
import java.util.List;
/**
* Created by EpicPandaForce on 2015.05.06..
*/
public class Main {
public static abstract class MyEnum<T> { //typed `enum`-like structure
public static final MyEnum<String> FOO = new MyEnum<String>(new TypeToken<String>() {}) {};
protected TypeToken<T> typeToken;
private MyEnum(TypeToken<T> typeToken) {
this.typeToken = typeToken;
}
public TypeToken<T> getTypeToken() {
return typeToken;
}
}
public static <T> TypeToken<ArrayList<T>> getListToken(TypeToken<T> typeToken) {
return new TypeToken<ArrayList<T>> () {};
}
public void execute() {
Gson gson = new Gson();
List<String> list = gson.fromJson("[]", getListToken(MyEnum.FOO.getTypeToken()).getType()); //construct empty list using GSON
list.add("hello");
System.out.println(list.get(0)); //writes out hello
}
public static void main(String[] args) {
Main main = new Main();
main.execute();
}
}
而且有效。
最好的是,您还可以将“enum
”的参数替换为 Class<T>
对象,并获得相同的结果。此外,您可以使列表的初始化成为静态方法的一部分。
这是最终代码:
public class Main {
public static abstract class MyEnum<T> {
public static final MyEnum<String> FOO = new MyEnum<String>(String.class) {};
protected Class<T> typeToken;
private MyEnum(Class<T> clazz) {
this.typeToken = clazz;
}
public Class<T> getClazz() {
return typeToken;
}
}
public static class ListFactory {
private static Gson gson;
static {
gson = new Gson();
}
private static <T> TypeToken<ArrayList<T>> getListToken(Class<T> typeToken) {
return new TypeToken<ArrayList<T>> () {};
}
public static <T> List<T> getList(Class<T> clazz) {
return gson.fromJson("[]", getListToken(clazz).getType());
}
}
public void execute() {
List<String> list = ListFactory.getList(MyEnum.FOO.getClazz());
list.add("hello");
System.out.println(list.get(0));
}
public static void main(String[] args) {
Main main = new Main();
main.execute();
}
}
输出为
hello
但是,是的,你不能做类似
的事情
List<MyEnum.FOO.getFooClass()>
你需要知道你得到的对象是一个List<String>
。
有什么方法可以使用 SomeClass.class
作为类型的通用类型吗?
例如我有一个枚举:
enum MyEnum {
FOO(String.class);
private Class fooClass;
private MyEnum(Class fooClass) {
this.fooClass = fooClass;
}
public Class getFooClass(){
return fooClass;
}
}
然后在我的代码中的某处:
List<MyEnum.FOO.getFooClass()> list = new ArrayList<>();
泛型类型在编译时使用,而不是 运行 时间 - 看看 Java 如何使用泛型擦除。因此,您无法执行此操作。
你可以做的是在遍历列表时对枚举中的 class 使用 cast 方法,这有点冗长,但是即便如此,您也无法进行任何动态泛型赋值。
没有。 泛型在编译时求值,而此调用的值:
MyEnum.FOO.getFooClass()
仅在运行时已知。
这是不可能的,因为显而易见的事实:FOO.getFooClass()
表达式的值被计算 runtime
,而所有泛型都被 compile-time
处理并且在 runtime
中没有任何关于通用类型的信息。
正如其他人所说,你不能。 在这里查看更多信息: How To Instantiate a java.util.ArrayList with Generic Class Using Reflection
实际上,这个 是 可能有一点 hack,这就是为什么 GSON 能够从 JSON 构造 List<T>
- 它使用TypeToken<T>
class 解析匿名类型令牌实现的 "typed generic superclass"。
基于此,我想 应该 可以从 Class<T>
对象中获取 List<T>
实例92=] 反序列化,然后像 so.
//from
private <T> List<T> getList(Class<T> elementType) {
...
TypeToken<List<T>> token = new TypeToken<List<T>>() {}
.where(new TypeParameter<T>() {}, elementType);
List<T> something = gson.fromJson(data, token); //this would have needed to be replaced
...
}
我试图弄清楚 GSON 是如何获得超级class的。
所以我找到了this:
//from
//from subclass
T instance = ((Class)((ParameterizedType)this.getClass().
getGenericSuperclass()).getActualTypeArguments()[0]).newInstance();
然后我尝试了这个:
public static abstract class MyTypeToken<T> {
public T factory() {
try {
Type type = getClass().getGenericSuperclass();
ParameterizedType paramType = (ParameterizedType) type;
return ((Class<T>) paramType.getActualTypeArguments()[0]).newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
}
和
MyTypeToken<String> typeToken = new MyTypeToken<String>() {
};
System.out.println(typeToken.factory().getClass().getName()); //works and prints java.lang.String
但以下崩溃:
public <T> List<T> getList(Class<T> clazz) {
MyTypeToken<ArrayList<T>> token = new MyTypeToken<ArrayList<T>>() {};
return token.factory();
}
和
Exception in thread "main" java.lang.ClassCastException: sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl cannot be cast to java.lang.Class
所以我很确定 Google 运行,正如他们在 TypeToken and more importantly this Canonicalize method in $Gson$Types 中的魔术代码所示,他们使用内部 Sun [=90= 的重新实现版本]例如ParametrizedTypeImpl
之类的(因为他们有私人访问)。
所以如果你像这样制作 "enum":
public static abstract class MyEnum<T> {
public static final MyEnum<String> FOO = new MyEnum<String>(new MyTypeToken<String>() {}) {};
protected MyTypeToken<T> typeToken;
private MyEnum(MyTypeToken<T> typeToken) {
this.typeToken = typeToken;
}
public MyTypeToken<T> getTypeToken() {
return typeToken;
}
}
public void execute() {
String string = MyEnum.FOO.getTypeToken().factory();
System.out.println(string.getClass().getName());
}
然后你得到java.lang.String
,但是如果你将它与ArrayList<String>
一起使用,你会得到
Exception in thread "main" java.lang.ClassCastException: sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl cannot be cast to java.lang.Class
at com.company.Main$TypeToken.factory(Main.java:19)
at com.company.Main.execute(Main.java:49)
at com.company.Main.main(Main.java:55)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:483)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:134)
所以我猜你 可以 做如果你不想窃取GSON内部代码是这个(使用 GSON 和它自己的 TypeToken):
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import java.util.ArrayList;
import java.util.List;
/**
* Created by EpicPandaForce on 2015.05.06..
*/
public class Main {
public static abstract class MyEnum<T> { //typed `enum`-like structure
public static final MyEnum<String> FOO = new MyEnum<String>(new TypeToken<String>() {}) {};
protected TypeToken<T> typeToken;
private MyEnum(TypeToken<T> typeToken) {
this.typeToken = typeToken;
}
public TypeToken<T> getTypeToken() {
return typeToken;
}
}
public static <T> TypeToken<ArrayList<T>> getListToken(TypeToken<T> typeToken) {
return new TypeToken<ArrayList<T>> () {};
}
public void execute() {
Gson gson = new Gson();
List<String> list = gson.fromJson("[]", getListToken(MyEnum.FOO.getTypeToken()).getType()); //construct empty list using GSON
list.add("hello");
System.out.println(list.get(0)); //writes out hello
}
public static void main(String[] args) {
Main main = new Main();
main.execute();
}
}
而且有效。
最好的是,您还可以将“enum
”的参数替换为 Class<T>
对象,并获得相同的结果。此外,您可以使列表的初始化成为静态方法的一部分。
这是最终代码:
public class Main {
public static abstract class MyEnum<T> {
public static final MyEnum<String> FOO = new MyEnum<String>(String.class) {};
protected Class<T> typeToken;
private MyEnum(Class<T> clazz) {
this.typeToken = clazz;
}
public Class<T> getClazz() {
return typeToken;
}
}
public static class ListFactory {
private static Gson gson;
static {
gson = new Gson();
}
private static <T> TypeToken<ArrayList<T>> getListToken(Class<T> typeToken) {
return new TypeToken<ArrayList<T>> () {};
}
public static <T> List<T> getList(Class<T> clazz) {
return gson.fromJson("[]", getListToken(clazz).getType());
}
}
public void execute() {
List<String> list = ListFactory.getList(MyEnum.FOO.getClazz());
list.add("hello");
System.out.println(list.get(0));
}
public static void main(String[] args) {
Main main = new Main();
main.execute();
}
}
输出为
hello
但是,是的,你不能做类似
的事情List<MyEnum.FOO.getFooClass()>
你需要知道你得到的对象是一个List<String>
。