修复未经检查的调用原始类型警告Java

时间:2017-07-12 23:57:32

标签: java generics

我有如下所示的代码。我在ingest方法中使用Handler raw类型时遇到了几个未经检查的警告。我坚持使用删除警告和我对原始类型的使用的最佳方法。我的主要障碍是ingest方法参数是IV2GraphObject,并且在尝试在处理程序上调用handle方法时,任何在Handler上设置边界的尝试都会产生编译错误。

public class IV2Ingestor implements Ingestor<IV2GraphObject> {
  public interface Handler<T extends IV2GraphObject> {
    void handle(T iv2Object);

    Set<? extends Element> getNewElements();
  }

  // map of handlers for supported objects
  private Map<Class<? extends IV2GraphObject>, Handler<? extends IV2GraphObject>> handlers;

  public static IV2Ingestor getInstance(VisalloEnv environment) {
    // create a new instance
    IV2Ingestor ingestor = new IV2Ingestor();

    ingestor.handlers = new HashMap<>();
    ingestor.handlers.put(Tweet.class, new TweetHandler(graphFactory));
    ingestor.handlers.put(TwitterUser.class, new TwitterUserHandler(graphFactory));
    ingestor.handlers.put(GoogleNews.class, new GoogleNewsHandler(graphFactory));
    ingestor.handlers.put(VKPost.class, new VKPostHandler(graphFactory));
    ingestor.handlers.put(YouTube.class, new YouTubeHandler(graphFactory));
    ingestor.handlers.put(Instagram.class, new InstagramHandler(graphFactory));

    // return ingestor
    return ingestor;
  }

  @Override
  public void ingest(IV2GraphObject ingestable) {
    Class<? extends IV2GraphObject> ingestableClass = ingestable.getClass();

    if (handlers.containsKey(ingestableClass)) {
        Handler handler = handlers.get(ingestableClass);

        try {
            handler.handle(ingestable);
        } finally {
            // persist changes
            graph.flush();

            // notify GPWs of any new graph elements
            workQueueRepository.pushElements(handler.getNewElements(), Priority.LOW);
        }
    }
  }

1 个答案:

答案 0 :(得分:0)

首先,您有一个从类到处理程序的映射,您希望每个Class<T>映射到Handler<T>,但您无法用Map的类型表达该关系。要安全地执行此操作,您应该创建一个新类,其API强制执行参数类型中的关系并返回getput的值(该类内部仍然具有未经检查的强制转换,但是类的API保证这是安全的):

class ClassToHandler {
    private Map<Class<? extends IV2GraphObject>, Handler<? extends IV2GraphObject>> map
        = HashMap<>();

    @SuppressWarnings("unchecked")
    public <T extends IV2GraphObject> Handler<T> get(Class<T> clazz) {
        return (Handler<T>)map.get(clazz);
    }

    public <T extends IV2GraphObject> void put(Class<T> clazz, Handler<T> handler) {
        map.put(clazz, handler);
    }
}

你会handlers成为这个类的对象。这样,您就可以拨打handlers.get()来返回更好的类型。

第二个问题是ingestable.getClass()返回类型Class<? extends IV2GraphObject>,它与ingestableIV2GraphObject的类型过于松散地联系在一起。对于某些ingestableClass,您理想的是Class<T>ingestableTT。这样handlers.get(ingestableClass)将返回Handler<T>handler.handle(ingestable)将会编译。

返回类型? extends.getClass()的原因是ingestable的实际运行时类可能是IV2GraphObject的子类型(事实上,在这里,它应该始终是一个子类型),因此它的类不是Class<IV2GraphObject>。但是,我们知道存在类型T(对象的实际运行时类型),其中ingestableT的实例,ingestable.getClass()是{的实例{1}};但是,我们如何得到Class<T>?我们可以使用辅助方法和捕获来从通配符T中获取T

?

但是,即使我们这样做,编译器仍然不知道helper(ingestableClass, ...); private <T extends IV2GraphObject> void helper(Class<T> clazz, ...) { ... } 是同一类型ingestable的实例(我们知道它必须是,但编译器只知道T 1}}是ingestable)的一个实例。我们可以使用类的IV2GraphObject将其强制转换为.cast()类型,而不会发出任何警告(我们知道强制转换将始终成功,但我们只是为了编译而没有警告;我们也可以直接完成一个T演员会产生警告):

(T)