2013-09-29 3 views
7

Es gibt eine interne Klasse SynchronizedCollection - in java.util.Collections mit zwei Konstruktoren. das erste nimmt die Sammlung und das andere nimmt Sammlung und einen Mutex. Der ehemalige Konstruktor prüft das Argument, dass er nicht null ist. aber die später nicht! Hier ist die Implementierung.Ist das ein Fehler in der Java SynchronizedCollection-Klasse?

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

mit dieser Implementierung i die Klasseninvariante durch Senden null zweiten Konstruktor brechen kann.

ich glaube, es so etwas wie dies sein sollte:

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

aber ich mich nicht überzeugen können Josh Bloch und Neal Gafter konnte das nicht sehen. Kannst du mir wirklich sagen, was ich hier verpasst habe?


bearbeitet: möglicher Angriff

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(); 

Antwort

11

Sicher ist dies ein Fehler. Die beiden Konstruktoren sollten konsistent sein, entweder sollten beide eine Ausnahme werfen oder keine werfen.

Dies hat beide Konstrukteure fest in Java 8. Nun die Ausnahme werfen:

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

Beide dieser Konstruktoren geschützt sind und nur das Paket ersten kann möglicherweise mit einem Argumente null durch die publicsynchronizedList() und synchronizedSet() Methoden der Collections verwendet werden.

Der andere Konstruktor wird intern verwendet (in der Collections Klasse) und das erste Argument kann nie null in den verschiedenen Implementierungen (Aufrufcode) sein, so dass Sie es nicht brechen können.

Sie könnten immer versuchen, etwas im java.util Paket zu erstellen, aber Sie werden höchstwahrscheinlich eine SecurityException erhalten.

+2

I erweitert Map-Schnittstelle kann eine Korrekturwerte() -Methode ohne Putting meine Implementierung in java.util Paket null zurück! Das Objekt wird von der Methode values ​​() an den zweiten Konstruktor zurückgegeben - siehe Collections.synchronizedMap() und Boom !! –

+0

sehe meine Notiz bearbeiten –

+1

@MortezaAdi Um fair zu sein, könnte dies als Missbrauch der Vertrag von 'Map.values ​​()' argumentiert werden, die dieses Verhalten nicht explizit erlaubt. (Es ist es auch nicht verbieten, aber: ** ** ** ** ** ** ** ** ** ** * * ** * * * * * Haben Sie jemals gesehen, jemand anderes zu tun, die Rückgabewerte von 'entrySet()', 'keySet()' so?) Ich gebe dir, dass die Klasse an Robustheit fehlt, aber es gibt keine Möglichkeit, es zu brechen, ohne die API wirklich zu missbrauchen. Ich stimme Sotirios zu, dass es eher ein Problem sein könnte, wenn Sie den Code von Drittanbietern beschädigen könnten. – millimoose