未经检查的演员:“ zzz.szi.m.Something1”为“ T”
运行“ mvn软件包”时收到警告
private <T> T get() throws Exception {
T m;
if (/*some condition*/) {
m = (T)new Something1()
}
elseif (/*some condition*/) {
m = (T)new Something2()
}
else {
m = (T)new Something3()
}
return m;
}
我的班级:
public class Something1 implements Something {
// ...
}
public class Something2 implements SomethingElse {
// ...
}
public class Something3 implements Something, SomethingElse, SomethingMore {
// ...
}
//向(T)添加了强制转换,但结果相同
我不要警告
答案 0 :(得分:1)
当您使方法通用时,这意味着调用方可以控制type参数。调用方始终可以提供满足任何限制的任何内容,并且您没有限制。调用方可以提供Integer
,Object
或Foo
,并且此方法需要返回该类型的实例。
但是,根据编译器,这与方法逻辑中的条件无关。不能保证您返回的内容与type参数完全匹配,这正是编译器要说的。
您的方法在这里不能通用。如果所有SomethingX
类都从基类或接口继承,则让您的方法返回该类型,否则它必须为Object
。如果您需要调用所有SomethingX
类都具有的特定方法,请提取一个新接口并让您的方法返回该类型。
如果没有任何公共接口,但是必须在返回的对象上调用特定的方法,则将该方法之外的条件逻辑带入调用代码,或者在返回对象之前对该对象进行调用。 / p>
private Object get() throws Exception {
Object m;
if (/*some condition*/) {
Something1 s1 = new Something1();
s1.s1Method();
m = s1;
}
else if (/*some condition*/) {
Something2 s2 = new Something2();
s2.s2Method();
m = s2;
}
else {
Something3 s3 = new Something3();
s3.s3Method();
m = s3;
}
return m;
}
答案 1 :(得分:0)
T
由编译器通过查看该方法的调用上下文来解决。如果将调用的结果分配给类型为XXX
的变量,则在编译过程中将T
替换为XXX
,以检查其余代码的逻辑。
问题代码打破了这种约定,因为方法代码似乎控制着返回的类型,因此通常无法根据实例化类来做出正确的选择。这就是为什么这种投射不安全的原因。
解决此问题的一种方法是将控件返回到调用代码。例如,get()
方法可以接受一个类对象,该对象指示要返回的类型,并使用Class.newInstance
创建该对象,因为它不得不处理相应的检查异常以及所请求类的可能性没有缺少参数的构造函数:
private <T> T get(Class<? extends T> class) {
try {
return class.newInstance();
} catch (Exception ex) {
// handle the exception apropiately
}
}
呼叫代码:
Something some;
if (/* condition 1 */) {
some = get(Something1.class);
} else if (/* condition 2 */) {
some = get(Something2.class);
} ...
问题仍然存在,您是否需要在对象实例化之前或之后将子类不可知的通用代码添加到get
的主体中,以使该方法值得使用,否则您最好在每个if中调用适当的子类构造函数-else(即new Something1()
,new Something2()
等)。