可変長パラメータと配列パラメータの互換性 [Java]
たとえば、次のAクラスとBクラスを見てみてください。
class A { void f(Object... o) { } void g(Object[] o) { } } class B extends A { void f(Object[] o) { } void g(Object... o) { } }
JDK 5.0では、これらのクラスをコンパイルすると警告メッセージが出ていました。しかし、Java 6では、警告メッセージは何も出ることなくコンパイルされるようになっているようです。JDK5.0がリリースされた時点では、将来はコンパイルエラーされる可能性も考えられていましたが、Java 6では警告は何も出ないようになっているので、将来コンパイルエラーとされる可能性はほとんどないでしょう。
しかし、警告が出なくても、やはり、どちらのオーバーライドも好ましくないでしょう。
class Test { public static void main(String[] args) { B b = new B(); A a = b; a.f(1, 2, 3); b.f(1, 2, 3); b.g(1, 2, 3); a.g(1, 2, 3); } }
この
Test
クラスをコンパイルすると次のようにエラーとなります。Test.java:10: g(java.lang.Object[]) (A 内) を (int,int,int) に適用できません a.g(1, 2, 3); ^ エラー 1 個
B
クラスのf
メソッドは、可変長パラメータと同じように呼び出せています。g
メソッドの場合には、参照の型によって、スーパークラスは配列パラメータ、サブクラスは可変長パラメータと見なされていることになります。[追記: 2009年5月2日]
一部訂正ブログを書いていますので、そちらも参照してください。
アノテーションの互換性 [Java]
実行時に存在するアノテーション型は、調べられようとしているクラスにアノテーションを付けるのに使用されたアノテーション型と異なる可能性がありますので、その型の2つの使われ方には互換性がない可能性があります。もし、互換性がない場合に、アノテーションの要素へアクセスしようとすると、AnnotationTypeMismatchException
あるいはIncompleteAnnotationException
がスローされます。もし、要素型がenumであり、アノテーション内のenum定数がそのenumに存在しなくなっていれば、EnumConstantNotPresentException
がスローされます。
この説明によれば、アノテーションは、互換性がある方法で変更することが可能だということになります。互換性を保ちながらアノテーションを変更できるという意味で、『Effective Java 第2版』には、次のように述べられています(174頁の最後の段落)。
マーカーインタフェースに優るマーカーアノテーションの主な長所は、デフォルトを持つアノテーション型要素を1つ以上追加することで、すでに使用された後でもアノテーション型に情報を追加できることです [JLS, 9.6]。単なるマーカーアノテーション型として始まっても、時間の経過に伴い機能が豊富なアノテーション型へ発展できます。そのような発展は、マーカーインタフェースでは不可能です。なぜなら、一旦実装された後に、インタフェースにメソッドを追加することは一般に不可能だからです。
つまり、既存のアノテーション型の定義に新たな要素を追加する場合には、デフォルトを指定すれば互換性を保ちながら変更が可能だということです。
実際に、既存のアノテーション型にデフォルトを持たない要素を追加した場合には、そのアノテーション型でアノテーションを付けられているコードを再コンパイルするとエラーになります。なぜならば、新たな要素の値が指定されていないからです。しかし、再コンパイルされない場合に、リフレクションによりその新たな要素の値を読み出そうとすると、IncompleteAnnotationException
がスローされます。
既存のアノテーション型の特定の要素の型を変更した場合には、そのアノテーション型でアノテーションを付けられているコードを再コンパイルするとエラーになったり、ならなかったりします。たとえば、元の要素の型がString
であったのををint
にすればコンパイルエラーとなります。一方、元の要素の型がString
であったのを配列String[]
に変更した場合には再コンパイルできます。なぜならば、要素の値が少なくとも1つはすでに指定してあるからです。しかし、どちらの場合でも、古いアノテーション型でアノテーションが付けられているコードを再コンパイルすることなく、そのアノテーションの要素の値をリフレクションにより読み出そうとするとAnnotationTypeMismatchException
がスローされます。
Java言語のアノテーションについてはきちんと学びたい方は、『プログラミング言語Java第4版』の第15章「アノテーション」と16.2節「アノテーションの問い合わせ」、および、拙著『Java 2 Standard Edition 5.0 Tiger―拡張された言語仕様について』の第7章「アノテーション」と8.1節「リフレクションAPI」を読まれることをお勧めします。
Top Java Developers Offer Advice to Students [Java]
Top Java Developers Offer Advice to Students
Java言語のenum型 [Java]
12月27日(土)にJava読書会へ参加したあと、青葉台のブックファーストで初心者向けのJavaの書籍をそこにあるだけチェックしたのですが、enum型に関しては、C/C++言語のenumと同じような機能部分だけをあっさりと説明している書籍ばかりでした。
『Effective Java プログラミング言語ガイド』で説明されていたタイプセーフenumから発展して導入されたenum型は、かなり強力なのですが、その強力な点はほとんど説明されていませんでした。
『プログラミング言語Java第4版』(2007年4月発売)では、第6章「列挙型」として9ページを費やして解説されていますし、拙著『Java 2 Standard Edition 5.0 Tiger―拡張された言語仕様について』(2005年5月発売)でも第4章「enum型」として15ページを費やして解説しています。
enum定数とシリアライズ [Java]
readResolve
よりenum
型を選ぶ」と独立した項目も書かれています。項目77のp.300には次のようにも述べられています。
enumとしてシリアライズ可能なインスタンス制御されたクラスを書くのであれば、宣言された定数の他にインスタンスが存在しないという完全な保証を得ます。JVMがその保証を行いますし、みなさんはそれに頼ることができます。みなさんの方で特別なことは必要ありません。
シリアライズに関しては、enumは特別に扱われます。それに関しては、拙著『Java 2 Standard Edition 5.0 Tiger 拡張された言語仕様』の4.7節「
enum
定数のシリアライズ」で説明しています。Java 2 Standard Edition 5.0 Tiger―拡張された言語仕様について
- 作者: 柴田 芳樹
- 出版社/メーカー: ピアソンエデュケーション
- 発売日: 2005/04
- メディア: 単行本
4.7節は短いので、その全文は以下の通りです。
java.lang.Enum
クラスは、Serializable
インタフェースを実装していますが、readResolve
メソッドは定義されていません。従来のタイプセーフenumでは、readResolve
メソッドを実装しなければ、正しくディシリアライズできませんでした。
リリース5.0からは、シリアライズ/ディシリアライズの仕様が変更になっており、enum
定数は特別に処理されるようになっています。enum
定数をシリアライズする場合には、name
フィールドだけがシリアライズされます。他のフィールドは一切シリアライズされません。そして、ディシリアライズでは、name
フィールドの値を用いて、Enum.valueOf
メソッドを使用して値オブジェクトを取得するようになります。
enum
型の宣言で、シリアライズ/ディシリアライズのためのカスタマイズ用メソッド(writeObject
、readObject
、readObjectNoData
、writeReplace
、readResolve
)を定義しても、すべて無視されます。同様に、serialPersistentFields
とserialVersionUID
もすべて無視され、serialVersionUID
は、常に0L
となります。
拙著ではリリース1.5で導入された言語仕様に関する制限事項や、どのように実装されているかについて説明しています。ただし、私自身の用語に対する勘違いなどの誤りがありますので、参考にされる際には、正誤表も参照をお願いします。
『Java 2 Standard Edition 5.0 Tiger』正誤表
http://www001.upp.so-net.ne.jp/yshibata/tigererrata.html
第8期「プログラミング言語Java」教育終了 [Java]
最終回は成果発表会で主に一年間を振り返って各人に発表してもらいます。多くの受講生が述べていましたが、もし独学で書籍『プログラミング言語Java第4版』と『Effective Java第2版』を読もうとしていたら、途中で挫折していただろうと。
Java言語によるソフトウェア開発に従事しているソフトウェアエンジニアには、書籍『プログラミング言語Java第4版』と『Effective Java第2版』の両方を最低でも学習してもらいたいところです。しかし、初心者には難しいため、実際に両方を全部読んで理解している人は、非常に少ないのではないかと思います。
その意味で、現在はグループ関連会社に限定していますが、多くのソフトウェアエンジニアを育成する意味で、来年度はグループ関連会社外に対しても、機会があれば実施してみたいと思っています。
Bug Id: 6783209 [Java]
プログラミング言語Java (The Java Series)
- 作者: ケン・アーノルド
- 出版社/メーカー: ピアソンエデュケーション
- 発売日: 2007/04
- メディア: 単行本
『プログラミング言語Java第4版』の551頁に
Formatter
クラスの説明で%%
に関して、以下のような記述があります。2 つの特別な変換を手短に説明します。最初の変換は、%
を出力するのに使用される%
変換です。%
文字 はフォーマット指定子の開始を示しますので、出力に実際に%
文字が含まれるようにする方法が必要です。 フォーマット指定子%%
は、それを行います(単一文字\を生成するのに、エスケープ文字\\が使用されるのと同じです)。出力に空白を埋めるためにこの変換と一緒に幅を指定できます。フラグが指定されなければ左に 空白を埋め、-
フラグが左寄せのために指定されていたら右に空白を埋めます。
これは、もともと
Formatter
クラスの仕様を元に記述されているのですが、実は、これは正しく動作しません。社内で行っている「プログラミング言語Java」教育で、この部分のテストコードを書いたが期待通りに動作しないと質問があり、私自身も簡単なテストコードを書いて確認しました。やはり、上手く動作しないので、先日不具合であると報告したので、Bug Databaseに登録されました。http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6783209
リリース1.5の初めからバグだった訳ですから、長い間、誰も報告しなかったようです。
『Effective Java 第2版』届きました [Java]
土曜日の午前中に、出版社から『Effective Java 第2版』が(翻訳契約に含まれる)5冊届きました。Amazonの発売予定日は、11月27日になっていますが、おそらく次の三連休中には書店によっては並ぶのではないかと思います。
英語版が今年5月のJavaOneで先行発売されてから、約半年後に日本語版を出すことができました。初版と同様に、翻訳版に関しては日本語版が最初に出版されたのではないかと思っています(出版社に確認していませんが・・・)。
英語版での第3刷(third printing)までに見つかった誤りは、日本語版では修正されています。また、本文を補足するための「訳注」も10個ほど新規に追加しています。しかし、やはり、初心者には内容的に難しいかもしれません。時間があれば、「Effective Java 第2版を読む」と題したブログを書いていきたいと考えています(本当に書けるかは約束はできませんが・・・)。
初版を手にとって読み始めた時にはJoshua Blochの名前も知りませんでした。しかし、初版の翻訳を通して、電子メールのやり取りをして、2002年の12月に初めて会って(拙著『プログラマー現役続行』のp.48の写真)以来、何度か会って話をしています。
彼の著書である『Effective Java』の初版、第2版、それに、『Java Puzzlers 罠、落とし穴、コーナーケース』を翻訳することで、私自身は多くの事柄を学びました。第2版を日本の多くのソフトウェアエンジニアが読まれて、日本のソフトウェア業界のレベルアップに多少なりとも結びつけばと思っています。
『Effective Java 第2版』 Amazon.co.jpで予約可能 [Java]
Amazon.co.jpで予約注文できるようになりました。また、出版社のホームページにも紹介されています。
出版社紹介ページ