为什么抑制这种未经检查的警告是安全的?

时间:2013-02-25 16:41:00

标签: java generics effective-java

考虑 Effective Java 泛型章节中定义的UnaryFunction接口。

public interface UnaryFunction<T> {
T apply(T arg);
}

以及以下用于返回UnaryFunction

的代码
// Generic singleton factory pattern
private static UnaryFunction<Object> IDENTITY_FUNCTION = new UnaryFunction<Object>() {
  public Object apply(Object arg) { return arg; }
};

// IDENTITY_FUNCTION is stateless and its type parameter is
// unbounded so it's safe to share one instance across all types.
@SuppressWarnings("unchecked")
public static <T> UnaryFunction<T> identityFunction() {
  return (UnaryFunction<T>) IDENTITY_FUNCTION;
}

为什么IDENTITY_FUNCTION(UnaryFunction<T>)的演员阵容安全?

这本书说的是我要问的问题,但我不能遵循这里的逻辑。我们在哪里调用执行身份操作的apply函数?我很困惑,因为它是一个函数,它返回传递给它的同一个对象,而不修改任何东西。

  

将IDENTITY_FUNCTION投射到(UnaryFunction<T>)会生成一个   未经检查的投射警告,因为UnaryFunction<Object>不是   每个UnaryFunction<T> T。但身份功能是特殊的:它   返回其参数未修改,因此我们知道它是使用的类型安全   无论UnaryFunction<T>的价值如何,它都是T。因此,我们可以   自信地抑制由生成的未经检查的强制转换警告   这个演员。一旦我们完成了这个,代码编译没有错误或   警告。

3 个答案:

答案 0 :(得分:3)

使用类型擦除

T apply(T arg);

实际上是

Object apply(Object arg);

现在为身份

Abc x = ...;
Abc y = IDENTITY.apply(x);

可以假设它总是正确的(相当于y = x;)。

(非常务实。)

答案 1 :(得分:3)

演员阵容是安全的,只有身份函数返回首先传递给它的 完全 对象。因此,在运行时,通用参数T没有可以违反演员表的专门化。

Aka,你正在投射一个对象,因为它是自己的类型。

答案 2 :(得分:1)

identityFunction()只返回函数本身,用于不同的对象。

以下是一个用法示例:

String result = identityFunction().apply("Hello");

类型安全警告很重要。它就在那里,因为实现了IDENTITY_FUNCTION,使得编译器不能保证函数返回与输入相同的类型。 考虑以下替代实现:

private static UnaryFunction<Object> CONST_FUNCTION = new UnaryFunction<Object>() {
    public Object apply(Object arg) { return "Default"; } 
};

此实现始终返回一个字符串,因此将其作为一般数据类型的一元函数返回显然是不安全的。

在我们的例子中(IDENTITY_FUNCTION),返回类型与输入类型相同的证明在实现中。我们返回相同的实例,因此保证它们具有相同的类型。当您取消类型安全警告时,建议使用证明来证明它。