Java 重新设计未经检查的强制转换警告
我有一个类将包含几个不同对象的不同解析器实现。虽然我能够在没有任何警告的情况下存储解析器实现,但从映射中获取解析器会警告未经检查的强制转换异常。以下是一个简化的摘录:Java 重新设计未经检查的强制转换警告,java,generics,Java,Generics,我有一个类将包含几个不同对象的不同解析器实现。虽然我能够在没有任何警告的情况下存储解析器实现,但从映射中获取解析器会警告未经检查的强制转换异常。以下是一个简化的摘录: private Map<Class<?>, Parser<?>> parsers = new HashMap<>(); public <T> void addParser(Class<T> type, Parser<T> parser) {
private Map<Class<?>, Parser<?>> parsers = new HashMap<>();
public <T> void addParser(Class<T> type, Parser<T> parser) {
parsers.put(type, parser);
}
private <T> Parser<T> parserFor(Class<T> type) {
// Compiler complains about unchecked cast below
return (Parser<T>) parsers.get(type);
}
private Map>parsers=new HashMap();
public void addParser(类类型,解析器){
put(类型,解析器);
}
专用解析器parserFor(类类型){
//编译器在下面抱怨未经检查的强制转换
return(Parser)parsers.get(type);
}
有没有其他方法可以实现类似的逻辑而不引起未检查的强制转换警告?因为您的map
parsers
值类型是Parser
,并且您的方法的返回类型是Parser
,所以将parsers.get(type)
的结果强制转换为T
,显然是一个错误
消除编译错误的一种方法是将类型强制转换为解析器
:
专用解析器解析器(类类型){
return(Parser)parsers.get(type);
}
此外,您还可以将返回类型更改为Parser
,因为您将解析器映射指定为map>
。这也将清除编译错误
private <T> Parser<?> parserFor(Class<T> type) {
return parsers.get(type);
}
专用解析器解析器(类类型){
返回parsers.get(类型);
}
也可以将类型参数添加到包装类中
public class YourClass<T> {
private Map<Class<T>, Parser<T>> parsers = new HashMap<>();
public void addParser(Class<T> type, Parser<T> parser) {
parsers.put(type, parser);
}
private Parser<T> parserFor(Class<T> type) {
return parsers.get(type);
}
}
公共类您的类{
私有映射解析器=新的HashMap();
public void addParser(类类型,解析器){
put(类型,解析器);
}
专用解析器parserFor(类类型){
返回parsers.get(类型);
}
}
我不确定哪一个可以正确应用,但是,尽量不要使用类型转换。考虑为什么我们使用Guang.< P>考虑从谷歌番石榴中使用A。这将允许您在没有任何编译器警告或错误的情况下执行类似操作:
TypeToInstanceMap<Parser<?>> parsers;
parsers.putInstance(new TypeToken<Parser<String>>(){},
makeStringParser());
Parser<Integer> intParser = parsers.getInstance(new TypeToken<Parser<Integer>>(){});
TypeToInstanceMap无法创建Map
,其中..
-s可以是任何东西,但必须在键与其值之间匹配;因此,您无法让编译器为您执行检查,检索类
保证为您提供一个解析器
。但是,您的代码本身是正确的;您知道您的强制转换是正确的,即使编译器没有这样做
所以,当您知道您的强制转换是正确的,但Java不知道时,您能做什么
最好、最安全的方法是精心设计一段尽可能小的特定代码,负责处理检查逻辑和未检查逻辑之间的转换,并确保未检查逻辑不会导致任何错误。然后,您只需使用适当的@SuppressWarnings
注释标记该代码。例如,您可以有如下内容:
public abstract class Parser<T> {
private final Class<T> mType;
protected Parser(final Class<T> type) {
this.mType = type;
}
public final Class<T> getType() {
return mType;
}
@SuppressWarnings("unchecked")
public final <U> Parser<U> castToParserOf(final Class<U> type) {
if (type == mType) {
return (Parser<U>) this;
} else {
throw new ClassCastException("... useful message ...");
}
}
}
公共抽象类解析器{
私有最终类mType;
受保护的解析器(最终类类型){
this.mType=type;
}
公共最终类getType(){
返回mType;
}
@抑制警告(“未选中”)
公共最终解析器castToParserOf(最终类类型){
if(type==mType){
返回(解析器)这个;
}否则{
抛出新的ClassCastException(“…有用的消息…”);
}
}
}
这将允许您在示例中安全地编写:
public <T> void addParser(final Parser<T> parser) {
parsers.put(parser.getType(), parser);
}
private <T> Parser<T> parserFor(final Class<T> type) {
return parsers.get(type).castToParserOf(type);
}
public void addParser(最终解析器){
put(parser.getType(),parser);
}
专用解析器parserFor(最终类类型){
返回parsers.get(type).castToParserOf(type);
}
我以另一种方式实现了这一点。我自己也在试验仿制药,很乐意接受批评:)
我所做的是为可解析对象添加一个标记接口,然后将其用作解析器的上限
public interface IParseable {}
public class Parser<T extends IParseable> {
T paresableObj;
// do something with parseableObject here
}
公共接口IParseable{}
公共类解析器{
T paresableObj;
//在这里对parseableObject执行一些操作
}
现在,解析器工厂不必使用通配符,也不必使用强制转换
public class ParserFactory {
private Map<Class<?>, Parser<? extends IParseable>> parsers = new HashMap<Class<?>, Parser<? extends IParseable>>();
public <T> void addParser(Class<T> type, Parser<? extends IParseable> parser) {
if(parserFor(type) == null){
parsers.put(type, parser);
}else{
//throw some excep
}
}
private <T> Parser<? extends IParseable> parserFor(Class<T> type) {
return parsers.get(type);
}
}
公共类ParserFactory{
private Map,ParserNo如果没有未经检查的强制转换,就没有办法做到这一点。只要你不做任何有趣的事情就可以了。关于编译错误,这是我的错别字;我已经相应地编辑了这个问题。对于你关于返回解析器的建议,我已经尝试过了,最初认为它会起作用。但是,然后我意识到,当我使用parserFor()时,会收到一个未经检查的强制转换警告
,这本质上意味着警告现在处于不同的位置。理想情况下,类本身不需要类型参数来完成其工作,因为它只想获取特定类型的解析器并使用它。还有什么方法可以避免警告吗?返回通配符类型,在我看来也是一个无界类型是一个坏主意。Parser
应该没问题。出于好奇,抑制原始类型警告如何比抑制未检查的警告更好/更安全?@fayerth:不是。两者都一样好——重要的是,您只需尽可能地本地化未经类型检查的代码,这样您就可以对其正确性充满信心。我的示例以th@SuppressWarnings(“raw”)
因为不能直接从解析器
转换到解析器
——这不是编译警告,而是编译错误——所以我需要一个中间转换,(解析器)
是最简单的转换。(否则我需要编写两个转换,例如(解析器)(解析器)之类的东西)此
)@fayerth:事实上,抱歉,更正:我刚刚在Eclipse中进行了测试,从解析器
到解析器
的强制转换实际上工作得很好。只是一个未经检查的强制转换警告。所以我将更改我的答案。这没有帮助,因为您现在强制客户端处理IParseable
,而不是默认为的通配符>对象
。但是,不可能所有
public class ParserFactory {
private Map<Class<?>, Parser<? extends IParseable>> parsers = new HashMap<Class<?>, Parser<? extends IParseable>>();
public <T> void addParser(Class<T> type, Parser<? extends IParseable> parser) {
if(parserFor(type) == null){
parsers.put(type, parser);
}else{
//throw some excep
}
}
private <T> Parser<? extends IParseable> parserFor(Class<T> type) {
return parsers.get(type);
}
}