如何使用泛型和Supplier lambda在抽象方法上安全地修复此类型不匹配

时间:2018-05-09 15:20:04

标签: java generics

我们有一个缓存框架,用于将特定于应用程序的缓存类型(例如下面显示的此身份验证缓存)连接到各种实现(例如ehcache,redis,memcached等)。该框架只是一个抽象层,允许应用程序定义和操作其缓存,类似于键值对的映射,同时指定其特定于应用程序的键类和值类。

例如我们有:

public class AuthenticationCache extends BaseAuthenticationCacheImpl<AuthenticationCacheKey, AuthenticationCacheEntry> {...}

public class AuthenticationCacheKey implements IAuthenticationCacheKey {...}

public class AuthenticationCacheEntry implements IAuthenticationCacheEntry {...}

以及应用程序中的其他位置,应用程序会覆盖为其缓存提供 Supplier 的抽象方法:

@Override
protected <K extends IAuthenticationCacheKey, E extends IAuthenticationCacheEntry> Supplier<BaseAuthenticationCacheImpl<K, E>> getAuthCacheSupplier() {
    Supplier<BaseAuthenticationCacheImpl<K, E>> supplier = () -> {
        return new AuthenticationCache();
    };
}

但这会产生编译错误:

  

类型不匹配:无法从AuthenticationCache转换为   BaseAuthenticationCacheImpl

仿制药现在正在踢我的背后。我这样做完全错了吗?我可以安全地将供应商转换为(BaseAuthenticationCacheImpl<K,E>),因为我知道在类型擦除之后它将是相同的运行时并且我知道AuthenticationCache的具体键/值类满足K,E(例如, IAuthenticationCacheKey / IAuthenticationCacheEntry)?

2 个答案:

答案 0 :(得分:0)

您可以通过使用以下内容来欺骗编译器:

protected <K extends IAuthenticationCacheKey, E extends IAuthenticationCacheEntry> Supplier<BaseAuthenticationCacheImpl<K, E>> getAuthCacheSupplier() {
    return () -> new AuthenticationCache().toBaseAuthenticationCacheImpl();
}


class AuthenticationCache extends BaseAuthenticationCacheImpl<AuthenticationCacheKey, AuthenticationCacheEntry> {

    public BaseAuthenticationCacheImpl toBaseAuthenticationCacheImpl(){
        return this;
    }

}

答案 1 :(得分:0)

演员在技术上是安全的,只要您可以保证KE总是AuthenticationCacheKeyAuthenticationCacheEntry,但编译器无法提供你保证。

假设这些类:

class BaseAuthenticationCacheImpl<K extends IAuthenticationCacheKey, E extends IAuthenticationCacheEntry> {}

interface IAuthenticationCacheKey {}

interface IAuthenticationCacheEntry {}

安全的解决方案是将返回类型更改为:

@Override
protected Supplier<BaseAuthenticationCacheImpl<?, ?>> getAuthCacheSupplier() {
    return AuthenticationCache::new;
}

只要BaseAuthenticationCacheImpl仅用于生成实现IAuthenticationCacheKey的内容以及实现IAuthenticationCacheEntry但不是消费者的内容。

根据您实际使用BaseAuthenticationCacheImpl类型参数的方式,您甚至可以完全删除它们并直接与IAuthenticationCacheKeyIAuthenticationCacheEntry进行交换。 (有时候泛型问题的最佳解决方案是不使用泛型)