Mr.Hack | ||
◆目次◆ ■前回の解答
Mr.Hackです。いかがお過ごしですか?少しずつ勉強も、仕事も、遊びも、Javaの勉強も調子に乗ってきましたか?まだまだ、5月病には早いですよ。がんばっていきましょうね。 皆さんががんばっているように、Mr.Hackもはれて、Computer Scienceのmaster's(修士課程)にacceptされました。Mr.Hackの学士が全くComputer Scienceと違っていたので、いきなりは入れてくれなかったのです。Undergraduateで修行してこい!ってことなのでしょうか。でもその甲斐あってか、GRE(日本での大学院版センター試験(共通一次?)みたいなもの)の点数が悪いにもかかわらずオッケーだったようです。アメリカでComputer Scienceを勉強してみたいと思っている人は、最初学部生として学び始めるのもいいとおもいますよ。授業内容は、結構高度ですから。
Question 2-1の答え class HelloWorld {String getMessage() {return "ハローワールド";} Question 2-2の答え
/** System.out.print("華氏(Fahrenheit)を入力せよ :
");
大事なところなのでもう一度確認しておきましょう。皆さんは、Question 2-1を発見できましたか? え?コンパイルしようとしたときにエラーがでたから発見できた? それでも、発見できたのですからすばらしい。でも、メルマガを見たときに発見できましたか。できなかった人は何故できなかったのでしょう? それは、プログラミングのライティングスタイルに問題があるからです。 class HelloWorld {String getMessage() {return "ハローワールド";} は、本来、 class HelloWorld {String getMessage() {return "ハローワールド";}} とあるべきですね。最後にカーリーブレイス(curly brace)が二つ。視野を広げてみないと、二番目のスタートである{String...は目に入ってきませんね。だから、見落としてしまったのです。コンパイルをせずに発見できなかった方は、ある意味Javaスタイルの大切さを実感して頂けたと思います。 じゃーどうすればいいの?万国共通の決まり事ってあるの? ありません。しかしながら、いいお手本はあります。"The element of Java style"に書いてある決まり事108条(vol.002、ちょっと珈琲ブレイク参照)です。この読者の皆さんが将来プログラムに携わる時にこの本を参考していくようになれば、それは慣習になります。決まり事になります。そして、他人のプログラムをみても素早く内容をとることができ、バグも発見しやすくなり、強いては、日本のプログラムディベロップメントに貢献するときがくるでしょう。 Question 2-2はどうでしたか?さて早速実行してみましょう。実行結果は、
となります。 さて、InputStreamReaderクラスとBurreredReaderクラスが出てきました。これは、java.ioパッケージの中のクラスです。これはどうやってわかったのでしょう?一つは、HelloWorldDemo3.javaの一行目に import java.io.*; とパッケージをインポート(import)しています。これが手がかりです。java.ioというパッケージの中に、InputStreamReaderクラスとBufferedReaderクラスがあるので、java.ioパッケージをインポートしたのです。*(スター)はioパッケージにある全てのクラスを全てインポートするという意味です。javaとioの間にある"."(ドット)は階層を示します。つまり、java.io.*は、javaフォルダ(ディレクトリ)以下にあるioフォルダの、そのioフォルダ以下あるクラスを全てインポートするという意味です。 java.io.*って小文字ですけど、大文字でもいいんですか? ここでは、ダメです。試しに大文字に変えて、コンパイルしてみてください。パッケージ java.IO は存在しません、とエラーメッセージがでます。でも、自分で作るときに、大文字でパッケージを作れば可能です。一般的には、packageは小文字にするのが慣習です。そのルールはどこからきたのでしょう?"The element of Java style"です。次号からいよいよスタートしますよ、『Javaスタイル職人への道』。 いまいち、このパッケージを理解できない方のために、実際にjava.ioパッケージを見てみましょう。Java SDK 1.3.1をインストールしたフォルダを開いてください。通常デフォルトでは、C:\jdk1.3.1_02になると思います。 C:\jdk1.3.1_02\jre\lib までエクスプローラーでフォルダをクリック(ダブルクリック)してたどっていきます。すると、libフォルダにrt.jarファイルがありますね?そのファイルをZip解凍(Lhaz等)で開けるように、jar拡張子を関連づけます。rt.jarファイル上で右クリックして、open with(日本語だとアプリケーションから開く?:WindowsXP)のサブメニューに、choose program(プログラムを選択?:WindowsXP)で、お使いのZip解凍ソフトを選択します。Always use the selected program to open this kind of file(いつもこのプログラムで開く?)を選択してOKを押すと、jarファイルをZip解凍ファイルで解凍できるようになります。この仕方が??の方は、ファイルの拡張子をjarからzipに変えてみてください。そうすれば、Zip解凍ソフトで開けます。 さて、解凍する準備はととのいました。お好きなところに解凍して下さい。解凍すると、解凍には結構時間がかかるので、息抜きに珈琲でもどうぞ。
Jarはジャーと読みます。正式名称はJava ARchive Fileです。これって何なんでしょう?実は、Zipファイル(圧縮フォーマットの一つ)の兄弟なんです。つまり、圧縮フォーマットなんですね。実体はZipファイルなので、拡張子をjarからzipに変えてあげるか、jarファイルにZip解凍ソフトを関連づけしてあげることによって、解凍できます。Zipファイルと違うところは、META-INFフォルダ以下にmanifest.mfファイルがある点です。このファイルには、ベンダーインフォメーションを記述したり、パッケージのメインクラスを指定して、release versionがわかるようにしたりします。例えば、manifest.mfファイルの中に、 Main-Class:com.mycompany.MyClass と指定し、MyClass.javaで package com.mycompany; public class MyClass { のように、main()メソッドでversion情報をプリントアウトするようにしておくと、MyClassを含めたmyjar.jarファイルと作ったときに、コマンド上で、 java -jar myjar.jar とタイプすることによって、このmyjar.jarのバージョン情報をプリントアウトすることができます。 jarファイルはまた、パッケージを提供したり、自分のapplicationに組み込んだりしたいときにそのjarファイルを自分のパッケージに入れることによってjarファイルのクラスを使うことができます。たとえば、jarファイル先をJBuilder等で指定して、 MyProject.javaクラスで、 import com.mycomany.MyClass; とインポート指定することによって、MyClassのメソッド等が使用できます。 これらは、後ほどJBuilderを使い慣れたときにまたふれていこうと思います。
com とあり、META_INF以外は全てパッケージです。javaフォルダをクリックしてください。javaフォルダ以下には、 applet がありますね。お!それです。ioとありますね。そのioフォルダをクリックしてください。その中に、ずらーーと93個ものクラスファイルがあります。これは、皆さんが最初Helloworld.javaをコンパイルしてクラスファイルを作ったのと同じbyte code形式のファイルです。その中から、InputStreamReader.classとBufferedReader.classを見つけられましたか?先ほどの import java.io.*によって、ioフォルダ以下にある93個のclassファイルをインポートしたわけです。解凍したフォルダ構造からわかるように、Java 2 Platform, Standard Edition のAPIの実体は、パッケージの集まりで、パッケージとは機能が似たもの同士でまとめたクラスということになります。 ところで、InputStreamReader.classとBufferedReader.classがio以下にあるってどうしてわかったでしょう?中級者の皆さんは、初心者の方からのこの問いにどうやって答えますか?んーーそれはね、長い経験と勘により・・・と答えますか?もし、 import java.io.*; を import java.io.InputStreamReader; としていたらどうですか?InputStreamReader.classとBufferedReader.classはio以下にあるclassだと一発でわかりますね。こう記述するのは、初心者の方のためだけに限りません。これは、大規模な開発になっていけば行くほど重要になってきます。一つのクラスに、標準のjava APIやサードパーティーが提供するAPIを使うケースがたくさん出てきます。そのときに、 import java.io.*; とすると、どこのクラスを使っているのかさっぱりわかりません。そのため、そのクラスの仕様を確認しようとするとき、よけいな時間と労力を費やすことになります。自分が書いたプログラムは自分だけが見るとは、限らないのです。上記より、 import java.io.IOException; と記述することによって、どのクラスを使用したか一目で確認できます。いままで悪い例として、 import java.io.*; と使っていましたが、以後は、使用するクラス名まで、記述してくださいね。 これからは、*(スター)は、いかなる時も禁止ですよ。 えークラスを探すのが面倒くさい?時間がかかる? 一時の手間が、あとで、多大の時間を節約してくれます。是非実行して下さいね。 いままでは、jarファイルを解凍して、その中のフォルダをたどって、InputStreamReader.classとBufferedReader.classを見つけました。しかし、これは、けっこう大変な作業の割に、そのクラスを見つけたとしても、何もいいことはありませんでしたね。classがどんな仕様になっているのか、メソッドがどんなものがあるのかもわかりませんでした。仕様を確認するには? そうです。GO TO APIでしたね。
APIとはApplication Programming Interfaceの略で、Javaクラスのセット(パッケージ(package)、C、C++的に言えばライブラリー(library))のことを言います。字面からいえば、ApplicationをProgramするのに必要なInterfaceを提供するもの、ということです。なんで、interfaceなんて言うんでしょう?Interfaceとはあるシステムの境界面をいいます。User
Interfaceといえば、システム(Application)を使う側のUserが、あるシステムの境界面(Interface、ウィンドウ形式であったり、コマンド形式であったりする)を通してシステム内部のプログラムとやりとり(住所録でいえば、新しく住所を入れたり、修正したり削除したりする)をすることをいいます。GUI(Graphical
User Interface)は、グラフィカルなウィンドウでマウスを使って、やりとりをすることをいいます。同じように、APIは、packageのJavaクラスとやりとりする境界面を提供するものなのです。APIでいうInterface(境界面)とは、クラス(Class)、インターフェイス(interface)、コンストラクター(constructor)です。それらを通して、その中身(たとえば、クラスのメソッド(method))を使用するのです。
ところで、BufferedReaderクラスとInputStreamReaderクラスは何をするクラスなのでしょう?
APIでSystemクラスに行ってください。Systemクラスのフィールドの概要を見るとSystem.inとあります。その左側には、戻り値がInputStreamだとなっています。クラスのオブジェクトの時は、戻り値という表現よりも、参照(refer)していると考えた方がわかりやすいと思います。。例えば、 InputStream myStream = System.in; というのは、System.inが何か値を戻す(返す)と考えるのではなくて、myStreamという参照変数がInputStreamのオブジェクトを参照していると考えるのです。前回、newはメモリーを確保すると言いました。今回はnewは使いませんが、すでに、Systemクラスの中ですでに、InputStream in = new InputStream()というメモリー確保(オブジェクト生成)がすでにあって、 InputStream myStream = in; のように、in参照変数が指しているオブジェクト(メモリースペース)をmyStream参照変数が参照すると考えるのです。 InputStreamクラスのオブジェクトはどういう役割をしているのでしょうか? キーボード ---------→ コンピューター InputStreamオブジェクトはキーボードからコンピューターに向かっている川(線)の流れだと思ってください。その川の上をユーザーによってキーボード上から入力された文字が次々の流れて行きます。それを、InputStreamクラスのread()メソッドによって、一文字づつ(byte)順番にすくい上げます。 System.in.read(); でバイト単位(byte)の文字を得ることができます。しかしながら、1byte(=8bits)は半角一文字(たとえば、A)なのでUnicodeである日本語の全角(16bits)は読めません。それを、Unicodeが読めるようにキャラクタ単位(char)ごとに川からすくえるようにしたのが、InputStreamReaderクラスです。このクラスはバイトストリーム(byte stream)からキャラクタストリーム(char stream)に変換してくれます。川の例で言えば、半角文字を二つ分すくえるようになったのです。InputStreamオブジェクトが片手で半角一文字づつすくい上げるとすると、InputStreamReaderオブジェクトは、両手で2倍分の文字をすくい上げることができます。InputStreamReaderクラスもread()メソッドがあるので、 InputStreamReader myStreamReader = new InputStreamReader(System.in); でキャラクタを一文字づつ得ることができます。 しかしながら、これでは、長い文字列を読むとき毎回毎回、read()メソッドを適用してキャラクタを一文字一文字読み込んで行かないといけませんね。そこで登場するのがBufferedReaderクラスです。これは、一文字一文字をバッファー(buffer)に蓄えて一度に大量に読み込んで行くことができます。川の例でたとえれば、片手でもなく、両手でもなく、川の流れから、網でドバッとすくい上げる感じです。その網でドバッとすくい上げた中から、readLine()をつかって一行分読み込みます。 BufferedReader myBufferedReader = new BufferedReader(myStreamReader); そして、最後に川の流れを止めてあげないと水が流れっぱなしになってしまいますね。close()メソッドを使って川の流れを止めて(閉じて)あげます。 myBufferedReader.close();
BufferedReader myBufferedReader = new BufferedReader(
最後に、String型から、double型への変換(キャスト)を見てみましょう。今までの課程でキーボードから打った文字列はString
型になりました。しかし四則演算するには、String型ではできません。String型の"72.0"とdobule型の72.0は違うのです。キャストには、DoubleクラスのparseDouble()メソッドを使います。APIのDoubleクラスのparseDouble()メソッドを見てください。パラメータとしてString型、戻り値としてdouble型を返却します。つまり、String型からdouble型へキャストできるのです。これで、やっと、四則演算できます。その値を ところで、宿題に取り組まれた方の中には、parseDouble()メソッドとvalueOf()メソッドはどう違うんだろうと思われた方がいるかもしれません。でも、よく見てください。valueOf()メソッドは戻り値はDouble型です。大文字で始まる表記はクラスでしたね。そう、Doubleというクラスなのです。そのため、Double型なのです。 それじゃー、double型は? double型はプリミティブ型といってクラスではありません。ある意味オブジェクト指向言語には似つかわしくないプリミティブ型です。なんでこんなプリミティブ型があるのでしょう。それは、やはり、四則演算・文字の取り扱い・Expressionという頻繁に扱うものは、クラスで武装するよりも手間暇かからず都合がいいからだと思います。 プリミティブ型である、byte、short、int、long、float、double、char、booleanにはすべて、クラスがあります。しかしながら、intとcharだけは、ただ始まりを大文字にするだけではなく、Integer、Characterとします。なぜでしょう?クラス名は省略しないようにするのがjavaの慣習だからです。int、charはC,C++等でも同じ表記ですので、他の言語も意識した互換性だと思います。 byte - Byte ところで、Doubleとクラスでdouble型をラップする(wrap、包み込む)によって、何がいいのでしょう?一つの理由として、クラス武装することによって、他のクラスで使えるようになります。doubleという裸では相手にしてくれないのです。 Stack stack = new Stack() stack.push(new Double(2.0)); というように、プリミティブ型の2.0、3.0、4.0をDoubleクラスでラップして(包み込んで)あげてから、stackにプッシュして(いれて)あげます。 さて、一通り、説明しましたが、質問等があれば、掲示板の方に投稿してください。皆さんからのフィードバックがこのメルマガをよりよいものにしていけると思います。難しい、簡単何でも結構です。 さて、今週の宿題です。
上記のConvertToCelsius1.javaをコンパイルし実行した後、何も入力せずにEnterキーを押しなさい。 Exception in thread "main" java.lang.NumberFormatException:
empty String ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ヒント ConvertToCelsius1.javaプログラムは、アメリカに行ったあなたが、友達のために作ったプログラムでしたね。72といれれば、うまく、22.222...Fと計算してくれました。友達もこれで天気予報がわかると大喜びです。しかし、たまたま、何も入力せずにEnterキーを押したら、上記の例外が発生してびっくりです。あなたも、思っていなかった自体にびっくりです。そこで、すぐに修正すると友達に約束し、プログラミングを始めます・・・。 APIのDoubleクラスのparseDouble()メソッドをクリックすると、 例外: という記述があります。空文字を入力した時に発生する例外をキャッチしてあげれば良さそうです。 例外をキャッチするには、try & catch構文を用いて try { でできます。上記で"例外を発生させる文"が例外を発生させた時だけ、catch構文は実行されます。つまり、例外が発生しなかった場合は、 System.out.println("例外が発生しました"); は実行されません。これをつかって、上記の訳のわからない例外メッセージを防いでみてください。
Mr.Hack ■ちょっと珈琲ブレイク ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||
© 2002 MR.HACK ALL RIGHTS RESERVED |