我有以下java示例类:
adb shell dumpsys meminfo | awk -F'[: ]' '/mobile_cep/ { print $1 }'
正在生成编译器警告:
类型安全:未捕获来自捕获#1的投射?将Object扩展为T
如果我这样做,我可以完美地获得确切的T对象:
public class TestClass {
public static <T> void method(List<T> objects) throws Exception {
for (int i = 0; i < objects.size(); i++) {
// Create new object of the same class
T obj = (T) objects.get(i).getClass().newInstance();
}
}
}
它完全知道的是T型。
为什么我无法创建该类的新实例?我怎么能解决它?
(我不是在寻找类型的回复:'添加@SuppressWarnings(“未选中”)')
答案 0 :(得分:11)
这是因为getClass()
返回Class<? extends Object>
。你不能(安全地)将通配符?
强制转换为任何东西,甚至不是通用的类类型。这是Java Generics的限制。但是,既然您可以确定此警告不是问题,您可以放心地忽略或禁止它。
但这是一种解决方法,许多应用程序和库都这样做:
public static <T> void method(List<T> objects, Class<T> clazz) throws Exception {
for (int i = 0; i < objects.size(); i++) {
// Create new object of the same class
T obj = clazz.newInstance();
}
}
答案 1 :(得分:4)
泛型在运行时被删除。因此,在列表的已声明getClass()
元素上调用T
将返回<? extends Object>
类实例。
Object.getClass()
个州:
实际结果类型为
Class<? extends |X|>
,其中|X|
为 擦除getClass所在表达式的静态类型 调用。
要调用newInstance()
并创建T
实例,您需要知道要实例化的Class
实例,但请注意List
可以包含任何子类T
,因此将类作为参数传递可能还不够。
例如:
List<Animal> list = new ArrayList<>();
list.add(new Lion());
list.add(new Rabbit());
list.add(new Turtle());
现在调用了哪一个?
method(list, Lion.class);
method(list, Rabbit.class);
method(list, Turtle.class);
任何人都无法编译!所以这显然是不够的 因此,我认为通过抑制警告来保留原始代码更有意义。通过这种方式,您可以确保创建与列表中的实际元素相同的类的实例:
public static <T> void method(List<T> objects) throws Exception {
for (int i = 0; i < objects.size(); i++) {
// Create new object of the same class
@SuppressWarnings("unchecked")
T obj = (T) objects.get(i).getClass().newInstance();
System.out.println(obj);
}
}
答案 2 :(得分:1)
为什么我无法创建该类的新实例?
你是。您的代码将编译并且它将按预期工作,但编译器并不是100%确定,因为类型擦除这就是您收到警告的原因。这里要注意的重要一点是警告与错误不同。
(我不是在寻找类型的回复:&#39;添加@SuppressWarnings(&#34;未经检查&#34;)&#39;)
如果你查看任何使用泛型和反射相互结合的Java代码库,你会看到类型安全的被抑制警告。不幸的是,这只是生活中的一个事实。