4

効果的なJavaアイテム26から ジェネリック型を優先

他のすべての条件が同じであれば、スカラー型よりも配列型へのチェックされていないキャストを抑制する方がリスクが高く、2番目の解決策が提案されます。ただし、Stackよりも現実的なジェネリッククラスでは、コード内の多くのポイントで配列から読み取る可能性があるため、2番目のソリューションを選択するには、E []への単一のキャストではなく、Eへの多数のキャストが必要になります。最初のソリューションがより一般的に使用されます[Naftalin07、6.7]。

著者はここで何を意味し、scalar type彼はここで何を伝えようとしているのですか?オプション2よりも危険と見なされるオプション1は何ですか?

コード :

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

3 に答える 3

5

この例のスカラー型は、数学ベクトルのように複数の値で構成される配列とは対照的に、単一の値です。E[] は配列で、E はスカラーです。

Joshua Bloch は、コードのタイプ セーフに問題が発生しないことを証明するのはより複雑であるため、配列の場合は unchecked cast 警告を抑制する方がリスクが高いと考えているというのが私の最初の考えでした。

考慮に値する別の意見として ruakh はコメントで次のように述べています。 (E[]) へのキャストが代わりに使用された場合よりも、(E) へのしかしチェックされていないキャストと、ClassCastException を発生させる後続の暗黙的なキャスト"

そして、3 番目の意見 (私が正しく理解している場合、これは評判の悪い人が彼の回答で指摘したいことであり、いずれにせよこれは私の新しい意見です) は、この配列はこれ以外では使用できないため、配列キャストは「危険」であるというものです。クラス。(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;
    }
}
于 2013-02-20T18:07:50.920 に答える
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 では、キャストが実行時に機能することを明確に許可しているため、仕様ごとにコードが間違っているわけではありません。それでも、ハック的すぎます。「通常の」型システムの一部ではありません。その正確性は、私たちが本当に学びたくないいくつかの妥協点.)

その2番目の回避策は、実際的にも理論的にも正しいです

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

プログラム ロジックでは必ずE.

于 2013-02-20T18:57:39.440 に答える
1

この場合のスカラー型は、非配列型を意味します。

于 2013-02-20T18:04:29.457 に答える