Javaの文法(Javaのぶんぽう)の記事では、プログラミング言語Javaの構文(シンタックス、英: syntax)について解説する。また、それ以外についても解説している。
キーワード一覧
Javaの基本言語仕様は54種類程度に抑えたキーワードによって比較的コンパクトにまとめられている。Javaの構文はC 言語によく似たものであり、それよりも比較的平易化されている。従って以下のキーワードを眺めるだけでもJavaプログラミングの大まかなスタイルを掴むことができる。
データ型
Javaのデータ型には大別して、プリミティブ型と参照型がある。
プリミティブ型
primitive data typeもしくはprimitive typeとも。 プリミティブ型はオブジェクトではなく、スーパークラスを持たない。
- 注
- オーバフローは例外等にはならず、2の補数として自然な形でラップアラウンド (wrap around) する。例えば、
Integer.MAX_VALUE(= 231−1) に1を加えると、結果はInteger.MIN_VALUE(= −231) になる。
float型は数字を符号付き32Bitの最大値(2,147,483,647)まで代入できるが、double型は符号付き64Bitの最大値(9,223,372,036,854,775,807)まで代入できる。
また、float型は代入する数字の末尾に「F」または「f」をつけなければdouble型とみなされ、コンパイルエラーになってしまう。
- 注
- 浮動小数点数は決して例外をスローしない
- 0でない値を0(ゼロ)で割った値はInf(無限大)と等値である
- 無限大でない値をInfで割った値は0(ゼロ)と等値である。
- 注
- J2SE v 1.4.2までのcharは基本多言語面 (BMP) の範囲内のコードポイントを符号無し16ビットで表現する。
- J2SE 5.0からは、補助文字をサポートするため、charは符号無し16ビットで表現可能でありBMPの範囲内に限ればコードポイントと同値となるUTF-16符号化形式のコード単位を表現するように変更され、21ビットが必要となるコードポイントの表現にはintを使用するように変更された(JSR#204)。つまりchar型は互換性の問題からあくまで符号無し16ビットのままとされており、UTF-16符号化形式を採用したことから補助文字を扱う場合はコードポイント一つにコード単位を格納したchar値のペアが対応する。これらを適切に取り扱う便宜として、
StringクラスやプリミティブラッパークラスであるCharacterクラスなどの各種メソッドが利用できる。
- 注
- C/C や類似の言語と異なり、Javaではfalseの代わりに0(ゼロ)またはnullと書くことはできない
- 同様に、0でない値を書いてtrueの代わりとすることはできない
- ブール型をブール型でない基本型へキャストすることとその逆はできない
参照型
すべての参照型はオブジェクト型を表すクラスObjectから派生する。オブジェクトは参照型のインスタンスである。クラスclassは既定でObjectから派生する参照型である。列挙型enumは抽象クラスEnumから暗黙的に派生する参照型である。
リフレクション機能のための「クラスを表現するクラス(メタクラス)」としてClassが存在するが、クラス自体はオブジェクトではない。
文字列
Stringオブジェクトは不変(変更不能)である- Stringオブジェクトは生成時に初期化されなければならない
- コンパイラは文字列リテラル(ダブルクォーテーションで囲まれた文字列)を見つけると、Stringオブジェクトを生成する
- 演算子
と=は文字列を連結するためにオーバーロードされる
StringBufferとStringBuilderオブジェクトは可変(変更可能)なので、オブジェクト生成オーバヘッド無しで柔軟に文字列を生成・変更できる。StringBufferとStringBuilderの違いは、StringBufferがマルチスレッドに対応している(=スレッド・セーフである)のに対し、StringBuilderは対応していないことである。- StringとStringBufferは互いに独立であり、一方から派生したものではない
プリミティブラッパークラス
プリミティブラッパークラス
ByteShortIntegerLongFloatDoubleBooleanCharacter
- 機能
- ある型の値を他の型へ変換する静的メソッドを提供する
- 基本型を参照型としてラッピングする目的(ボックス化)で使用できる(コレクションに格納するなど)
- その他
- ブール型以外の基本型の初期値は0。ブール型の初期値はfalse。ラッパークラス(およびObjectクラスに属する全クラス)の初期値はnull。
配列
- 配列自体はオブジェクト型
Objectのサブクラスつまり参照型である。 - プリミティブ型の配列、オブジェクト型の配列、さらにそれらの配列の配列(ジャグ配列)、などの配列を扱える。
- プリミティブ型の配列では、全ての要素はその型の値でなければならない。
- オブジェクトの配列では、階層関係にある必要がある(例えば、インタフェースの配列では、あるオブジェクトがその要素になるには、そのインタフェースを実装したクラスのインスタンスでなければならない)。
- 配列オブジェクトは配列要素の数を表す読み取り専用の属性「
length」を持つ。 - すべての配列は動的に領域確保される。配列を生成する際の要素数として、定数だけでなく変数を使用することができる。
- 「配列の配列」ではない、(C#にあるような「本物の」)多次元配列(矩形配列)は無い。
リテラル
リテラルの例を示す。
国際化サポート
Javaは1バイト整数の型(byte)と文字の型(char)とを区別する。なお、charは、名前に反して必ずしも文字を表現していない場合があり得る。すなわち、実際にはUCS-2(UTF-16)による、いわゆるダブルバイトである。J2SE 5.0以降ではサロゲートAPIによって、サロゲートペアに対応した。
JavaプログラムのソースコードおよびソースファイルはUTF-8でエンコードするのが基本である。Unicodeに対応したエンコードであれば、Javaプログラムのソースコードに直接Unicode文字を記述することもできる。なお、-encodingコンパイルオプションを指定することで、対応する任意のエンコードを使用することもできる。ロケール依存のコードページ(日本語版Microsoft Windowsで使われているCP932等)を利用することもできる。
文字列リテラルやコメントの他、クラス名や変数名も国際化に対応している。例えば、次のソースコードはJavaのコードとして正しく解釈されコンパイルされ実行できる。ここではクラス名、変数名、および文字列リテラルとして日本語の文字を使っている。
演算子
算術演算子
算術演算子
代入演算子
代入演算子
関係演算子
関係演算子
関係演算子(==と!=)を参照型に対して用いた場合、そこで比較されるのは参照先のオブジェクトが同じかどうかであり、オブジェクトの中身の値が一致するか否かではない。オブジェクトの中身を比較したい場合はObject.equals(Object)メソッドを使用する。instanceof演算子は、オブジェクトが指定クラスのインスタンスであるか否かを判定するために用いる。
三項演算子
三項演算子は二つの記号?と:を組み合わせて記述する。条件演算子とも呼ぶ。構文は以下である。
条件 ? 式1 : 式2
条件がtrueであるとき、式1の値をとる。そうでない場合は式2の値をとる。
例:
論理演算子
論理演算子
- 短絡評価論理演算 (結果が判定するまでオペランドを左から右へと評価する)
- 必要最小限の式しか評価しない
- 部分的な評価 (完全な評価ではない)
ビット演算子
ビット演算子
文字列演算子
制御構造
if... else
if文
if (expr) {
statements;
}
else if (expr) {
statements;
}
else {
statements;
}
- exprは真偽値を与えなければならない。
switch文
switch文
switch (expr) {
case VALUE1:
statement11 ; … ; statement1L ;
break ;
case VALUE2:
statement21 ; … ; statement2M ;
break ;
default:
statementd1 ; … ; statementdN ;
}
expr値の型はbyte/short/int/charあるいはそれらのプリミティブラッパークラスでなければならない。- J2SE 5.0以降では列挙型 (Enumのサブクラス) を、JavaSE 7以降ではString型を使用することもできる。caseラベルの値にnullは使用できない。
- 各々のcaseラベルの値はユニークなリテラル、あるいはコンパイル時に値が定まる定数式 (constant expression) でなければならず、変数を書くことはできない。
forループ
for文
for (initial-expr; cond-expr; incr-expr) {
statements;
}
for-each ループ
J2SE 5.0では、for-each文と呼ばれる新機能が追加された。これは集合の中の全要素を順番に参照するような処理を大いに簡素化する。このような場合、従来は次の例に示すような反復子 (iterator) を書かねばならなかった:
for-each文はこのメソッドを大いに簡素化する:
この例の動作としては、stringSetに含まれる全てのStringについて、長さを取得してsumに加算する。
whileループ
while文
while (expr) {
statements;
}
do ... while
do-while文
do {
statements;
} while (expr);
分岐命令
例
ラベル
- 末尾にコロンがついた識別子からなる。
- 分岐命令が参照する文またはブロックを識別するために使われる。
- 仮にラベルを外したとすると、分岐命令は最も内側のループについて機能する。
例:
LABEL1: statement;
LABEL2: { statements; }
goto
Javaのキーワードには「goto」という綴りも含まれているが、goto文は無い(他にもうひとつ、constも同様に、キーワードとして予約されているが、予約されているだけで使われていない)。
オブジェクト
クラス
Javaではクラスあるいはインタフェースの内部で別のクラスを宣言することができる。これは「ネストされたクラス」(nested class) と呼ばれる。ネストされていないクラスは「トップレベルクラス」(top-level class) と呼ばれる。ネストされたクラスがstatic修飾されていない場合、「内部クラス」(inner class) となる。内部クラスは外側のクラスのインスタンスを暗黙的にキャプチャすることで、静的メンバ、非静的メンバいずれにもアクセスすることができる。ネストされたクラスがstatic修飾されている場合、「静的クラス」(static class) となり、静的メンバのみにアクセスできる。メソッドの内部にクラスを定義することもでき、これは「ローカルクラス」(local class) と呼ばれる。ローカルクラスでは、外側のローカル変数には読み取りアクセスのみできる。また、型の名前を持たないローカルクラスとして「匿名クラス」(anonymous class) を定義し、同時にインスタンス生成をすることもできる。
クラスあるいはインタフェースの内部で別のインタフェースを宣言することもできる。これは「ネストされたインタフェース」と呼ばれる。
クラスを宣言する際は以下の修飾子を付けることができる:
- abstract – インスタンス化できない。インタフェースと
abstract(抽象) クラスだけがabstract(抽象) メソッドを持つことができる。抽象クラスを継承する具象 (非abstract) サブクラスは、引き継がれた全ての抽象メソッドを、abstractでないメソッドでオーバーライドしなければならない。修飾子finalと併用することはできない。 - final – サブクラスを作らせない。 finalクラスのすべてのメソッドは無条件にfinalになる。 修飾子abstractと併用することはできない。
- strictfp – このクラスとそこに含まれる全てのネストクラスにおいて、全ての浮動小数点演算は厳密な浮動小数点演算動作を使用する。厳密な浮動小数点演算動作は、演算結果がプラットフォームに関わりなく同一となることを保証する。
Javaのクラス定義ブロックはセミコロン;で終わらせる必要はない点に注意。この点はC の文法と異なる。
継承
- 任意のクラスのデフォルトの親クラスは
Objectクラスである。 - クラスは単一の親クラスだけを継承できる。実装多重継承はできない。
スコープ
- this – 現在のサブクラス (デフォルト) への参照 (例:
this.someMethod())。 - super – 親クラスへの参照 (例:
super.someMethod())。サブクラスがオーバライドした親クラスのメソッドや、サブクラスが継承しつつも隠蔽した親クラスのフィールドにアクセスするために使うことができる。
インタフェース
インタフェースとは、実装の詳細がいっさいない抽象型である。その目的は複数のクラスを多態性によって統一的に扱うことである。共通のインタフェースを実装する複数のクラスは、そのインタフェース型のコンテキストにしたがって互いに交換可能とすることができる(リスコフの置換原則)。インタフェースはまた、抽象化 – クラスの実装方法を隠蔽すること – という考え方を強制するのにも役立つ。
インタフェースは抽象メソッドと定数フィールド (static finalフィールド) だけを含むことができる。インタフェースメソッドはデフォルトでpublicかつabstractであり(実装を持たない)、インタフェースフィールドはデフォルトで public static final である。インスタンスフィールドやクラスフィールドすなわち状態を持つことができない点が抽象クラスと異なる。
Javaは完全な直交の多重継承はサポートしておらず、インタフェースによる「型の多重継承」のみをサポートする。C における多重継承(実装の多重継承)には、複数の親クラスや型から複数回継承したフィールドやメソッドを識別するための複雑なルールが伴う。インタフェースを実装から分離することにより、インタフェースはより単純かつ明快に多重継承が持つ利点の多くを提供する。もっとも、実装の多重継承を避ける代価としてコードは若干冗長になる。というのは、インタフェースはクラスのシグネチャを定義するのみで実装を持てないため、インタフェースを継承する全てのクラスは定義されたメソッドをいちいち実装しなければならないからである。純粋な多重継承であれば実装自体も継承されるのでこのようなことはない。
なお、Java 8ではインタフェースのデフォルトメソッドにより実装の多重継承を限定的にサポートするようになった。また、インタフェースが静的メソッドを持つこともできるようになった。
Javaのインタフェースは Objective-C規約のコンセプトによく似た振る舞いをする。
インタフェースの実装
クラスは、一つのクラスを継承できるのに加えて、implementsキーワードを用いて一つ以上のインタフェースを実装することができる。
以下の例では、Deleteableインタフェースを実装する非abstractクラスは、引数無しで戻り型がvoidであるdeleteという名前の非抽象メソッドを定義しなければならない。そのメソッドの実装と機能は各々のクラスによって決定される。
このコンセプトにはさまざまな使い道がある。例えば:
上の配列に含まれる全てのオブジェクトはdelete()メソッドを持つことが保証されるので、deleteAll()メソッドはFredオブジェクトと他の如何なるDeleteableオブジェクトをも区別する必要がない。
インタフェースの継承
インタフェースはextendsキーワードを用いて一つ以上のインタフェースを継承することができる。
結果として生じるインタフェースを実装するクラスは、元のインタフェースに含まれたメソッドをも併せて定義しなければならない。
アクセス修飾子
アクセス修飾子は、そのクラスやクラスメンバにアクセス可能なクラスを決定する。
トップレベルクラスアクセス
デフォルトでは、Javaのクラスは、それら自身のJavaパッケージからのみアクセスできる。これは、クラスのパッケージが、裏に隠れて機能を実行するようなAPIを提供することを可能とする。外にアクセスを公開されたクラスの動作を、隠されたクラスが支える形になる。
- デフォルト (修飾子を省略した場合) – 定義されたパッケージ内からのみアクセス可能。
- public – 定義されたパッケージの外のクラスからもアクセス可能。
クラスメンバアクセス
クラスメンバとはフィールド、メソッド、コンストラクタ、クラス内で定義されたネストされたクラスのことである。アクセス制限が厳しいものから並べると、クラスメンバのアクセス修飾子は次の通り。
- private – そのクラスからのみアクセス可能 (内部クラスからのアクセスを含む)。
private宣言されたメンバはサブクラスによって引き継ぐことができない。 - package-private (修飾子を省略した場合) – 同じパッケージ内の他クラスからもアクセス可能。
- protected – 上に加え、パッケージ外の継承クラスからアクセス可能。
- public – 任意のクラスからアクセス可能。
メソッドをオーバライドする際、そのメソッドのアクセス権を「より厳しく」することはできない。さもなくば親クラスのインタフェース契約を壊してしまうからである。したがってオーバライドされる場合、publicメソッドはpublicとして宣言されねばならず、protectedメソッドをデフォルトアクセス権(修飾子省略)とすることはできない。しかしながら、メソッドをオーバライドしてアクセス権を「より緩める」ことは許される。したがってオーバライドする際、デフォルト (パッケージ) アクセス権のメソッドはprotectedまたはpublicとして宣言することができ、protectedメソッドはpublicとして宣言することができる。
フィールド
アクセス修飾子に加えて、データフィールドは以下の修飾子によって宣言される:
- final – このフィールドの中身は変更できない。ただ一度のみ値を設定(初期化)できる。イニシャライザ (初期化子) がないfinalフィールドを「ブランクfinal」フィールドと呼ぶ。
staticなブランクfinalフィールドは最終的にスタティックイニシャライザによって初期化されなければならない。staticでないブランクfinalフィールドはコンストラクタの実行中に必ず初期化されなければならない。volatileにはなれない。 - static – クラスのインスタンスではなくクラスに属する。
- transient – オブジェクトの中でも永続的 (persistent) にできないフィールドである。このフィールドの中身を待避または復元してはならないことをコンパイラに知らせる。
- volatile – そのフィールドが他スレッドによって非同期にアクセスされる可能性があることをコンパイラに知らせる。finalにはなれない。
定数
staticとfinal両方を宣言されたフィールドは事実上、定数である。staticはそのフィールドがそのクラスにおいてただ一つのみ存在することを示し、finalはそのフィールドがただ一度のみ値を設定(初期化)可能であることを意味する。
初期化子
「イニシャライザ」(初期化子)はフィールドのイニシャライザと同時に実行されるコードのブロックである。
静的初期化子
「スタティックイニシャライザ」(静的初期化子)はstaticフィールドのイニシャライザと同時に実行されるコードのブロックである。静的フィールド初期化子と静的初期化子は宣言された順番に実行される。静的初期化はクラスがロードされた後で実行される。
インスタンス初期化子
「インスタンスイニシャライザ」(インスタンス初期化子)はインスタンスの (非staticな) フィールドの初期化子と同時に実行されるコードのブロックである。インスタンスフィールド初期化子とインスタンス初期化子は宣言された順番に実行される。
インスタンス初期化子とインスタンスフィールド初期化子はコンストラクタが呼び出された際に実行される。正確な実行順序としては、親クラスのコンストラクタが実行された後、かつ、自身のコンストラクタが実行される前、となる。
メソッド
アクセス修飾子に加えて、メソッドには以下の修飾子を付けて宣言できる:
- abstract – 当該クラスでは定義されないメソッドであり、代わりに当該クラスの全ての具象 (非
abstract) サブクラスによって定義されなければならない。static、final、nativeのいずれとも併用できない。 - final – サブクラスによって再定義できないメソッド。そのメソッドがインスタンス (非
static) メソッドでありかつ十分小さいならば、コンパイラはそのメソッドをインライン関数のように各所に展開する場合がある(訳注:性能改善目的と思われる)。abstractと併用はできない。 - native – このメソッドはネイティブなマシン依存コードにリンクする。メソッド本体無しで宣言される。abstractと併用はできない。Java Native Interfaceにて使用される。
- static – クラスのインタンスではなく、クラスに属する。abstractと併用はできない。
- strictfp – メソッドとそこに含まれる内部クラス全てにおける浮動小数点演算が、厳密な浮動小数点演算動作を使用する。厳密な浮動小数点演算動作は、演算結果がプラットフォームに関わりなく同一となることを保証する。
- synchronized – メソッド本体を実行する前に、関連オブジェクトを排他する。関連オブジェクトが他スレッドにて排他済である場合、他スレッドが排他を解除し自スレッドが排他を獲得するまで実行を待たされる。ここで言う関連オブジェクトとは、そのメソッドがstaticならば
Classオブジェクトを指し、非staticならばオブジェクトインスタンスを指す。abstractメソッドをsynchronizedとして宣言することは可能だが意味はない。何故なら排他とは宣言ではなく実装に伴う機能であり、抽象メソッドは実装を持たないからである。
privateメソッドは自ずからfinalであり、abstractにはできない点に注意。
可変引数
Java SE 5.0において、引数の個数が可変であるようなメソッドについての文法上の便宜 (varargs) [1]が追加された。これによって引数の個数が可変であるメソッドをタイプセーフに使用することが容易になる。最後のパラメタの後に「...」と書くと、Javaは全ての引数を配列に格納する:
このメソッドを呼ぶ際、プログラマは個々のpointsを単にカンマで区切って書けばよく、Pointオブジェクトの配列をわざわざ用意する必要はない。このメソッドの内部でpointsを参照する際はpoints[0]、points[1]、などのように書ける。pointsが渡されていない場合、配列のlengthは0となる。可変個の引数と別に固定的に必要なパラメタがある場合は、それらのパラメタは可変引数に先立って指定すればよい。
コンストラクタ
コンストラクタはオブジェクトが割り当てられた後すぐに呼び出され、オブジェクトの初期処理を行う。コンストラクタは典型的にはnewキーワードを使用して呼び出されるが、リフレクションを使用して呼ぶこともできる。リフレクション機能はjava.lang.reflectパッケージより提供される。
コンストラクタを宣言する際に使える修飾子はアクセス修飾子のみである。
- 可能ならば、オブジェクトはひとたびコンストラクタを呼ばれた以後は直ちに有効かつ有意味なオブジェクトとなるべきである。分割された複数の初期化用メソッドを使わなければ初期処理が完了しないというような設計は好ましくない。
- 慣習として、引数としてそのオブジェクト自身の型を受け取ってデータメンバを複写するようなコンストラクタを「コピーコンストラクタ」と呼ぶ。
- コンストラクタが明示的に定義されていない場合、コンパイラは暗黙のうちに内容が空で引数を取らないデフォルトのコンストラクタを生成する。
- コンストラクタはオーバーロードできる。
- コンストラクタ内の最初の文は親クラスのコンストラクタ:
super(...);または同じクラス内の別のコンストラクタ:this(...);を呼び出せる。 - もし、
super(...)またはthis(...)に対する明示的な呼び出しがないならば、コンストラクタ本体が実行される前に、親クラスのデフォルトコンストラクタsuper();が呼ばれる。
Objectクラスのメソッド
Objectクラスのメソッドは継承されるので、全てのクラスにて使用できる。
cloneメソッド
Object.clone()メソッドは現在のオブジェクトのコピーである新しいオブジェクトを返す。クラスは、それがクローンできることを明示するためにマーカーインタフェースCloneableを実装しなければならない。
equalsメソッド
Object.equals(Object)メソッドはそのオブジェクトともう一つのオブジェクトを比較し、二つのオブジェクトが同一かどうかをboolean型の値で返す。意味的には、このメソッドはオブジェクトの内容を比較するのに対し、関係演算子"=="はオブジェクトの参照を比較する。equalsメソッドはjava.utilパッケージにあるデータ構造クラスの多くで使われる。これらのデータ構造クラスのいくつかはObject.hashCodeメソッドにも依存している - equalsとhashCodeとの間の契約の詳細について、hashCodeメソッドを参照のこと。
finalizeメソッド
Object.finalize()メソッドはガベージコレクタがオブジェクトのメモリを解放する前に必ず一度だけ呼び出される。オブジェクトが消滅する前に実行しなければならない何らかの後処理がある場合、各クラスはfinalizeをオーバーライドすることができる。とはいえほとんどのオブジェクトはfinalizeをわざわざオーバーライドする必要はない。
finalizeメソッドがいつ呼ばれるかは保証されない。複数のオブジェクトのfinalizeがどのような順番で呼ばれるかも不定である。もしJVMがガベージコレクションを実行せずに終了するならば、OSがオブジェクトを解放する可能性があり、その場合finalizeメソッドは呼ばれない。
finalizeメソッドは、他のクラスから呼ばれるのを防ぐために、常にprotectedとして宣言されるべきである。
getClassメソッド
Object.getClass()メソッドはオブジェクトをインスタンス化するために使われたクラスのClassオブジェクトを返す。このクラスオブジェクトはJavaにおけるリフレクションの基本となる。その他のリフレクション機能はjava.lang.reflectパッケージにて提供される。
hashCodeメソッド
Object.hashCode()メソッドは連想配列にオブジェクトを保存するための「ハッシュ値」として (int型の) 整数を返す。java.util.Mapインタフェースを実装するクラスは連想配列を提供しhashCodeメソッドに依存する。hashCodeの良い実装は安定 (不変) かつ均等に分布するハッシュ値を返す (異なるオブジェクトのハッシュ値は互いに異なる値となる傾向を持ち、かつハッシュ値は整数値の範囲内で均等に分布する)。
連想配列はequalsとhashCodeの両メソッドに依存するため、これら二つのメソッドの間では、オブジェクトがMapに挿入される場合に関する或る重要な契約が維持されねばならない:
- 二つのオブジェクト a と b に関して
-
a.equals(b) == b.equals(a)でなければならない。- もし
a.equals(b)がtrueならば、a.hashCode() == b.hashCode()でなければならない。
この契約を維持するために、equalsメソッドをオーバーライドしたクラスは同時にhashCodeメソッドもオーバーライドし、逆もまた同様として、hashCodeとequalsが常に同じ性質(または同じ性質の一部)に基づくようにしなければならない。
マップがオブジェクトとの間に有する更なる契約は、ひとたびオブジェクトがマップに挿入されたなら、hashCode と equals両メソッドの結果は以後変わらないということである。したがって、一般にハッシュ関数はオブジェクトの不変(変更不能)な属性に基くように設計するのが良い。
toStringメソッド
Object.toString()メソッドはオブジェクトの文字列表現をStringで返すものである。toStringメソッドは、オブジェクトが文字列連結演算子( と =)のオペランドとして使われたとき、コンパイラによって暗黙のうちに呼び出される。
waitとnotifyスレッドシグナルメソッド
全てのオブジェクトは、そのオブジェクトに関連するスレッドについての二つの待ちリストを持つ。一つの待ちリストはsynchronizedキーワードに伴いオブジェクトをミューテックス排他するために使われる。もしミューテックスが他スレッドによって排他されているならば、自スレッドは排他を待っているスレッドのリストに追加される。もう一つの待ちリストはスレッド間でシグナルを送るためのもので、これはwait、notify、notifyAllの各メソッドを通して使用される。
wait/notifyを用いるとスレッド間での能率的な連携が可能となる。あるスレッドが別スレッドでの処理が終わるのを待ち合わせる必要があるとき、または何らかのイベントが発生するまで待たねばならないとき、スレッドはその実行を一時停止してイベントが発生した際に通知を受け取ることができる。これはポーリングとは対照的である。ポーリングにおいては、スレッドは一定時間スリープしてはフラグや他の状態表示をチェックする処理を繰り返す。ポーリングはスレッドがチェックを繰り返さねばならないという点でより計算コストが掛かる上に、実際にチェックしてみるまでイベント発生を検知できないという意味で鈍感でもある。
waitメソッド
waitメソッドには三つのオーバーロード版があり、タイムアウト値の指定方法がそれぞれ異なる:wait()、wait(long timeout)、wait(long timeout, int nanos)の三つである。一つ目のメソッドはタイムアウト値が0であり、これはタイムアウトが発生しないことを意味する。二つ目のメソッドはミリ秒単位のタイムアウト値を取る。三つ目のメソッドはナノ秒単位のタイムアウト値を取り、これは1000000 * timeout nanosとして計算される。
waitを呼んだスレッドは待機状態となり、そのオブジェクトの待ちリストに追加される。そのスレッドは以下の三つのイベントのいずれか一つが起きるまで、オブジェクトの待ちリスト上に留まる:
- 別のスレッドがそのオブジェクトの
notifyまたはnotifyAllメソッドを呼ぶ (詳細はnotifyメソッド参照) - 別のスレッドがそのスレッドの
interrupt()メソッドを呼ぶ waitにて指定した0でないタイムアウト値が満了する
waitメソッドは、そのオブジェクトについての同期(synchronized)ブロックまたは同期(synchronized)メソッドの内部からのみ呼ばねばならない。これはwaitとnotifyとの間で競合を起こさないためである。スレッドが待ちリストに入るとき、そのスレッドはそのオブジェクトのミューテックス排他を解除する。そのスレッドが待ちリストから削除され実行可能スレッドとなった際に、そのスレッドは走行を再開するのに先立ってそのオブジェクトのミューテックスを改めて排他しなければならない。
notifyとnotifyAllメソッド
Object.notify() と Object.notifyAll() メソッドはオブジェクトの待ちリストから一つ以上のスレッドを削除し、それらを実行可能スレッドとする。notifyは待ちリストから1スレッドのみ削除し、notifyAllは待ちリストから全てのスレッドを削除する。notifyがどのスレッドをリストから削除するかは規定されておらず、JVMの実装に依存する。
notifyとnotifyAllメソッドは、そのオブジェクトについての同期(synchronized)ブロックまたは同期(synchronized)メソッドの内部からのみ呼ばねばならない。これはwaitとnotifyとの間で競合を起こさないためである。
アノテーション
Javaのアノテーションはクラスやインタフェース、メソッドやフィールド、パッケージなどに対してメタデータとして付加情報を記入する機能で、Java SE 5 で追加された。
アノテーションはjava.lang.annotation.Annotationインタフェースを実装することで自作することもできる。
Javaのアノテーションは三つに分けることができる。
- マーカー・アノテーション – データが無く名前だけを持つアノテーション。
- 単一値アノテーション – データを一つだけ持つアノテーション。見かけはメソッド呼び出しに似ている。
- フル・アノテーション – 複数のデータを持つアノテーション。
Java標準APIの主なアノテーション
@Deprecated– 対象となるクラスやメソッドが非推奨であることを情報として付加する。@Override– そのメソッドがスーパークラスのメソッドをオーバーライドしていることを示す。@SuppressWarnings– 引数で指定した特定の警告メッセージをJavaコンパイラに与えず無視する。@Target– 定義したいアノテーションがどこに適用されるべきかを指し示すメタアノテーション。@Retention– アノテーションの配置方法を設定するメタアノテーション。
JUnit4 から利用可能になったアノテーション
@Test- そのメソッドがテストメソッドであることを示す。このメソッドにテストを記述する。従来のJUnitでメソッド名が
testで始まるメソッドと同じ。 @Before- このアノテーションが付加されたメソッドは、
@Testアノテーションが付いたメソッドを実行するたびに事前に実行されることを意味する。 @After- このアノテーションが付加されたメソッドは、
@Testアノテーションが付いたメソッドを実行するたびに、必ず後から実行されることを意味する。 @BeforeClass- このアノテーションが付加されたメソッドは、そのテストクラスを呼び出す前に実行される。
@AfterClass- このアノテーションが付加されたメソッドは、そのテストクラスを呼び出した後に実行される。
アノテーションを使用する
マーカーアノテーション
クラスやメソッドにマーカーアノテーションを付加するには以下のようクラスやメソッドの接頭辞に最低一つ以上のスペースまたは改行コードを入れて修飾子のように記述する。 この例は、クラスに非推奨、メソッドに、スーパークラスからのメソッドをオーバーライドしていることを意味するマーカーアノテーションを付加している例である。
単一値アノテーション
単一値アノテーションを付加するには以下のようにする。
この例は、Serializableインタフェースを実装したクラスのフィールドにstatic finalなserialVersionUIDが宣言されていないという警告を無視するアノテーションを付加していることを意味する。
これは、以下のような書き方もできる。これは単一値アノテーション@SuppressWarningsがvalue()メソッドを一つしか持たないことがわかっているためvalue = を省略できることを意味する。
このアノテーションは、戻り値の型がString[]になっているため同じvalue値であっても以下のように複数指定することができる。以下のように指定することで、シリアルバージョンIDが設定されていない警告と、コレクションで総称型による型チェックを行われていないことによって生ずる警告を無視することができる。 "unchecked"はメソッドに対してのみ設定することもできる。
このアノテーションは正確に記述すると以下のようにString[]配列の初期化宣言のようになる。
フルアノテーション
フルアノテーションは、複数のデータ型を持つアノテーションである。ここでは自作したアノテーション @MyAnnotation があるとき、以下のように、変数名 = 値の形をカンマで区切って記述する。各値の記法は、各アノテーションで定義されているメソッドの戻り値の型で決まる。たとえばこの場合valueという変数名はStringを戻り型にとる value() というメソッドと、int を戻り型にとる version() というメソッドを持つ。フルアノテーションの場合は、default によりデフォルト値が設定されているアノテーション以外は、value = や version = を省略することはできない。
アノテーションを定義する
アノテーションを定義するには、interfaceキーワードの接頭辞に@をつけて定義する。
マーカーアノテーション
マーカーアノテーションは以下のように定義する。メソッドやフィールドが一切ないマーカーインタフェースのアノテーション版ともいえる。@Overrideや@Deprecatedがこれらのアノテーションに相当する。
単一値アノテーション
単一値アノテーションは以下のように定義する。このアノテーションには少なくともメソッドがひとつだけ定義されている。単一値アノテーションのメソッド名にはvalueという名前をつけるのが儀礼である。
フルアノテーション
フルアノテーションは以下のように定義する。以下のように二つ以上のメソッドを定義する。
メタアノテーション
メタアノテーションとは、定義しているアノテーションのみにつけられるアノテーションのことである。メタアノテーションの例としては@Targetや@Retention、@Documented、@Inheritedがあり、これらはクラスやメソッドなどには使うことができず、アノテーションのみに使うことができる。アノテーションを定義するために使われるアノテーションということから、メタアノテーションと呼ばれる。
メタアノテーションを使用する
メタアノテーションを使ってアノテーションを定義するには、以下のように記述する。
このとき、@Retentionは、新たにアノテーション NewAnnotation を作るとき、このアノテーション情報はソースコードのみにしか保存されないことを意味する。@Targetはこのアノテーションをどの型に使うことができるかを指定している。この場合、ANNOTATION_TYPE と METHOD を指定しているのでこのアノテーションはアノテーション型とメソッドにしか使うことができない。つまり、この NewAnnotation もまた、メソッドだけでなくアノテーションにも保存できるため、メタアノテーションとしても使えることを示している。
@Retention
メタアノテーション@Retentionには以下のRetentionPolicy列挙型を設定することができる。
@Target
メタアノテーション@Targetには以下のElementType列挙型を設定することができる。これは配列を使って
と複数指定することができる。ただし、同じ値を { … } 内で複数使用するとエラーとなる。これによって型を指定することで、そのアノテーションが、どの型に対して使うことができるのかを指定できる。
入出力
- 関連項目: Java Platform, Standard Edition#java.io と New I/O
J2SE1.4よりも前のバージョンのJavaはストリーム・ベースのブロッキングI/Oのみをサポートしていた。これは1ストリームにつき1スレッドを必要とした。何故ならストリームの入力または出力を行おうとすると、それが完了するまでそのスレッドは完全に待ちに入ってしまい、他の処理がいっさい行えなくなったからである。これは、Javaを用いたネットワークサービスを構築する上で、スケーラビリティと性能双方の面で大きな問題となっていた。J2SE1.4以降では非ブロッキングI/OフレームワークとしてNIO (New I/O) が導入され、このスケーラビリティ問題は修正された (ただし、サンによるNIO APIの実装にはまだ多くの問題点がある)。
非ブロッキングIOフレームワークは、以前のブロッキングIOフレームワークより遥かに複雑ではあるが、一つのスレッドで任意の数の"チャネル"を扱うことができる。このフレームワークはReactorパターンをベースとしている。
実行コード
アプリケーション
- (ウェブブラウザではなく) スタンドアロン仮想マシンで実行されるJavaコード
mainメソッドは以下のように定義されなければならない:
アプレット
- ウェブブラウザで明示された表示領域上で実行されるJavaコード。
initとdestroyは一度だけ呼ばれるが、startとstopはユーザがウェブページを訪問するたびに何回も呼ばれる。
appletタグの埋め込み
- HTMLのappletタグをアプレットのソースコードに埋め込むことができる。
- appletタグを書くと、そのアプレットは.htmlファイル無しでも、簡易アプレットビューアによって直接実行可能となる。
- 典型的には、appletタグはimport文の直後に書かれる。
- appletタグは
/* */コメントによって囲まれていなければならない。
サーブレット
- Webサーバ上で実行されるJavaコードであり、その出力 (一般的にHTMLやXML) は典型的にはウェブブラウザに対して送信される。
JSP (JavaServer Pages)
- ウェブページにJavaコードを埋め込む形態。
- JSPタグはウェブサーバで処理され、出力結果 (一般的にHTMLやXML) はクライアントに送信される。
- JSPコードは実行される前にJava Servletにコンパイルされる。
- JSPはJava Servletの拡張である。
- JSPタグの使用法はPHPやASPのタグの使用方法と類似する。
JSPタグ
その他
ケースセンシティビティ (大文字小文字区別)
Javaはケースセンシティブ (大文字小文字を区別する) である。
コメント
コメントの文法はC と同じである。
なお、ドキュメンテーションコメントとしてJavadoc方式をサポートする。
関連項目
- Java
- 予約語 (Java)
- Java Platform, Standard Edition
参考文献
- James Gosling, Bill Joy, Guy Steele, and Gilad Bracha, The Java language specification, third edition. Addison-Wesley, 2005. ISBN 0-321-24678-0.
- Patrick Naughton, Herbert Schildt. Java 2: The Complete Reference, third edition. The McGraw-Hill Companies, 1999. ISBN 0-07-211976-4
- Vermeulen, Ambler, Bumgardner, Metz, Misfeldt, Shur, Thompson. The Elements of Java Style. Cambridge University Press, 2000. ISBN 0-521-77768-2
脚注
注釈
出典
外部リンク
オラクル
- Java
- Javaソフトウェア
- Java Language and Virtual Machine Specifications - Authoritative description of the Java language
- Java SE 9 API Javadocs
- The Java Tutorials
- New features in Java SE 7




