2013-09-29 6 views
7

内部クラスSynchronizedCollectionがあります。コンストラクタが2つあるjava.util.Collections の内部にあります。最初はコレクションを取り、もう1つはコレクションとミューテックスをとります。 元のコンストラクタはnullでないという引数をチェックします。しかし、後でしないでください!ここには が実装されています。この実装でこれはJava SynchronizedCollectionクラスのバグですか?

SynchronizedCollection(Collection<E> c) { 
     if (c==null) 
      throw new NullPointerException(); 
     this.c = c; 
     mutex = this; 
    } 
SynchronizedCollection(Collection<E> c, Object mutex) { 
     this.c = c; 
     this.mutex = mutex; 
} 

私は2番目の コンストラクタにnullを送信することにより、不変クラスを破ることができます。私は自分自身を納得させることはできませんしかし、ジョシュ・ブロッホとニールGafter氏がこれを見ることができなかった

SynchronizedCollection(Collection<E> c) { 
     this(c,this) 
    } 
SynchronizedCollection(Collection<E> c, Object mutex) { 
     if (c==null) 
      throw new NullPointerException(); 
     this.c = c; 
     this.mutex = mutex; 
} 

は、私はこのようなものであるべきと考えています。あなたは本当に私がここで逃したものを教えてくれますか?編集


:攻撃の可能性それらのコンストラクタの

Map<String, String> m = new Map<String, String>(){ 

     @Override 
     public int size() { 
      // TODO Auto-generated method stub 
      return 0; 
     } 

        . 
        . 
        . 

     @Override 
     public Collection<String> values() { 
      return null; 
     } 


    }; 

    Map<String, String> synchronizedMap = Collections.synchronizedMap(m); 
    Collection<String> values = synchronizedMap.values(); 

答えて

11

これはバグです。両方のコンストラクタは一貫している必要があります。両方とも例外をスローするか、スローする必要がありません。

これは今、両方のコンストラクタが例外をスローするJava 8で修正されています:

SynchronizedCollection(Collection<E> c) { 
    this.c = Objects.requireNonNull(c); 
    mutex = this; 
} 

SynchronizedCollection(Collection<E> c, Object mutex) { 
    this.c = Objects.requireNonNull(c); 
    this.mutex = Objects.requireNonNull(mutex); 
} 
2

両方がパッケージ保護及びおそらくはCollectionspublicsynchronizedList()synchronizedSet()方法によりnull引数と共に使用することができる唯一の最初のものです。

他のコンストラクタは内部で(Collectionsクラス内で)使用され、最初の引数はさまざまな実装(呼び出しコード)では決してnullになることはありません。

java.utilパッケージで何かを作成しようとすることもできますが、おそらくSecurityExceptionが表示されます。

+2

私ができるには、Mapインタフェースを拡張する方法は、java.utilパッケージに私の実装をかけることなく、nullを返すように()オーバーライド値!オブジェクトはvalues()メソッドによって返され、2番目のコンストラクタに送られます。Collections.synchronizedMap()およびBoomを参照してください。 –

+0

私の編集ノートを参照してください –

+1

@MortezaAdi公正であるためには、その動作を明示的に許可しない 'Map.values()'の契約を乱用すると主張できます。 (これはどちらも許可しませんが、 'entrySet()'、 'keySet()'、 'values()'の戻り値をnullにチェックしていますか?だから?)クラスは堅牢性に欠けているが、APIを実際に悪用することなくそれを壊す方法はない。私はSotiriosに同意します。サードパーティのコードで何らかの理由で破損した場合、それはもっと問題になるでしょう。 – millimoose

関連する問題