我使用GSON解析Java中的json。当我想从json String获取整数列表时,我的代码可能如下所示:
Type type = new TypeToken<List<Integer>>(){}.getType();
List<Integer> result = null;
try {
result = new Gson().fromJson(jsonStringGoesHere, type);
} catch (JsonSyntaxException e) {
e.printStackTrace();
}
如果jsonStringGoesHere
为空字符串或为null,则result
也为空。
虽然集合等于null被认为是不好的做法,所以我希望在这种情况下有一个空的List而不是null。
所以基本上这就是我现在要做的:如果result
为空,我想检查type
是List
(或List
的子类型)。如果为true,我将使结果为空ArrayList。如何检查type
是否包含List
或List
的子类型?
我的尝试是检查if(type instanceof Collection)
- 但返回false。
我的下一个尝试是取type.getTypeName()
返回字符串java.util.List<java.lang.Integer>
,并尝试从中创建一个对象:
Class c = Class.forName(type.getTypeName());
Object o = c.newInstance();
if(o instanceof List){
System.out.println("it's working!");
}
但这会引发java.lang.ClassNotFoundException: java.util.List<java.lang.Integer>
。
任何想法如何使这项工作?
答案 0 :(得分:1)
我的尝试是检查
if(type instanceof Collection)
- 但返回false
。
这不会起作用,因为Type
和Collection
不是&#34;可以相互转换&#34;并存在于不同的层次结构中。
我的下一次尝试是取
type.getTypeName()
,返回字符串java.util.List<java.lang.Integer>
这也不会奏效。 Class.forName
以完全限定的名称返回现有的Class<?>
实例(简单来说,就是.class
中CLASSPATH
文件所代表的内容,但从不 - 参数化类(类不可参数化,但可以是带参数化超类的子类 - 这就是类型标记之下的内容)。因此,Class.forName("java.util.List")
是有道理的,但Class.forName("java.util.List<String>")
没有。
请注意,Type
可以代表某种类型,而TypeToken<T>
可以达到此目的。只要看看它是如何宣布的 - 你就会更好地理解它。更重要的是,它的子接口ParameterizedType
可以保存类型参数,这可以通过TypeToken
生成或手动构建(像往常一样 - 只需看一下接口声明)。 TypeToken
通常使用匿名基类参数化来获取类型参数,以及它们的设计原理:完善的编译时支持+ Google Guava中的类似技术,杰克逊, Spring Framework(但如果Java可以支持类似java.util.List<Integer>.type
的东西来获取参数化类型实例,那将会很好)。从后来的Gson版本开始,您甚至可以使用TypeToken.getParameterized(...)
来创建参数化类型。
你正在寻找的是一个&#34; class-instanceof&#34;或&#34; a-subclass-of&#34; (如果可以这样称呼它):Class.isAssignableFrom(...)
。此实例方法检查一个类是否相同或另一个类的子类。说,
SuperClass.class.isAssignableFrom(SubClass.class)
始终返回true
。所以你只需要这样检查:
final Type type = new TypeToken<List<Integer>>() {
}.getType();
final TypeToken<?> typeToken = TypeToken.get(type);
System.out.println(List.class.isAssignableFrom(typeToken.getRawType()));
甚至更短:
final TypeToken<List<Integer>> typeToken = new TypeToken<List<Integer>>() {
};
System.out.println(List.class.isAssignableFrom(typeToken.getRawType()));
两者都返回true
。请注意,类型标记通过Class<?>
返回getRawType()
个实例,但不返回getType()
,因为后者可能不代表类(例如Collection<String>.class.isAssignableFrom(List<Integer.class>)
会返回什么类型?)
此外,您可以将类型标记及其类型提取到static final
字段,因为它们是不可变的值,不应在运行时更改。
答案 1 :(得分:0)
在Java中,通用部分的集合在编译时发挥作用,因此它在运行时不可用,这就是您获得该异常的原因。因此,如果您想使用反射创建集合类,那么您必须删除通用部分。
列表,设置和地图是他们无法直接实例化的界面。因此,为了创建对象,您必须使用其中一个实现,例如 ArrayList , LinkedList 等。