Java の概要
この節では、Java 構文の基本的な規則について説明し、WebLogic Workshop の開発者に役立つ Java の概念を簡単に紹介します。C、C++、Visual Basic のような他の高水準プログラミング言語や JavaScript の知識があれば、Java をすぐに習得するのに支障はありません。Java についてさらに詳しい解説が必要な方には、良質の書籍や講座が多数あります。
以下の節では、基本的な Java の構文について説明します。
Java では、変数を使用する前に、変数の名前と型を指定して宣言する必要があります。必要なときに変数をただ使用するのに比べて、あらかじめ行う作業が多いように感じられますが、この手間をかけるとコンパイラが型の制限をチェックできるので効果的です。後でデバッグにかかる時間を節約することができます。
たとえば、整数を格納する新しい変数は、次のように宣言できます。
int x;
テキスト文字列を格納する新しい変数は、次のように宣言します。
String strName;
変数を宣言したら、変数に値を割り当てられます。
x = 5;
または
strName = "Carl";
上の変数のようにプレフィックス str を付けると、String 型の変数であることを開発者が覚えやすくなります。
Java では、ほとんどの種類の基本データを扱う複数のプリミティブ型を用意しています。プリミティブ型は以下のとおりです。
boolean
byte
char
double
float
int
long
short
Java では、プリミティブ型を使用して基本的な値を扱い、Java オブジェクトを使用してより複雑なデータを格納します。すべての Java オブジェクトは基本の Object クラスから派生しています。クラスとはオブジェクトを作成するためのテンプレートです。クラスをクッキーの抜き型とすると、クラスから作成されるオブジェクトはクッキーと考えることができます。
プリミティブ型とオブジェクトの違いを覚えておくことは重要です。同じように整数値を格納する場合でも、Integer オブジェクトと int は異なります。一方を引数として受け取るメソッドは、特別に定義されていない限り、もう一方を引数には取りません。また、Java オブジェクトは処理に使われるメソッドを常に持っていますが、プリミティブ型はメソッドを持ちません。
Java では、プリミティブ型のメモリ サイズが明確に定義されています。たとえば、int の値は常に 32 ビットです。
Java のヒント : オブジェクトの集合(リスト、ツリー、配列など)を格納および管理する便利な Java クラスの多くは、プリミティブ型を操作できません。プリミティブ型は Java Object クラスから派生していないためです。ただし、Java にはプリミティブ型のためのラッパー クラスがあり、それを使用して一時的にオブジェクトを作成できます。作成したオブジェクトは目的の処理に使用できます。ラッパー クラスの名前はプリミティブ型の名前と似ていますが、最初の文字が大文字になっています。
Boolean
Byte
Char
Double
Float
Integer
Long
Short
次に示す Integer と int の場合のように、プリミティブ値からラッパー クラス オブジェクトを作成するのは簡単です。
int myInt;
Integer myInteger = new Integer(myInt);
プリミティブ値は次のようにラッパー オブジェクトから取得できます。
myInt = myInteger.intValue();
文とは、論理的な 1 行のコードです。文では変数に値を割り当てたり、関数を呼び出したりします。文は Java プログラムの基本的な構成要素です。たとえば、次の文では変数 x に値 5 を割り当てています。
x = 5;
次の文では関数を呼び出します。
calculateIT(x);
上記のように、文はセミコロンで終了します。この規則の例外として、コードの新しいブロック(中括弧({})で囲まれたコードの部分)を開始する文があります。
中括弧({})は次のようにブロックを囲むために使用します。
for( i=0; i< 100; i++) { <one or more statements> }
改行の位置は重要ではありません。次の例は上記の例と論理的に同じです。
for(i=0; i<100; i++) { <one or more statements> }
ただし、大抵のプログラマは、後者の例は読みにくいのでよくない書き方と考えるでしょう。
ブロックは一連の文をグループにまとめます。上の例では、ブロック内のすべての文が for ループの一部として順番に実行されることを示しています。
以下の節では、Java コードを記述するために知っておく必要のある演算子について説明します。
Java でオブジェクトを使用するには、2 段階のプロセスに従う必要があります。最初に、名前と型を指定してオブジェクト変数を宣言し、次に、オブジェクトのクラスの新しいインスタンスを作成しなければなりません。2 番目の手順では、新しいオブジェクトがメモリ内に作成され、宣言した変数に割り当てられます。クラスの新しいインスタンスを作成するには、クラス コンストラクタと共に、new キーワードを使用します。
Java クラスには常に 1 つまたは複数のコンストラクタがあります。コンストラクタは、クラスの新しいインスタンスを返すメソッドです。すべての Java クラスは、引数を取らない基本のコンストラクタ メソッドを提供します。以下の例を見てみましょう。
class MyClass { int firstElement; float secondElement; } MyClass myClassInstance; // at this point, myClassInstance is null myClassInstance = new MyClass(); // now myClassInstance refers to an object
Java クラスには複数の引数を取るコンストラクタ メソッドもありますが、通常それはオブジェクトを使用するプログラマに便利なように提供されるものです。オブジェクトへのデータの格納方法に基づいて、どのコンストラクタを使用するかを決定します。
. (ドット)演算子は、情報へのアクセスまたはオブジェクトのメソッドの呼び出しに使用されます。たとえば、上記のようなクラス定義と変数宣言がある場合、myClassInstance オブジェクトのメンバーには以下のようにアクセスします。
myClassInstance.firstElement = 1; myClassInstance.secondElement = 5.0f;
Java では、整数の配列のインデックスによって配列にアクセスします。配列のインデックスはゼロ(0)で始まります。配列の各要素へは、[] (配列)演算子を使用するインデックスによってアクセスできます。
たとえば、6 つの名前の配列を格納するには、次のような配列を宣言できます。
String strNames[5];
次に、適当な値を割り当てることによって、配列の最初の要素に値を設定できます。
strNames[0] = "Carl";
以下の節では、コレクションとイテレータについて説明します。
Java ではコレクション クラスと呼ばれる一連のクラスを定義しています。これらのクラスは java.util パッケージで定義されています(詳細については、後述のパッケージを参照)。最もよく使用されるコレクション クラスは以下のとおりです。
ArrayList
HashMap
LinkedList
これらのクラスで作成されるオブジェクトを使用すると、他のオブジェクトの集合を管理しやすくなります。配列に対するコレクションの利点は、コレクションにオブジェクトを追加するために、コレクションの最終的なサイズを知らなくてもよいことです。コレクションの不利な点は、一般に同じサイズの配列よりも大きくなることです。たとえば、サイズのわからないオブジェクトの集合を管理するために、LinkedList オブジェクトを作成できます。
LinkedList l = new LinkedList();
l.Add("Bob");
l.Add("Mary");
l.Add("Jane");
…
バージョン 1.2 より前の Java では、オブジェクトの集合を管理するために、Vector および Hashtable クラスがよく使用されました。ただし、これらのクラスは同期的であるため、マルチスレッドで使用する場合は安全ではありませんでした。同期化にはパフォーマンス上の問題があります。同期化の動作が必要ない場合、新しい ArrayList および HashMap クラスを使用する方がパフォーマンスが向上します。
コレクション クラスには、コレクションの内容に順にアクセスしやすいように、組み込みのイテレータを備えているものもあります。組み込みのイテレータは java.util.Iterator クラスから派生します。このクラスを使用すると、順に各オブジェクトを操作しながら、オブジェクトのコレクション内を移動することができます。イテレータを使用する場合、イテレータには、イテレータを取得した時点のコレクションのスナップショットが含まれることに注意してください。イテレータで処理している間は、コレクションの内容を変更しないことをお勧めします。
Java では、java.lang.String クラスと java.lang.StringBuffer クラスで、便利な文字列操作機能を提供しています。初心者の Java プログラマが誤りやすい点で、パフォーマンスに影響を与えるものに、StringBuffer オブジェクトではなく String オブジェクトの文字列操作を実行することが挙げられます。
String オブジェクトは不変です。つまり、オブジェクトを作成したら、その値は変更できません。そのため、連結のような操作の場合、String オブジェクトを変更しているように見えても、実際には元の String オブジェクトの内容を変更した新しい String オブジェクトを作成しています。String オブジェクトの操作を多数実行すると、計算の負荷がかかります。
StringBuffer クラスは String で提供されるものと同様の文字列操作メソッドを提供していますが、StringBuffer オブジェクトは変化するため、適当な箇所で変更することができます。
Java では、プログラムの要素に情報を添付して、その情報を自動抽出するメカニズムが定義されています。このメカニズムは Javadoc と呼ばれますが、もともとは、クラスに関するドキュメントを自動的に生成できるように、クラス、メソッド、および変数に特定のフォーマットのコメントを添付することを目的としていました。標準の Java API ドキュメントはこのようにして作成されています。
Javadoc コメントには、特殊な開始記号が必要です。/* ではなく /** で開始しなければなりません。
Java のヒント : コメント内の最初の Javadoc タグの前には任意のテキストを含めることができますが、最初の Javadoc タグより後のテキストは、すべてタグの値の一部でなければなりません。Javadoc タグの後には自由なコメントを含めることができません。含めた場合はコンパイル エラーが発生します。
コメントの特殊な開始記号の他に、Javadoc では、コードの部分の注釈に使用される複数の Javadoc タグを定義しています。Javadoc タグは常に @ 記号で開始します。標準の Javadoc タグの例を以下に示します。
@param:メソッドのパラメータの説明です。
@see:他のクラスへの参照です。ドキュメントではハイパーリンクになります。
@since:このクラスが最初に導入されたバージョンの番号です。
Javadoc タグの当初の目的はドキュメントの作成でしたが、プログラムの要素に情報を添付し、自動的に生成できる便利で体系的な方法なので、現在では他にも利用されています。
WebLogic Workshop では Javadoc タグを使用して、プログラムの要素に特定の意味を関連付けています。たとえば、JWS ファイルでクラスのメンバー変数に @jws:control タグを付けた場合、WebLogic Workshop ではコメントの付いたメンバー変数を WebLogic Workshop コントロールとして扱います。
Java では、予期しないプログラムの状況に対応するための一般的な方法を定義しています。例外とは、コード内で予期しない状況が発生したことを示す信号です。予期しない状況に遭遇すると、メソッドは例外を送出します。例外を送出するメソッドを呼び出す場合、Java コンパイラでは、try-catch ブロック(後述)内にメソッド呼び出しを配置して例外を処理するように強制しています。
例外は Java オブジェクトです。そのため、そのメソッドを呼び出すことで、例外の情報が簡単に取得できます。ほとんどの Java 例外オブジェクトは基本の java.lang.Exception クラスを継承しています。特殊な例外クラスには、特定の状況の発生に関連する情報が含まれています。たとえば、SQLException オブジェクトは、SQL エラーの発生に関する情報を提供します。
例外処理には try-catch-finally ブロックを使用します。try-catch-finally ブロックを使用すると、エラー処理のコードを 1 箇所にまとめることができます。その位置はプログラム ロジックの近くですが、ロジックには混ざりません。
以下の例に try-catch-finally ブロックを示します。例では doSomething() メソッドが BadThingHappenedException を送出すると仮定しています。
public void callingMethod() { try { doSomething(); } catch (BadThingHappenedException ex) { <examine exception and report or attempt recovery> } finally { <clean up any work that may have been accomplished in the try block> } return; }
doSomething() が正常に終了すると、プログラムは try-catch-finally ブロックの後の最初の文から実行を継続します。finally ブロックは実行されないことに注意してください。
doSomething() が BadThingHappenedException を送出した場合、catch ブロックで捕捉されます。catch ブロックでは、予期しない状況に対応するために必要なアクションを実行できます。
try ブロックの一部を実行して例外が発生した場合は、finally ブロックが実行されます。これにより、実行された部分的な処理をクリーン アップする機会が与えられます。たとえば、例外が発生する前に try ブロックでファイルが開かれた場合、finally ブロックでファイルを閉じるようなコードを記述しておきます。
C や C++ のような前身のコンパイル言語とは異なり、Java は、実行されるプロセッサ アーキテクチャに固有のマシン コードへはコンパイルされません。代わりに、Java コードは Java バイト コードにコンパイルされます。Java バイト コードは Java 仮想マシン(JVM)用のマシン コードです。この特徴によって、さまざまなオペレーティング システムにわたる Java 特有の移植性が実現します。
すべての Java コードは JVM で実行されるため、JVM には従来のプログラミング言語では実装するのが難しい機能も含まれています。JVM が備える機能の 1 つにガベージ コレクションがあります。
JVM は存在する各オブジェクトのすべての参照を追跡します。オブジェクトの最後の参照が削除されると、オブジェクトはもう使用されません(どこからも参照できないため、使用されなくなります)。定期的に、またはメモリ リソースが減少した時点で、JVM はガベージ コレクタを実行します。ガベージ コレクタは参照されていないすべてのオブジェクトを破棄して、そのメモリを解放します。
プログラマにとっては、JVM が代わりに行ってくれるため、メモリの割り当てを意識したり、オブジェクトが解放される時期を把握したりする必要がなくなります。Java には、C/C++ の malloc 関数や C++ の new 演算子と似た new キーワードがありますが、free() 関数や delete キーワードはありません。Java でもやはりメモリ リークが発生する可能性はありますが、その頻度は他の高水準言語より少なくなります。
以下の節では、Java パッケージについて、および Java パッケージと Java クラスとの関係について説明します。
すべての Java コードは、パッケージ ネームスペースの中に存在します。パッケージ ネームスペースは、複数のエンティティに同じ名前を付けた場合に起きる衝突を回避するためにあります。エンティティが別々のネームスペースに存在する場合、それぞれはユニークであり、衝突しません。
Java ソース ファイルの上部には、package 文が含まれていることがあります。ファイルで特定のパッケージが宣言されていない場合、そのファイルの内容はデフォルト パッケージに割り当てられます。
すべてのクラスとオブジェクトは、単純名と完全修飾名の両方を持っています。たとえば、Java クラス String には、単純名 String と完全修飾名 java.lang.String があります。String クラスは java.lang パッケージで宣言されているからです。
パッケージ名とファイルが存在するディレクトリ階層との間には関係があります。次の文を含むファイルがあるとします。
package security.application;
このファイルは security/application ディレクトリに存在しなければなりません。ファイルがない場合、Java コンパイラはエラーを発行します。
パッケージでは、完全修飾名がユニークである限り、パッケージ階層の複数の場所に、同じクラス名やオブジェクト名が存在してもよいことになっています。標準の Java パッケージで、java.util パッケージと java.awt パッケージの両方に List クラスが含まれているのはこのためです。
ファイルに package 文を含める場合、package 文は、コメント以外のものではファイル内で最初の位置に記述しなければなりません。
他のパッケージのクラスやオブジェクトを参照する前に、参照するパッケージまたはパッケージ内の特定のエンティティをインポートする必要があります。上の例のパッケージのすべてのクラスとオブジェクトをインポートするには、ファイルに次の文を含めます。
import security.application.*;
次の文では、security パッケージで宣言されるクラスとオブジェクトだけをインポートし、security.application パッケージやその内容はインポートしません。
import security.*;
UserCredentials が security.application パッケージ内のクラスで、パッケージの中で参照するのはこのクラスまたはオブジェクトだけという場合は、次の文を使って限定的に参照することができます。
import security.application.UserCredentials;
大きなパッケージからいくつかのクラスだけをインポートする場合、パッケージ全体をインポートする代わりに、限定的な形式を使用します。
import 文は、コメント以外のものではファイル内で最初の位置に記述しますが、package 文がある場合はその後になります。