回归基础:方法Sig中的泛型

Arr*_*ran 0 java generics

因此,当我尝试将对象Map<String, Future<Cache<?>>传递给方法时,我的代码显示编译器错误Map<String, Future<?>>.如下...

private static void logProgress(Map<String, Future<Cache<?>>> cacheLoaders, Map<String, Future<?>> cacheWriters)
            throws InterruptedException, ExecutionException {
        if (logFuturesAndCheckStillRunning("loader", cacheLoaders)
                && logFuturesAndCheckStillRunning("writer", cacheWriters)) {
            try {
                TimeUnit.SECONDS.sleep(10);
            } catch (InterruptedException e) {
                logger.error("interrupted whilst log progress slept", e);
            }
            logProgress(cacheLoaders, cacheWriters);
        }
    }

    private static boolean logFuturesAndCheckStillRunning(String context, Map<String, Future<?>> futures)
            throws InterruptedException, ExecutionException {
        boolean areStillRunning = false;
        for (String key : futures.keySet()) {
            Future<?> future = futures.get(key);
            if (future.isDone()) {
                futures.remove(key);
                logger.info("{} future has completed: {}", context, future.get());
            } else {
                logger.info("{} future is still running: {}", context, future);
                areStillRunning = true;
            }
        }
        return areStillRunning;
    }
Run Code Online (Sandbox Code Playgroud)

这应该工作,因为我的方法应该接受一个Map,其中键是一个字符串,值是任何类型的Future.

下面显示我可以使用缓存加载器未来并将其放入缓存编写器映射但我不能将缓存编写器放入缓存加载器映射,因为缓存加载器映射中的未来指定了CacheLoader泛型类型"在我脑海中"是一个类似的概念.

            logger.info("starting cache loading");
            Map<String, Future<Cache<?>>> cacheLoaders = startCacheLoading(injector, executorLoadingService);

            logger.info("starting cache writing");
            Map<String, Future<?>> cacheWriters = startCacheWriting(injector, executorWritingService);

            Future<Cache<?>> aa = cacheLoaders.get("");
            cacheWriters.put("", aa);

            Future<?> bb = cacheWriters.get("");
            cacheLoaders.put("", bb);
Run Code Online (Sandbox Code Playgroud)

所以我的问题是......有人可以向我解释为什么原始代码片段存在编译错误,并且如果有办法让我通过两个地图而丢失值的类型作为期货?

And*_*ner 6

更多地剥离你的例子,你正在尝试编译这个:

interface Cache<T> {}

static void logProgress(Map<String, Future<?>> futures) {}

public static void main (String[] args) {
    Map<String, Future<Cache<?>>> map = new HashMap<>();
    logProgress(map);  // Compiler error.
}
Run Code Online (Sandbox Code Playgroud)

futures地图上的边界更改为:

Map<String, ? extends Future<?>>
Run Code Online (Sandbox Code Playgroud)

Ideone demo


您最初的代码不起作用的原因是,泛型是在Java中不变的:即使Future<Cache<?>>Future<?>,一个Map<String, Future<Cache<?>>不是Map<String, Future<?>>,在几乎相同的方式,一个Map<String, Integer>不是Map<String, Object>.

如果是,您的logProgress方法可以添加Map<Future<SomethingOtherThanCache>>futures地图,导致返回时发生非类型安全的事情:

void logProgress(Map<String, Future<?>> futures) {
  Future<String> future = ...
  futures.put("", future);  // Compiler error, but let's pretend it's OK.
}

Map<String, Future<Cache<?>> map = new HashMap<>();
logProgress(map);  // Compiler error, but let's pretend it's OK.
Future<Cache<?>> future = map.values().iterator().next();
Cache<?> cache = future.get();  // ClassCastException here!
Run Code Online (Sandbox Code Playgroud)

相反,您需要使用上限(? extends Future<?>),这使得logProgress尝试将任何内容放入地图(除文字之外null)的编译器错误.

void logProgress(Map<String, ? extends Future<?>> futures) {
  futures.put("", Futures.immediateFuture("boom!")); // Compiler error.

  futures.put("", null);  // OK.
}
Run Code Online (Sandbox Code Playgroud)