简体   繁体   English

如何使用泛型和Supplier Lambda在抽象方法上安全地解决此类型不匹配问题

[英]How to safely fix this type mismatch on abstract method with generics and Supplier lambda

We have a cache framework which we use to wire application-specific cache types (such as this authentication cache shown below) to various implementations (eg ehcache, redis, memcached etc). 我们有一个缓存框架,可用于将特定于应用程序的缓存类型(例如下面显示的身份验证缓存)连接到各种实现(例如ehcache,redis,memcached等)。 The framework is just an abstraction layer to allow the application to define and manipulate its cache similar to a map of key-value pairs, while specifying its app-specific key class and value class. 该框架只是一个抽象层,允许应用程序在定义其特定于应用程序的键类和值类的同时,类似于键值对的映射来定义和操作其缓存。

So for example we have: 因此,例如,我们有:

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

public class AuthenticationCacheKey implements IAuthenticationCacheKey {...}

public class AuthenticationCacheEntry implements IAuthenticationCacheEntry {...}

and elsewhere in the application, the app overrides an abstract method which provides a Supplier for its cache: 而在应用程序的其他位置,该应用程序会覆盖一个抽象方法,该方法为其缓存提供一个Supplier

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

But this creates a compiler error: 但这会导致编译器错误:

Type mismatch: cannot convert from AuthenticationCache to BaseAuthenticationCacheImpl 类型不匹配:无法从AuthenticationCache转换为BaseAuthenticationCacheImpl

Generics are kicking my backside these days. 这些天,仿制药正在踢我的后腿。 Am I doing this completely wrong? 我这样做是完全错误的吗? Can I safely cast the supplier to (BaseAuthenticationCacheImpl<K,E>) since I know after type erasure it'll be the same runtime and I know that the concrete key/value classes of AuthenticationCache satisfy K,E (eg extends IAuthenticationCacheKey/IAuthenticationCacheEntry) ? 我可以安全地将供应商(BaseAuthenticationCacheImpl<K,E>)(BaseAuthenticationCacheImpl<K,E>)因为我知道类型擦除后,它将是相同的运行时,并且我知道AuthenticationCache的具体键/值类满足K,E(例如,扩展了IAuthenticationCacheKey / IAuthenticationCacheEntry )?

You could cheat the compiler by using something like this: 您可以使用以下方法欺骗编译器:

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;
    }

}

The cast is technically safe, as long as you can guarantee that K and E are always AuthenticationCacheKey and AuthenticationCacheEntry , but the compiler can't give you that guarantee. 只要您可以保证KE始终为AuthenticationCacheKeyAuthenticationCacheEntry ,则转换在技术上是安全的,但是编译器无法提供此保证。

Assuming these classes: 假设这些类:

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

interface IAuthenticationCacheKey {}

interface IAuthenticationCacheEntry {}

A safe solution is to change the return type to: 一个安全的解决方案是将返回类型更改为:

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

As long as the BaseAuthenticationCacheImpl is just used to produce something that implements IAuthenticationCacheKey and something that implements IAuthenticationCacheEntry , but is not a consumer. 只要BaseAuthenticationCacheImpl仅仅是用于生产的东西,实现IAuthenticationCacheKey和一些实现IAuthenticationCacheEntry ,而不是消费者。

Depending one how you actually use the type parameters of BaseAuthenticationCacheImpl you might even be able to just drop them completely and exchange them for IAuthenticationCacheKey and IAuthenticationCacheEntry directly. 根据您实际使用BaseAuthenticationCacheImpl的类型参数的BaseAuthenticationCacheImpl您甚至可以完全删除它们并将它们直接交换为IAuthenticationCacheKeyIAuthenticationCacheEntry (Sometimes the best solution to a generics problem is to not use generics) (有时,解决泛型问题的最佳方法是不使用泛型)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM