2009-05-16 7 views
49

java.util.Propertiesクラスは、キーと値が両方ともStringであるマップを表すことを意図しています。これは、Propertiesオブジェクトがテキストファイルである.propertiesファイルを読み取るために使用されるためです。java.util.PropertiesがMap <Object、Object>を実装し、Map <String、String>を実装しない理由

Java 5では、なぜMap<Object,Object>を実装し、Map<String,String>ではなく、このクラスを実装したのですか?

javadoc状態:

プロパティのHashtableから継承するため、プットとのputAllメソッドは、Propertiesオブジェクトに適用することができます。キーや値が文字列でないエントリを呼び出し側が挿入できるため、これらの使用は強く推奨されません。代わりにsetPropertyメソッドを使用する必要があります。 StringまたはString以外のキーまたは値を含む「侵害された」Propertiesオブジェクトでstoreメソッドまたはsaveメソッドが呼び出された場合、呼び出しは失敗します。

キーと値はどちらもStringであるはずなので、適切なジェネリック型を使用して静的に強制するのはなぜですか?

Properties implement Map<String,String>は、pre-Java 5用に書かれたコードと完全に下位互換性がないと思われます。非文字列をPropertiesオブジェクトに貼り付ける古いコードがある場合、そのコードはJava 5でコンパイルされなくなります。しかし...それはいいことではない?コンパイル時にこのような型のエラーを捕まえるのは、ジェネリックの全体的なポイントではないのですか?

答えて

50

彼らはJavaの初期の段階で急いで行ったので、後で4つのバージョンがどのような意味を持つのか分かりませんでした。

ジェネリックは最初からJavaの設計の一部であると思われていましたが、機能は複雑すぎて、当時は不要でした。その結果、標準ライブラリのコードの多くは、非ジェネリックコレクションの前提で書かれています。Martin Oderskyのプロトタイプ言語「Pizza」では、Javaコードとバイトコードの両方で完全な下位互換性をほぼ維持しながら、それらがかなりうまくいく方法を示しました。プロトタイプはJava 5に導かれました。コレクションクラスは、古いコードが機能し続けるようにジェネリックで改良されました。

彼らは遡及Map<String, String>からProperties継承を作成した場合残念ながら、次の以前に有効なコードは、作業を停止する:

Map<Object, Object> x = new Properties() 
x.put("flag", true) 

なぜ誰もがそれを行うだろう私を超えているが、中に後方互換性に対するSunのコミットメントJavaはヒーローを超えて無意味な存在になった。

現在、ほとんどの教育観察者から認められていることは、PropertiesMapから決して継承されるべきではないということです。代わりにMapを囲んで、意味のあるマップの機能のみを公開する必要があります。

Martin OderskyはJavaを再開発して以来、よりクリーンな新しいScala言語を作成し、いくつかのミスを継承し、いくつかの分野で新しい土台を打ち立てました。あなたがJavaの悩みを悩ましているのを見ているなら、それを見てください。プロパティから地図を作成するための

+1

実際にマップx = new Properties()はいずれの方法でも動作します。その人々はproperties.put( "flag"、Boolean.TRUE)のようなものを置く。私は人々があらゆる種類のデータをPropertiesオブジェクトに入れたが、決して非文字列のキーではないことを見てきた。 ;) –

+0

私は答えを更新しました。 –

+5

ちょっと待ってください! Map x = new Properties()はJava 5以降では有効ではありません。Java 5では構文が導入されました。 –

2

理由:Liskov substitution principleと下位互換性。 PropertiesHashtableを拡張するので、Hashtableが受け入れるすべてのメッセージを受け入れる必要があります - それはput(Object, Object)を受け入れることを意味します。 Genericsはtype erasureを介して下位互換性のある方法で実装されているため、Hashtable<String, String>の代わりにplain Hashtableを拡張する必要があります。コンパイラがその処理を完了したらジェネリックはありません。

+3

私はリスコフの置換原則はそれとは何かを持っているとは思いません。 Javaでは、クラスを継承するときにジェネリック型をうまく絞り込むことができます。そのため、の構文が存在します。 –

27

Propertiesは、実際にはHashtable<String,String>に拡張されることをもともと意図していました。残念ながら、ブリッジメソッドの実装は問題を引き起こしました。このように定義されたPropertiesは、javacに合成メソッドを生成させます。 Propertiesは、例えば、Stringを返すgetメソッドを定義する必要がありますが、Objectを返すメソッドをオーバーライドする必要があります。合成ブリッジメソッドが追加されました。

悪い古い1.4日間に書かれたクラスがあったとします。 Propertiesのメソッドをオーバーライドしました。しかし、あなたがしていないことは、新しい方法に優先されます。これは意図しない動作につながります。これらのブリッジ方法を回避するには、PropertiesHashtable<Object,Object>に拡張されています。同様にIterableは、SimpleIterableを返しません。これは、Collectionの実装にメソッドを追加したためです。

+2

良い説明。私もこれについて疑問に思っています。 –

13

ワンライナー(警告なしには2つのライナー):

@SuppressWarnings({ "unchecked", "rawtypes" }) 
Map<String, String> sysProps = new HashMap(System.getProperties()); 
+0

質問には答えません。しかし、最初に質問の原因となったものに答える。ポイントまでまっすぐ。 –

+1

"rawtypes"はここで必要ですか? (少なくとも私のIntelliJ IDEAでは、警告を抑止するには "未チェック"で十分です)。 – Jonik

関連する問題