【问题标题】:Java and generic type boundaries [duplicate]Java和泛型类型边界[重复]
【发布时间】:2016-02-12 00:30:31
【问题描述】:

一些背景

我正在开发一个基于 Lambda 表达式的小型 DI 容器。 我有代表 lambda 的接口:

@FunctionalInterface
public interface LambdaOp<T> {
    T resolve();
}

这是(非常简化的)容器:

public class Container {
    private final Map<Class<?>, LambdaOp<?>> bindings;

    public <T> void bind(Class<T> clazz, LambdaOp<? extends T> lambda) {
        bindingd.put(clazz, lambda);
    }

    public <T> T resolve (Class<T> clazz) {
        LambdaOp<?> lambda = bindings.get(clazz);
        return (T) lambda.resolve(); 
    } 

}

有了这个实现,我可以做这样的事情:

container.bind(
    FooInterface.class,
    () -> {
        FooImplementation foo = new FooImplementation();
        foo.setParameterA(paramA);
        //do whatever needed to configure it
        return foo;  
    }
);

FooInterface foo2 = container.resolve(FooInterface.class);

它工作正常而且很好,因为编译器不会让我做这样的事情:

container.bind(
    FooInterface.class,
    () -> new BarImplementation() //compiler error; Bar does not implement Foo
);

问题

绑定 Map 本身并不保证 LambdaOp 会有一个泛型类型,该类型扩展了用作键的类。

private final Map<Class<?>, LambdaOp<?>> bindings;

因此,我在以下行收到未经检查的警告

return (T) lambda.resolve();

我认为绑定方法签名足以保证内聚(是吗?)但仍然感觉有些难闻。

有没有什么方法可以以更有凝聚力的方式实现它?

编辑:

完整代码位于github。我最近做了很多改动,README.md very有点过时了。

【问题讨论】:

  • 据我所知,没有办法解决这个问题。我不会认为警告是一个问题,因为它隐藏在您的实施背后。将始终保证客户端接收到正确的类型,因为(如您所述)添加到地图的唯一方法是通过您的 bind 方法。
  • 在 Java 中,任何时候转换为不可具体化的泛型类型,都会收到未经检查的警告。这是因为类型信息在运行时不存在,Java 环境无法保证强制转换的类型安全。这样的情况无济于事..如果您分析自己的代码并且可以证明它是类型安全的,那么只需取消警告。
  • 不错。我使用这个项目作为学习语言的工具,从更有经验的开发人员那里得到一些反馈总是好的。
  • 顺便说一句,您的LambdaOp&lt;T&gt; 接口可以替换为标准Supplier&lt;T&gt;

标签: java generics lambda java-8


【解决方案1】:

为什么不直接使用Class clazz 键进行投射?您的逻辑已经保证了演员阵容将始终有效

return clazz.cast( lambda.resolve() );

编辑澄清: 使用Class 对象在没有警告的情况下工作但简单的泛型转换没有的原因是因为在运行时使用泛型转换,泛型类型也可能被擦除为Object,因此编译器无法保证演员表将适用于预期的类型。另一方面,Class 对象将包含进行强制转换所需的所有信息,因此编译器可以安全地允许它用于泛型类型。

当然,假设您不会特意弄乱泛型。

【讨论】:

【解决方案2】:

没有办法做到这一点,这样编译器就会自然而然地自行判断并保证泛型类型是正确的。但是,您可以告诉编译器闭嘴,在这种情况下这样做是合适的,因为您的实现确实提供了相关保证。

public <T> T resolve (Class<T> clazz) {
    @SuppressWarnings("unchecked")
    LambdaOp<? extends T> lambda = (LambdaOp<? extends T>) bindings.get(clazz);
    return lambda.resolve(); 
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-04-03
    • 2016-03-31
    • 1970-01-01
    • 1970-01-01
    • 2018-08-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多