- PR -

JDKバージョン互換の落とし穴(旧件名:Colorクラスの落とし穴)

投稿者投稿内容
maru
ぬし
会議室デビュー日: 2003/01/27
投稿数: 412
投稿日時: 2003-03-01 11:31
いつもお世話になっています。
よく使うColorクラスを使っているときに思わぬ落とし穴にはまりました。
参考になればと思って書かせていただきました。

Colorクラスで色指定するのに用意されている定数(Color.BLACKやColor.WHITEなど)を
使うことがあります。
javaでの定数は大文字アルファベットで宣言されています(思い込みかもしれませんが)

Color.BLACKなど JDK1.4では問題なく動きますが、JDK1.2(1.3?)以前では動きません。
JDK1.2ではColorクラスの定数はなぜか Color.black のように小文字で宣言されていま
した。JDK1.4では大文字、小文字両方で宣言されています。
従いまして、「Colorクラスなどは昔からあるし定数は大文字で宣言されているもの」との
思い込みでソースを書くと古いJDKでは動かないこともありそうです。
ほかにも同様の問題のクラスがありそうですね。

#追記(2003/3/19)
javaを本格的に使い始めて3ヶ月ほどたちましたが、javaって結構こういうの多いですね?
同じプラットフォームのjavaでもこういう問題がおおいとなると、「「Write Once,
Run Anywhere」はやっぱり難しいのでしょうね。
言語として登場して約7,8年です(もうそんなにたってんの?)が、API周りはまだまだ発展
途上なんでしょうかね?
また、似たような問題があれば参考までにこのスレッドに追記させていただきます。
そのために件名を変更しました。


[ メッセージ編集済み 編集者: maru 編集日時 2003-03-19 11:47 ]
unibon
ぬし
会議室デビュー日: 2002/08/22
投稿数: 1532
お住まい・勤務地: 美人谷        良回答(20pt)
投稿日時: 2003-03-18 16:15
unibon です。こんにちわ。

引用:

maruさんの書き込み (2003-03-01 11:31) より:

ほかにも同様の問題のクラスがありそうですね。


おくればせながら、似たものを2点書きます。

(1) 1.4 で親切に(?)新設された StringBuffer.append(StringBuffer) の問題

たとえば、

StringBuffer a = new StringBuffer();
StringBuffer b = new StringBuffer();
a.append(b);

のようなコードを書いていた場合、1.4 では新たに、
http://java.sun.com/j2se/1.4/ja/docs/ja/api/java/lang/StringBuffer.html#append(java.lang.StringBuffer)
が新設されているので、コンパイル時にこのメソッドが使われます。
また、同じコードを 1.3 でコンパイルすると、
http://java.sun.com/j2se/1.3/ja/docs/ja/api/java/lang/StringBuffer.html#append(java.lang.Object)
が使われます。
したがって 1.4 でコンパイルしたものを 1.3 で動かすと、
NoSuchMethodError になってしまいます。
これがいやらしいのは、同じコードのままで
1.3 でもコンパイルはできて 1.3 でも 1.4 でも動いてしまうことです。


(2) JDialog.setLocationRelativeTo(Component) が Window クラスに移動

1.3 では、JDialog クラスにあった setLocationRelativeTo メソッド、
http://java.sun.com/j2se/1.3/ja/docs/ja/api/javax/swing/JDialog.html#setLocationRelativeTo(java.awt.Component)
が、1.4 では Window クラス、
http://java.sun.com/j2se/1.4/ja/docs/ja/api/java/awt/Window.html#setLocationRelativeTo(java.awt.Component)
に移動したようです。
したがって、たとえば、

JDialog d = new JDialog(〜);
d.setLocationRelativeTo(〜);

のようなコードを 1.4 でコンパイルして 1.3 で動かすと
NoSuchMethodError が発生します。
たむ
会議室デビュー日: 2003/01/14
投稿数: 5
投稿日時: 2003-03-19 17:18
こんにちは。
JDK1.4でまだ開発したことがないので、Color.BLACK等、大文字が使
えるとは知りませんでした(^^;

昔からJavaはバイナリーやソースレベルでの上位互換性は維持努力し
てるようですが、下位互換性は保証してませんよね?元々そのような
前提だと考えていたので、JDKをバージョンアップするタイミングに
ついては、気を付けています。

maruさんがJavaを使い始めて3ヶ月程とのことなのでこの様な問題に
直面されたと考えますが、「下位互換性はあてにしない」事が、精
神的に楽かなー、と思っています

参考:旧バージョンとの互換性に関するページ
http://java.sun.com/j2se/1.4.1/ja/compatibility.html
maru
ぬし
会議室デビュー日: 2003/01/27
投稿数: 412
投稿日時: 2003-03-20 00:55
こんばんは。

>「下位互換性はあてにしない」事が、精神的に楽
そうですね。バージョンが進むにつれ、APIも強化(追加)されているので、私も下位互換
はあてにしていなかったのですが、今回はColorクラスの色の定数のように、昔からあって
よく使って、まさか変更があるとは思えないものまで、変更があった(つまずいた)こと
について驚いた次第です。

たかだかマイナーバージョンアップでも、ここまで互換性が捨てられている(保証されて
いない)となると、ちと厳しいですねぇ。いままで(VBやDelphiでの開発)以上に
プラットフォームの実行環境(JDKのバージョン)について気をつける必要が有りそう
かな?
たむ
会議室デビュー日: 2003/01/14
投稿数: 5
投稿日時: 2003-03-20 18:43
こんにちは。

引用:

maruさんの書き込み (2003-03-20 00:55) より:
>今回はColorクラスの色の定数のように、昔からあって
よく使って、まさか変更があるとは思えないものまで、変更があった


とありますが、1.4のソースを見ると、例えば、昔からあるColor.whiteの定義も存在してます。Color.WHITE = Color.white となってますね。このColorクラスに限定して言えば、「昔から存在するJavaプログラム」は、1.4でも動作する様になっており、大きな問題にはなりません。

maruさんが、JDK1.4で作成したJavaプログラムをJDK1.2や1.3環境でソースのコンパイル、または実行しようとされたキッカケについては判りませんが、私の感覚では、ターゲットとするプラットフォームのJava実行環境のバージョンにJDKのバージョンを合わせる、逆に言えば、ターゲットとするプラットフォームのJava実行環境のバージョンは開発しているJDKのバージョンに合わせておくことが重要ではないかと思っています。

例えばお客様のコンピュータのJava実行環境のバージョンをこちらがコントロールできないケースでは、上位互換性を期待して、JDKの低いバージョンを使うことがあります。

「Write Once, Run Anywhere」のお話をこの件に適用するのは、ちょっと酷かなー思うのですが(^^;

maruさんが仰っている事が、これからJavaを勉強を始めようとされている方が、最新のJDK1.4を用いた(JDK1.4をベースにした参考書や開発環境を使う場合等も)場合、この様な問題に直面することがあるので注意しましょう、ということであれば理解できます

[ メッセージ編集済み 編集者: たむ 編集日時 2003-03-20 18:44 ]
maru
ぬし
会議室デビュー日: 2003/01/27
投稿数: 412
投稿日時: 2003-03-21 11:27
こんにちは。

そもそも、このスレッドを書いたのは、決して互換性がないと問題視してつっこみ
をいれようと思ったのではなく、初めの文書の締めくくりにも書いてますように、

「○○のAPIは昔からあるし定数は大文字で宣言されているから動くだろう」との「思い込
み」でソースを書くと古いJDKでは動かないこともありそう」ということで気をつけた方が
いいかな?と、参考になればと思い書かせてもらっただけです。誤解のないように(^^;

で、unibonさんが追記されたことで、「へ〜、こんなこともあるんだ」と思って、元の件名
ではColorクラスに限った内容なので件名を変更したまでで、互換性がないと問題視して
つっこみをいれようと思ったのではありませんので、誤解のないように(^^;

私は、今までの(たくさん痛い目にあった(^^;)経験上、開発環境や客先の実行環境のバー
ジョンにはこと細かく気にするタイプでして、今回のものも納品するものについては当然実
行保証バージョンを設定していました。

今回作ったプログラム(といっても納品のものでなく簡単なテストプログラムみたいなもの
ですが)がアプレットで動くもので、APIの参考にした資料(サンプルソース)がJDK1.4
(というか特に明記無し)のものだったようで、使っているAPIは昔からある「はず」、
「API(クラス)互換はなくとも中間コードの互換はある」とJDK1.4でコンパイルし
たものを、数種類のブラウザでJDKバージョンを気にせず(といってもすべてJDK1.2
以上というのは知っていてこれぐらいなら動く「はず」と思い込み)に動かしてみて、
動かないブラウザがでたので少し悩んだのでした。

同じようなプログラムでも、たまたまあるOSのブラウザ上のアプレットではNGだが、
そのOSのJavaアプリではOKだったということもあって、余計に混乱しましたが、同一
OS上でも普段使っているJDK(1.4)とちょっと前に手動でセットアップしたブラウザの
Pulg-inのバージョン(1.2)が食い違っているのがわかりました。

コンパイラのバージョンを落としていくと、コンパイルできないバージョンが出てきたの
で、双方のバージョンのAPIのヘルプを見くらべると、違いがあることにわかったのです。
※けど、見落としかもしれませんけどColorのメソッドについては「導入されたバージョ
ン」がかかれているけど、定数に関しては変更があったとは見当たらなかったことも少し
悩んだ。見比べてわかった。

結果的にはちょっとした問題ですが、こういった遠回りのいきさつがあって、参考になれば
(気をつければきりがないのでなんかあった場合に頭の片隅にでもあれば)とおもい書いた
のでした。

「Write Once, Run Anywhere」については、あてにはしていませんが、若干の期待とjava
を使ってみて上記のようなレベルでの現実とでちょっと感想を書いたもので、あまり深い意
味はありません。
これについて話を広げるつもりはありませんし、これについてはいろんな考え方や見方が
あると思うので、話を広げようとすると、おそらく収拾つかなくなると思うので(^^;


[ メッセージ編集済み 編集者: maru 編集日時 2003-03-21 12:08 ]
unibon
ぬし
会議室デビュー日: 2002/08/22
投稿数: 1532
お住まい・勤務地: 美人谷        良回答(20pt)
投稿日時: 2003-03-24 09:55
unibon です。こんにちわ。

引用:

たむさんの書き込み (2003-03-19 17:18) より:

参考:旧バージョンとの互換性に関するページ
http://java.sun.com/j2se/1.4.1/ja/compatibility.html


このページは差分情報(1.3 と 1.4 の差、あるいは 1.2 と 1.3 の差)のみ
記載しているらしいので注意が必要ですね。
#1.1 と 1.2 の差はリンクが切れていますね。

また、最初の話題の Color クラスですが、
API リファレンスである、
http://java.sun.com/j2se/1.4/ja/docs/ja/api/java/awt/Color.html
や、あるいは Color クラスのソースコードを見ても、
@since に相当するバージョン情報の記述がないことも混乱(?)の一因だと思います。

API リファレンスやソースコードを見ても、API の対象バージョンが分からないということは、
新しい開発環境で古い実行環境をターゲットとした開発はできない、ということになります。
実際、Sun の JDK のリリースのバージョン管理は、
古いものはなるべく使わせないようにしているようですが。

また、上記の互換性に関するページ内では、大別すると、
・バイナリ互換性
・ソース互換性
の2つについて触れています。
バイナリ互換性は、クラスファイルのフォーマット関連で
具体的には javac の -target オプション相当を指していると思います。
ソース互換性は、API の有無については触れているのですが、
私が前回書いたようなメソッドのオーバライドの点について触れられていないのが
不親切のような感じがします。
すなわち、このページを読んだだけだと、ああ、新しい JDK を使っても、
-target オプションを付けて、@since タグの有無に気をつければ大丈夫だな、
と思い込んでしまうのです(私がそうでした)。
#@since タグに対する過剰な期待?
unibon
ぬし
会議室デビュー日: 2002/08/22
投稿数: 1532
お住まい・勤務地: 美人谷        良回答(20pt)
投稿日時: 2003-05-29 12:51
unibon です。こんにちわ。

古い話題ですが、たまたま互換性に関して新たに気づいたケースがあったので、
備忘録代わりに書かせていただきます。
たとえば、次のようなコードをコンパイルして実行します。

--- VectorTester.java ---
コード:
import java.util.Vector;

public class VectorTester {

    public static void main(String[] args) {
        Vector a = new Vector();
        a.addElement("foo");
        Vector b = new Vector();
        b.addElement("foo");
        boolean e = a.equals(b);
        System.out.println("equals = " + e);
    }
}


コンパイルはどのバージョンでも関係ないのですが、
実行時のバージョンが 1.2 未満か 1.2 以上かで結果が異なります。
1.2 未満の場合は false が表示され、
1.2 以上の場合は true が表示されます。
そうなる理由は、
http://java.sun.com/products/jdk/1.2/ja/compatibility.html#api
の中の「バージョン 1.2 における API の非互換性」の 7. 番目の項目に書かれています。
(Vector クラスの equals メソッドの仕様が変わったため)

このケースは、実行時に落ちなくて(実行時例外がスローされず)、
実行結果が異なる、というのがいやらしいです。
上位互換性がないことになります。
ただ、結局はライブラリの互換性の話なので、
アプリケーションの世界では良くあることだとは思いますが、
でも、なんだか釈然としないです。

スキルアップ/キャリアアップ(JOB@IT)