Java2認定試験対策

 

1.              言語の基礎

予約語

 

package:        クラスのパッケージを宣言する。ソースファイルの先頭に書かなくてはならない。

 

protected:     自分、もしくは自分から派生したクラス、もしくは自分と同じパッケージ内にある別のクラスからアクセス可能なメンバを定義する。

 

final:         クラスの継承メソッドのオーバーライド変数の再初期化を出来なくする。

 

native:        プラットフォームに依存する言語(Cなど)で書かれているメソッドを示す。

 

strictfp:      メソッドまたはクラスの前に指定して、すべての式の中で浮動小数点数が、FP-strict規則に従うことを示す。

 

transient:     フィールドが直列化(シリアライズ)されるのを防ぐ。

 

volatile:      変数が複数のスレッドで使われて、非同期に変更される可能性があることを示す。

 

instanceof:    オブジェクトが特定のクラス、サブクラス、インタフェースのインスタンスかどうか(IS-A)を判断する。

 

assert:        プログラマーの仮定を確認するために条件式を査定(アサーション)する。

               特殊なコンパイラオプションおよび実行オプションが必要。

               注)Eclipseでアサーションのプログラムを動かすには、

1)       ProjectBuild Pathの設定にて、JDK Compliance1.4以上に設定する(assert1.4以降に導入された機能)

2)       VM Argumentsに –ea を指定して実行

3AssertionException例外がスローされる

 

boolean:       trueまたはfalse (2ビット)

byte:           8ビットの整数(符号付)

char:          1つのUnicode(符号なし16ビット)

short:         16ビットの整数(符号付)

int:           32ビットの整数(符号付)

long:          64ビットの整数(符号付)

float:         32ビットの浮動小数点数(符号付)

double:        64ビットの浮動小数点数(符号付)

 

使われていない予約語

const:         定数を宣言するために使用してはならない(static finalを使う)

goto:          実装されていない(gotoロジックは有害と考えられている)

 

基本データ型の範囲

ビット数

バイト数

最小値

最大値

byte

8

1

-128

127

short

16

2

-32,768

32,767

int

32

4

-2,147,483,648

2,147,483,647

long

64

8

-9,223,372,036,854,78*,***

9,223,372,036,854,78*,***

float

32

4

 

 

double

64

8

 

 

 

IEEE754

米国電子技術者協会で定められた、浮動小数点数の表現規格。

一つの浮動小数点数を32ビットまたは64ビットで表現する。

有効な数を仮数と呼び、残りのビットを指数符号にあてる。

 

32ビット(単精度):最初の1ビットが符号部,次の23ビットが仮数部,残りの8ビットが指数部

64ビット(倍精度):最初の1ビットが符号部,次の52ビットが仮数部,残りの11ビットが指数部

 

例)光の速さ:30万キロ[/sec]= 2.997924578×10^8では、

符号:+

仮数:2.997924578

指数:8

となる。

 

IEEE754のビット表現

例)単精度のビットパターン

符号ビット(1ビット)、指数部(8ビット)、仮数部(23ビット)の計32ビット。

 

指数(exponent)

指数部は20乗のとき、0111 1111となる。

指数部の2進数表現

1000 0011       +4

1000 0010       +3

1000 0001       +2

1000 0000       +1

0111 1111       0    (8桁の2進数の真ん中)

0111 1110       -1

0111 1101       -2

0111 1100       -3

 

仮数(mantissa)

仮数部は2を基数として、整数部が一桁になるように正規化した数の2進数表現になる。

正規化によって仮数部の最上位ビットは常に1になるので、実際に用意しておく必要はなく、倍精度の52ビットであれば、最上位の1隠しビットhidden bit)にして含めなければ、53ビット分の情報を含めることになる。

 

少数の2進数表現

0.1000          1/2             = 0.5

0.0100          1/(2*2)         = 0.25

0.0010          1/(2*2*2)       = 0.125

0.0001          1/(2*2*2*2)     = 0.0625

 

IEEE754フォーマットの例

例えば、21.6875を単精度浮動小数点表示すると、

21.6875 = (0001 0101.1011)2     2進数表現)

= (1.01011011)2×2^4    (正規化:小数点の位置を左に4桁ずらし、2のべき乗を4とする)

となるので、

仮数部:1.01011011

指数部:4

符号:正

より、

(符号ビット)    (指数部)      (仮数部)

0               | 1000 0011     | 010 1101 1000 0000 0000 0000

が単精度浮動小数点数表示となる。

 

基本データ型のリテラル値

リテラルとは、ソースコード内に記述する基本データ型の値。

 

10進リテラル:int ten = 10;

8進リテラル:int eight = 010;           (数値の先頭に0を置く)

16進リテラル:int sixteen = 0x10;               (数値の先頭に0xを置く)

注)int fourteen = 0XE;は有効。long fifteen = 0xeL;も有効(Lの代わりに小文字のlも有効)

double d = 113.988は有効(浮動小数点のリテラルはデフォルトではdouble

double d = 113.988dまたはdouble d = 113.988Dはともに有効だがこのdまたはDは必須ではない

floatのリテラルを代入する場合は末尾にFまたはfが必要、よってfloat f = 113.988はコンパイルエラー。float g = 113.988fは有効

int mio = 1,000,000;は無効(カンマはリテラルには使えない)

double d = .5;は有効(.の前の0は省略可)

double d2 = 3E+10は有効(nE+yという表現は、数の浮動少数表現であり、n*10^yを表す。この場合3*10^10 = 30000000000となり、double型の範囲であるので正しい)

char c1 = \uabcd’は有効(Unicodeは単一引用符で囲まれ、\uプレフィックスで始まり、4桁の16進数で表される)

リテラル整数は常に暗黙的にint型になる

 

配列の宣言、作成、初期化

Javaの配列はオブジェクトである。テーマは3つ。

 

l         配列参照変数を作成する方法(宣言)

l         配列オブジェクトを作成する方法(作成)

l         配列に要素を格納する方法(初期化)

 

配列の宣言

int[] key;    // 有効(かつ推奨)

int key[];    // 有効

配列の宣言にサイズを含めることは出来ない。

int[5] key;   // 無効

 

配列の作成

作成時にはサイズが必要。

int[] key;

key = net int[4];                       // 有効

Thread[] threads = new Thread[4];       // 有効

ただし、この時点ではThreadのコンストラクタは呼び出されない。

 

配列の初期化

オブジェクトの配列である場合、配列の各要素は実際のオブジェクトではなく、オブジェクトを指す参照を格納する。(これは非基本データ型の変数が、オブジェクトそのものを格納するのではないのと同様)

String[] strings = new String[5];       // Stringオブジェクトを指す5つの参照を格納する配列

(問題)実際に本物のStringオブジェクトを指しているのか?(それともnullか?)

オブジェクトが参照されていない参照は、null参照

この時点では、stringsの各要素はnullを参照している。

strings[0].length();            // NullPointerExceptionが発生する

strings[0] = new String();      // 初期化処理が必要

 

配列オブジェクトのpublic変数lengthで配列の長さが確認できる。

 

省略構文

        int x = 9;

        int[] array = { 1, 2, x, 6 };

 

無名配列

        Object os = new Object[] {null, new Object(), new Object()};    // 有効

無名配列構文を使うときはサイズを指定してはならない。

        Object os = new Object[3] {null, new Object(), new Object()};   // 無効

無名配列は配列を直接メソッドの引数内で作成するときなどに使える。

 

配列要素への代入

配列の要素である参照変数に代入できるものであれば代入が可能。

l         暗黙の型変換をする整数(int型の変数をlong型の要素に)

l         派生クラスのオブジェクト型(Derived型の変数をBase型の要素に)

l         実装クラスのオブジェクト型(Implemented型の変数をBase型の要素に)

 

配列を配列参照変数に代入

値型の配列には、同じ値型の配列参照変数しか代入できない

オブジェクト型の配列には、そのオブジェクトを継承もしくは実装しているオブジェクト型(IS-A)の配列参照変数を代入できる

 

未初期化または未代入の変数/配列要素

基本データ型とオブジェクト型のデフォルト値

デフォルト値

オブジェクト参照

null (どのオブジェクトも参照しない)

byte, short, int, long

0

float, double

0.0

boolean

false

char

'\u0000'

 

インスタンス変数:新しいインスタンスが作成されるたびに、デフォルト値に初期化される。

配列インスタンス変数:新しいインスタンスが作成されるたびに、nullに初期化される。

(配列変数が初期化されると、配列内の要素はデフォルト値に初期化される)

ローカル変数:基本データ型を含め、使う前に必ず初期化しなくてはならない。

(宣言しただけでは初期化されず、初期化しないで使おうとするとコンパイルエラーが発生する)

ローカルなオブジェクト参照変数は初期化しないと、デフォルト値が設定されず、その変数にはいかなる値も含まれないことになる。

ローカル配列参照変数:使う前に初期化が必要。しかし、配列要素は配列参照変数の初期化時点でデフォルト値に設定される。

複雑な例)

public class ArrayTest {

       public static void main(String[] args) {

              Dog[][] theDogs = new Dog[3][];

              System.out.println(theDogs[2][0].toString());

       }

}

class Dog {}

これは有効な文(コンパイル可能)である。theDogs[2][0]はその一行前の文でnullに初期化されているので、この場合実行時にNullPointerExceptionが発生する。

要は、この場合このローカルメソッド内の配列参照変数の要素はすでに初期化されていると見抜く必要がある。

 

自己診断テスト(第1章 言語の基礎)

 

2.宣言とアクセス制御

 

クラス宣言と修飾子

クラスのアクセス修飾子:public、(デフォルト)

メソッドのアクセス修飾子:public, protected, (デフォルト),private

クラスのその他の修飾子:abstract, final, strictfp

注)finalabstractを同時には適用できない。

 

public:         あらゆるクラスからアクセス可能

protected:      同一パッケージ内のクラス、もしくは継承したクラスからのみアクセス可能

デフォルト:     同一パッケージ内のクラスからのみアクセス可能

private:                同一クラスからのみアクセス可能

 

注)ローカル変数にはアクセス修飾子は適用できない。

 

abstractメソッド:

スーパークラスはそのメソッドが各サブクラスでどのような動作をするか何も知らない

l         finalと併用できない

l         privateと併用できない

l         synchronizedと併用できない

l         strictfpと併用できない

l         nativeと併用できない

 

変数宣言

インスタンス変数:

l         4種類のアクセスレベルのどれを使っても良い

l         finalで修飾できる

l         transientで修飾できる

l         abstractでは修飾できない

l         synchronizedでは修飾できない

l         strictfpでは修飾できない

l         nativeでは修飾できない

 

ローカル変数:

l         finalでのみ、修飾できる

 

ファイナル変数:明示的に初期化した後に、再び初期化できなくなる。

基本データ型:値が不変

         オブジェクトデータ型:変数の指すオブジェクトを変えることは出来ないが、オブジェクトの持つプロパティを変更することは出来る。

         ファイナルインスタンス変数:コンストラクタ終了時までに明示的に初期化する必要がある。

(ファイナル変数には、たとえそれがインスタンス変数だとしても、デフォルト値が与えられない)

 

適用できる修飾子

クラス

メソッド

インスタンス変数

ローカル変数

public

 

(default)

 

protected

 

 

private

 

 

final

abstract

 

 

synchronized

 

 

 

volatile

 

 

 

strictfp

 

 

native

 

 

 

transient

 

 

 

static

 

 

 

静的メソッドと静的変数:

l         インスタンス変数、インスタンスメソッドにアクセスできない

l         スタティックメソッドはオーバーライドできない

l         メソッドに適用可能

l         インスタンス変数に適用可能

l         最上位のネストクラスに適用可能

l         コンスタトラクタには適用不可

l         クラスには適用不可

l         インタフェースには適用不可

l         インナークラスには適用不可、ただし静的ネストクラス(またの名をトップレベルネストクラス)には適用可能

l         インナークラスのメソッドと変数には適用不可

l         ローカル変数には適用不可

 

static

可否

インスタンス変数へのアクセス

×

インスタンスメソッドへのアクセス

×

スタティックメソッドの多態性の適用

×

メソッドへの適用

インスタンス変数への適用

最上位のネストクラス

コンスタトラクタ

×

クラス

×

インタフェース

×

インナークラス(静的ネストクラスを除く)

×

インナークラスのメソッドと変数

×

ローカル変数

×

synchronizedとの併用

finalとの併用

abstractとの併用

×

 

 

インタフェース宣言:

l         インタフェースメソッドはすべて、public abstract

l         インタフェースメソッドはstaticであってはならない

l         インタフェース内で定義するすべての変数は、public static finalのみ。つまり、定数である

l         インタフェースは他のインタフェースから拡張(extends)出来る

l         インタフェースは他のインタフェースを実装(implements)出来ない

自己診断テスト(第2章 宣言とアクセス制御)

 

3.演算子と代入

Javaの演算子はオーバーロードすることができない。

(ただしStringの+結合演算子を除く)

 

基本型の代入

リテラル整数は常にint

int型と同じサイズまたはそれより小さい型が関わる式の結果は常にint

        浮動小数点リテラルは暗黙的にdouble

        複合演算子+=を使うと、明示的にキャストしなくても値を加算できる

 

instanceof比較

        nullもテストできる      (常に結果はfalse

 

算術演算子

        整数は0除算できない    ArithmaticException

        剰余演算子の右辺を0にしても、0除算と同じ結果になる (整数:ArithmaticException、浮動小数:正もしくは負の無限大またはNaN

        浮動小数の0除算の結果は、

        正の数 / 0 = Infinity   (正の無限大)

        負の数 / 0 = -Infinity  (負の無限大)

        0 / 0 = Nan             (数ではない)

 

シフト演算子

>>  : 右シフト

<<  : 左シフト

>>> : 符号無し右シフト(0補充右シフトとも呼ばれる。結果は常に正になる)

シフト演算子は整数に対してのみ作用する。

 

1-102ビット左シフト

i = -10;

i <<+ 2;

10:     0000 0000 0000 0000 0000 0000 0000 1010

Rev:    1111 1111 1111 1111 1111 1111 1111 0101

+1:     1111 1111 1111 1111 1111 1111 1111 0110 (-10)

<< 2:   1111 1111 1111 1111 1111 1111 1101 1000 (This is answer! but what ? -> -40)

-1:     1111 1111 1111 1111 1111 1111 1101 0111

Rev:    0000 0000 0000 0000 0000 0000 0010 1000 (32+8 = 40)

 

2-1003ビット符号無し右シフト

i = -100;

i >>> 3;

100:    0000 0000 0000 0000 0000 0000 0110 0100 (64+32+4)

Rev:    1111 1111 1111 1111 1111 1111 1001 1011

+1:     1111 1111 1111 1111 1111 1111 1001 1100 (-100)

>>> 3:  0001 1111 1111 1111 1111 1111 1111 0011 (This is answer! but what ? -> 536,870,899)

 

                 1 * 16^7

                15 * 16^6

                15 * 16^5

                15 * 16^4

                15 * 16^3

                15 * 16^2

                15 * 16^1

                 3 * 16^0

 

3-10004ビット右シフト

i = -1000;

i >> 4;

1000:   0000 0000 0000 0000 0000 0011 1110 1000 (512+256+128+64+32+8)

Rev:    1111 1111 1111 1111 1111 1100 0001 0111

+1:     1111 1111 1111 1111 1111 1100 0001 1000 (-1000)

>> 4:   1111 1111 1111 1111 1111 1111 1100 0001 (This is answer! but what ? -> -63)

-1:     1111 1111 1111 1111 1111 1111 1100 0000

Rev:    0000 0000 0000 0000 0000 0000 0011 1111 (32+16+8+4+2+1 = 63)

 

メモ)たまたま動いてしまった紛らわしい記法

       i = -10;

       i = i <<+ 2;

       System.out.println(i);

これはただ単に、

        i = i << +2;

であって、iを左に+2分だけシフトしているに過ぎず、特別な演算子でも何でもない。

 

シフトする数値のビットよりも多くの桁数をシフトしようとした場合

「シフトされるビット数は右オペランドをその基本型のビット数で割った剰余になる」

int x = 2;

x >> 34; => x >> 2 //(=34%32);

 

ビット演算子

l         &   (AND)   ビットの両方が1なら1

l         |   (OR)    ビットの片方が1なら1

l         ^   (XOR)   それぞれのビットが異なれば1

l         ~           ビットを反転させる演算子

 

論理演算子

短絡論理演算子と非短絡論理演算子がある。

短絡論理演算子には、&&演算子(AND)と||演算子(OR)がある。

l         &&演算子は左のオペランドがfalseの場合、右のオペランドの評価をしない。(結果はfalse)

l         ||演算子は左のオペランドがtrueの場合、右のオペランドの評価をしない。(結果はtrue)

l         &&演算子は、||演算子に優先して評価される。

(true || false && true && false) = true (false if from left)

 

非短絡論理演算子には、&演算子(AND)と|演算子(OR)がある。

l         &演算子は、|演算子に優先して評価される。

(true | false & true & false) = true   (false if from left)

 

メソッドに変数を渡す

Javaのメソッドでは値渡しが使われる

しかし、これは参照変数の参照先のビットパターンが値渡し(変数のコピー渡し)で渡されるという意味であり、渡し元の参照変数と渡し先の参照変数はそれぞれヒープ上の同一オブジェクトを指すことになるので、いかにも参照渡しされているように見えるがそうではない。

基本型変数と参照変数のどちらを渡す場合でも例外はなく、常に変数の中のビットパターンのコピーが渡される。

 

 

自己診断テスト(第3章 演算子と代入)

 

4.フロー制御、例外、アサーション

 

if

else句は、そのelse句よりも前にあり、対応するelse句を持たない最も近くのif文に対応する。

 

switch

l       switch文で評価されるのは、int型(暗黙的にキャストできる変数と値のみ評価可能)

l       case句の引数は、finalかつコンパイル時定数でなくてはならない

l       switch文では、等価性しか評価できない

l       case句の引数が、switch文で指定された引数の取り得る値の範囲を超えてはならない

例)

byte a;

switch (a) {

case 1:         // 有効

case 128:       // 無効(byteの最大値は127

l         case句の引数は、同じ値を取る事は出来ない

l         case文の中の注括弧は必要ない

 

whileループ、forループ、do-whileループ

ラベル付のcontinue文とbreak文を使うことが出来る。

 

例外処理

finallyブロック内のコードは、直前のtryブロックで例外が投げられたかにかかわらず、必ず実行される。

tryブロック内にreturn文がある場合でも、return文の直後にfinallyブロックが実行される。

複数の例外ハンドラを記述するときは、より具体的な例外ハンドラを先に書かなくてはならない。

RuntimeExceptionErrorおよびこれらのサブクラスは、宣言および例外処理を書く必要のない「非チェック例外」

それ以外の例外はすべて、宣言もしくは例外処理を書く必要のある「チェック例外」

自己診断テスト(第4章 フロー制御、例外、アサーション

 

5.オブジェクト指向、オーバーロード、オーバーライド、コンストラクタ、戻り値型

 

IS-A関係

B extends A => B IS-A A

C extends B => C IS-A A

 

HAS-A関係

BAのインスタンスをメンバに持つ場合、A HAS-A B

 

オーバーライド

l         コンストラクタはオーバーライドできない。(当たり前)

l         finalメソッドはオーバーライドできない。

l         オーバーライドする側(サブクラス)のメソッドでは、オーバーライドされる側(スーパークラス)のメソッドよりも制限の厳しいアクセス修飾子を使うことは出来ない。

protected宣言されたメソッドをオーバーライドして、privateにすることは出来ない。ただし、publicにすることはできる)

l         オーバーライドする側のメソッドは、新しいチェック例外や、オーバーライドされる側のメソッドよりも範囲の広いチェック例外を投げてはならない。(狭めたり、減らすことは出来る)

l         privateメソッドはオーバーライドできない。(当たり前)

 

 

オーバーロード

l         引数リストを変えなくてはならない。

 

どのオーバーライドメソッドを呼び出すかの判断は、実行時オブジェクト型に基づいて行われるが、

どのオーバーロードメソッドを呼び出すかの判断は、コンパイル時参照型に基づいて行われる。

 

コンストラクタとインスタンス化

l         コンパイラはクラスにコンストラクタが一つもない場合、デフォルトコンストラクタをコンパイル時に作成、挿入する。

l         デフォルトコンストラクタには引数はない。

l         コンパイラはコンストラクタが最初の行でスーパークラスのコンストラクタを呼んでいない場合、super()を挿入する。

l         コンストラクタは継承されない。

l         スーパークラスに引数のないコンストラクタがない場合、サブクラスのコンストラクタでは明示的にsuper(<引数リスト>)を呼ばなくてはならない。

l         コンストラクタの1行目は、this()もしくはsuper()でなくてはならない。

 

自己診断テスト(第5章 オブジェクト指向、オーバーロード、オーバーライド、コンストラクタ、戻り値型)

 

6.java.langMathクラス、Stringクラス、ラッパー

 

Stringは不変のオブジェクト

l         Stringオブジェクトは不変だが、それを参照する変数はどのStringオブジェクトを参照するか随時変更可能

l         JVMは「String定数プール」と呼ばれる特別なメモリ領域を確保し、コンパイラはコードの中にStringリテラルを見つけるとこのプールをチェックする。同じStringがあれば、新しい参照を既存のStringリテラルと結びつけ、新しいStringリテラルは作成しない。

l         newを使ってStringオブジェクトを作ると標準の(プールでない)メモリ上にオブジェクトが作成される。例えば、

String s = new String(abc);

この場合、”abc”がプール上に作成されるが、右辺のStringオブジェクトは標準メモリ上に作成され、それを参照変数sが参照する。

 

Mathクラスの特殊ケース

コード例

float p_i = Float.POSITIVE_INFINITY;             // floatdoubleは正の無限大をサポート

double n_i = Double.NEGATIVE_INFINITY;           // floatdoubleは負の無限大をサポート

double notanum = Double.NaN;                     // floatdoubleNaNをサポート

 

if (notanum != notanum) {                        // NaNは何と比較しても==にならない

       System.out.println("NaNs not equal");

}

 

if (Double.isNaN(notanum)) {                     // DoubleFloatNaNかどうかを判定するメソッドを持つ

       System.out.println("got a NaN");

}

 

double d = Math.sqrt(n_i);                      

if (Double.isNaN(d)) {

       System.out.println("got sqrt NaN");       // 負の無限大の平方根はNaN

}

 

System.out.println(Math.sqrt(-16d));             // 結果はNaN

System.out.println(16d/0);                       // 結果はInfinity

System.out.println(-16d/0);                      // 結果は-Infinity

 

try {

       System.out.println(16/0);                 // 整数は0除算できない

} catch (ArithmeticException ae) {

       System.err.println(ae.getMessage());      // 結果は例外 "/ by zero"

}

 

double n = 0.0 / 0.0;                            // 0.0 / 0.0 NaN

if (Double.isNaN(n)) {

       System.out.println("0.0 / 0.0 is NaN");

}

 

int i_min = Integer.MIN_VALUE;                   // 整数のラッパーはMIN_VALUEMAX_VALUEをサポート

System.out.println(i_min);

System.out.println(Math.abs(i_min));             // abs()MIN_VALUEには負の数を返す

 

 

ラッパークラス

l         ラッパーオブジェクトも不変

l         ラッパーオブジェクトを作成するには、

Ø         (intなどの)基本型の引数をラッパーオブジェクトのコンストラクタに渡す

Ø         String型引数をラッパーオブジェクトのコンストラクタに渡す

Ø         valueOf()メソッドを使う

 

ラッパーの変換機能

要するにラッパー変換メソッドのシグネチャは以下の3種類

l         primitive xxxValue()

l         primitive parseXxx(String)

l         Wrapper valueOf(String)

 

変数の比較

同じJVM上で動くすべての参照変数は、いずれも同じサイズ(ビット数)と形式を持つので、==演算子を使って2つの参照変数を比較する場合、実際にテストしているのは、

「その2つが同じオブジェクトをさしているかどうか」

である。ただし、==演算子を使って比較できるのは同じクラスまたはクラス階層に属するオブジェクトを指す参照変数に限られる。(違う場合、コンパイルエラーとなる)

 

7.オブジェクトとコレクション

 

equals()メソッドのオーバーライド

equals()メソッドをオーバーライドしないと、オブジェクトをハッシュテーブルのキーとして使えなくなる。

例)Objectクラスのequals()メソッドは内部的には「==演算子」での等価演算を行っているので、参照変数が同じオブジェクトを参照していない限り結果はfalseになる。

問題なのは、Mapなどのコレクションに格納されたオブジェクトを検索したい場合である。Mapからあるオブジェクトを取り出す場合、キーを元に値を取り出すが、このキーが等しいかどうかの判定にJavaequals()メソッドでの判定を行う。このequals()が「==演算子」での比較しか行わない場合、格納されたオブジェクトと等しくなるのは、それを格納した参照変数だけである。

 

一般的なhashCode()のアルゴリズム

-         インスタンス変数を^演算(XOR演算)し、その結果に素数を掛ける。

-         等しい2つのオブジェクトはハッシュコードも等しくなくてはならない。 

-         transient変数はハッシュコードの計算に使用しない(equalsの判定にも使用しない)

 

コレクション

-         ArrayList: 反復処理とランダムアクセスの速度が高速

-          

 

ガ−ベジコレクタ

-         実行中のJavaプログラムから到達不可能になったオブジェクトは削除する

-         いつ実行するかはJVMが決める

-         オブジェクトにアクセスしている生存中のスレッドが1つもないとき、そのオブジェクトはガ−ベジコレクションの対象になる

 

オブジェクトを明示的にガ−ベジコレクタの対称にする

-         参照をnullにする

-         参照変数が別のオブジェクトを参照する(それまで参照されていたオブジェクトは参照されなくなる)

-         メソッドのローカル変数をメソッドの戻り値として使用しない場合

-         オブジェクトを「隔離された島」に閉じ込める(参照が有効な場合でもガ−ベジコレクションの対象になるケース)

class A {

    A a;

 

    public static void main(String[] args) {

            A a1 = new A();

            A a2 = new A();

A a3 = new A();

 

a1.a = a2;

a2.a = a3;

a3.a = a1;

 

a1 = null;

a2 = null;

a3 = null;

 

// a1.aは(まだヒープ上に存在している)a2を指すので有効だが、もはや外界からは(参照変数を通じては)アクセスできない。

}

}

 

ガ−ベジコレクションの強制実行

-         ガ−ベジコレクションを強制実行することは出来ない

-         JVMにガ−ベジコレクションの要求をすることは出来る

 

 

8.インナークラス

インナークラスの特性

- 「通常」のインナークラスはstatic宣言を一切持つことは出来ない

- インナークラスにアクセスするには、アウタークラスのアクティブなインスタンスを使用しなくてはならない

 

アウタークラスのインスタンスコード外でインナークラスのインスタンスを作成する例

public class InnerClassTest {

      

       private int x = 7;

 

       public static void main(String[] args) {

              InnerClassTest ict = new InnerClassTest();

              InnerClassTest.MyInner in = ict.new MyInner();

              in.seeOuter();

       }

 

       class MyInner {

              public void seeOuter() {

                     System.out.println("Outer.x="+x);

              }

       }

}

 

静的ネストクラス

-         トップレベルネストクラスともいう

-         static修飾子を使って宣言できるインナークラスはトップレベルネストクラスのみ(厳密に言えばこれはインナークラスではないのだが)

 

 

9.スレッド

スレッドの作成

スレッドを定義するには、

-         Threadクラスを拡張し、run()メソッドをオーバーライドする

-         Runnableインタフェースを実装し、run()メソッドを定義する

のいずれか。

 

スレッドのインスタンス化

スレッドジョブを実行するには、

-         Threadクラスを拡張したサブクラスをインスタンス化して、start()メソッドを実行する

-         Runnableインタフェースを実装したクラスをThreadクラスのコンストラクタに渡し、Threadクラスをインスタンス化して、start()メソッドを実行する

すると、JVMが新しいスタックを起動し、そこに別のスレッドを起動する。

)ThreadクラスもRunnableインタフェースを実装しているので、ThreadクラスのコンストラクタにThreadクラスを引数として渡すことも出来る

 

スレッドの実行順序

-         各スレッドをそれぞれを起動した順序の通りに実行しなくてはならないという決まりはない

-         いったん終了したスレッドは二度と起動できない

-         実行可能状態のスレッドが実行される順番は決まっていない

-         スレッドスケジューラを制御する手段はない

-         ただしスレッドスケジューラに影響を与えるメソッドは用意されている

-         すべてのスレッドに実行の機会を均等に与えるにはsleep()が最良の方法

 

スレッドの状態

初期状態:Threadオブジェクトのインスタンスが作成されてからstart()が呼び出される前までの状態

実行可能状態:start()が呼び出されてから、run()が実行される前までの状態、または待機状態から復帰し実行する前段階の状態

実行中状態:run()開始され、終了するまでのうち、実際に実行されている状態

終了状態:run()が終了した状態(このスレッドは二度と起動できない)

待機状態/ブロック状態/スリープ状態:スレッドは生存しているものの、現在は実行対象としての資格を有していない状態、言い換えれば実行可能状態ではないが、何らかのイベントが発生すれば実行可能状態に戻る可能性がある状態

 

 

スレッドスケジューラ

適格なスレッドの中からどのスレッドを実行するかを決定する

 

スレッドの優先順位とyield()メソッド

現在実行中のスレッドの優先順位は、実行可能プール内のスレッドよりも低くなることはなく、実行可能プール内でもっとも優先順位の高いスレッドと同じかそれよりも高い優先順位になる。

ただし、スレッド優先順位の動作が保証されているわけではなく、これに基づいてプログラムの動作を決めるのは避けなくてはいけない。

 

スレッドを実行中状態から解放するには

-         sleep()メソッドを呼び出す:現在実行中のスレッドは少なくとも指定の時間だけ実行を抑制する

-         yield()メソッドを呼び出す:必ずそうなるわけではないが、現在実行中のスレッドが実行可能状態に戻り、優先順位の高いほかのスレッドが実行機会を得る

-         join()メソッドを呼び出す:現在実行中のスレッドはjoin()メソッドの呼び出しに使用したスレッドが完了するまで実行を抑制する

 

メソッドとロックの状態

ロックを解放するメソッド

ロックを保持するメソッド

定義されているクラス

wait()

notify()

ただし、スレッドはこのメソッドを呼び出すとすぐに同期コードを抜けるので、結局はロックを解放することになる

java.lang.Object

 

join()

java.lang.Thread

 

sleep()

java.lang.Thread

 

yield()

java.lang.Thread

 

同期メソッドの呼び出し

- wait(), notify(), notifyAll()メソッドはsynchronizedメソッド内、もしくはsynchronizedブロック内で呼び出す必要がある。

これは、これらのメソッドが呼び出し対象のオブジェクトのロックを獲得していない状態で呼び出された場合、IllegalMonitorStateExceptionを投げるからである。

(ただしIllegalMonitorStateExceptionは非チェック例外なので、try/catchで囲む必要はない)

- また、wait()メソッドはInterruptedExceptionチェック例外を投げるので、これはtry/catchで囲む必要がある。

 

(参考文献)Sun Java2認定ガイド(日経BP社)