Java泛型和Serializable

Mar*_*urz 5 java generics serialization

我们创建了一个抽象类,用于处理Redis(set/get values),如下所示:

public abstract class AbstractCachedSupport<T extends Serializable> {
    protected T get(CacheKey key, Supplier<T> supplier) {...}
    // ...
}
Run Code Online (Sandbox Code Playgroud)

我不高兴的是,在扩展这个类时我们不能使用List,Map等接口:

public class CachedMap extends AbstractCachedSupport<Map<String, Integer>>
Run Code Online (Sandbox Code Playgroud)

因为它们不扩展Serializable,所以我们必须始终使用具体的类:

public class CachedMap extends AbstractCachedSupport<HashMap<String, Integer>>
Run Code Online (Sandbox Code Playgroud)

毋庸置疑,当从一个具体类迁移到另一个具体类时,这有其共同的问题.这也不是我称之为最佳实践的东西,但也许这只是我.

使我们能够灵活地使用接口的替代方法是删除有界类型并在运行时检查T是否扩展Serializable:

public abstract class AbstractCachedSupport<T> {
    public AbstractCachedSupport() {
        final Class<T> type = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
        if (!Serializable.class.isAssignableFrom(type)) {
            throw new RuntimeException("T must extend Serializable");
        }
    }

    protected T get(CacheKey key, Supplier<T> supplier) {...}
    // ...
}
Run Code Online (Sandbox Code Playgroud)

这使我们没有编译时间检查T扩展Serializable,也不是一件好事.

你知道我们如何能够优雅地解决这个问题吗?您是想使用第一个(有界类型参数)还是第二个(仅运行时检查)?

折衷方案是选择第一个并始终使用容器类来保存集合:

public class IntegerParamsContainer implements Serializable {
    private static final long serialVersionUID = 1L;
    private Map<String, Integer> map;
}

public class CachedMap extends AbstractCachedSupport<IntegerParamsContainer>
Run Code Online (Sandbox Code Playgroud)

但这最终与第二个问题相同:没有编译时间检查,开发人员肩负着始终使用实现Serializable的集合的责任.

编辑: 一些扩展类AbstractCachedSupport是春季(4.1版目前)组件类和它们不叫CachedMap或类似的东西,而是CityAutocompleteDataBean,WrParamsDataBean等等.如果我们增加仿制药到这些组件类,我们将与宣言,如结束:

@Inject
private CityAutocompleteDataBean<ArrayList<String>>;
@Inject
private WrParamsDataBean<HashMap<String, WrData>>;
Run Code Online (Sandbox Code Playgroud)

而不是

@Inject
private CityAutocompleteDataBean;
@Inject
private WrParamsDataBean;
Run Code Online (Sandbox Code Playgroud)

当他们看到这样的代码行时,使用<ArrayList<String>><HashMap<String, WrData>>将逃脱大多数开发人员的原因.考虑到我们的起点以及我们使用它的原因,我也觉得它很难看.

尽管如此,这符合我的要求,谢谢Jesper.

Jes*_*per 5

您可以使用以下语法执行此操作:

public abstract class AbstractCachedSupport<T extends Serializable> {
    // ...
}

public class CachedMap<T extends Map<String, Integer> & Serializable>
        extends AbstractCachedSupport<T> {
    // ...
}
Run Code Online (Sandbox Code Playgroud)

这意味着该类型T必须实现Map<String, Integer>Serializable.

然后,您可以使用实现CachedMap的特定Map实现Serializable:

CachedMap<HashMap<String, Integer>> cachedMap = new CachedMap<>();
Run Code Online (Sandbox Code Playgroud)