来自Effective Java Item 26 偏好通用类型
在所有其他条件相同的情况下,抑制未经检查的风险更大 强制转换为数组类型而不是标量类型,这表明了 第二解决方案但是在一个比Stack更现实的泛型类中,你 可能会在代码中的许多点读取数组, 所以选择第二种解决方案需要很多演员来E 而不是单个演员到E [],这就是为什么第一个解决方案被更多地使用 通常[Naftalin07,6.7]。
作者在scalar type
的意思是什么,他想在这里传达什么?什么是选项1被认为比选项2更危险?
代码:
// The elements array will contain only E instances from push(E).
// This is sufficient to ensure type safety, but the runtime
// type of the array won't be E[]; it will always be Object[]!
@SuppressWarnings("unchecked")
public Stack() {
elements = (E[]) new Object[DEFAULT_INITIAL_CAPACITY];
}
VS
// Appropriate suppression of unchecked warning
public E pop() {
if (size == 0)
throw new EmptyStackException();
// push requires elements to be of type E, so cast is correct
@SuppressWarnings("unchecked") E result =
(E) elements[--size];
elements[size] = null; // Eliminate obsolete reference
return result;
}
答案 0 :(得分:5)
此示例中的标量类型是单个值,而不是由多个值组成的数组,如数学向量。 E []是数组,E是标量。
我最初的想法是,Joshua Bloch认为在数组的情况下抑制未经检查的强制转换警告风险更大,因为证明代码的类型安全性不会发生任何错误会更加复杂。
ruakh在评论中提到了另一个值得考虑的意见:“我会认为这与证据的复杂性无关,就像在发现错误时检测错误一样。我认为通常会有更少的错误错误但未经检查的强制转换为(E)与引发ClassCastException的后续隐式强制转换之间的“距离”,而不是使用强制转换为(E [])“
还有第三种意见(如果我理解正确的话,这是无可争辩的想在他的回答中指出的,无论如何这是我的新观点)是阵列演员是“冒险的”,因为这个阵列不可能在这堂课之外使用。 (E[])
是未经检查的强制转换:由于类型擦除,运行时无法真正检查此(不正确)强制转换的正确性。我们得到了一个肮脏的技巧,但如果某个方法将此数组作为E []返回,并且它将被分配给客户端类中的E [],那么它在运行时仍会因ClassCastException而失败:
public class Test {
public static void main(String[] args) {
Stack<String> stack = new Stack<String>();
String[] array = stack.getArray(); // ClassCastException at runtime here!
}
}
class Stack<E> {
E[] elements;
public Stack() {
elements = (E[]) new Object[10];
}
// oh no, our dirty-tricky array escapes!
E[] getArray() {
return elements;
}
}
答案 1 :(得分:5)
理想情况下,我们想写
E[] elements;
public Stack()
{
elements = new E[DEFAULT_INITIAL_CAPACITY];
}
不幸的是,Java犯了一个巨大的错误并且不允许这样做。所以我们需要解决方法。
此解决方法
E[] elements;
public Stack()
{
elements = (E[]) new Object[DEFAULT_INITIAL_CAPACITY];
}
理论上在Java类型系统中错误,因为Object[]
不是E[]
的子类型。 碰巧在今天的 JVM上运行时工作,但是,我们不应指望它永远工作。嗯,实际上,人们确实指望这一点,我认为它不会有任何改变的机会。所以没人关心。
(更正:实际上语言规范§5.5特别允许演员在运行时工作,因此每个规范的代码都没有错。然而,它太过于hackish,它不是“普通”类型系统的一部分,它的正确性是基于一些我们不想真正学习的妥协。)
第二种解决方法在实际和理论上都是正确的
Object[] elements;
public Stack()
{
elements = new Object[DEFAULT_INITIAL_CAPACITY];
}
public push(E e)
{
...
elements[size++] = e;
}
public E pop()
{
...
E result = (E)element[size--];
}
从Object到E的转换是正确的,因为程序逻辑确保它必须是E
。
答案 2 :(得分:1)
在这种情况下,标量类型表示非数组类型。