プリミティブ変数
型 ビット数
byte 8
short 16
int 32
long 64
float 32
double 64
プリミティブ変数のデフォルト値は 0 (0.0) です。
10進数
int cnt = 7;
int cnt = 7,2 (カンマを使っているのでコンパイルエラー)
8進数
先頭に 0 をつける
int seven = 07; (10進数の7)
int eight = 010; (10進数の8)
int nine = 011; (10進数の9)
16進数
先頭に 0x をつける
10進数の 1~15 までは0 1 2 3 4 5 6 7 8 9 a b c d e fで表す。
アルファベットは大文字小文字の区別なし。
サフィックス
double d = 1.2d;
float f = 1.2f;
long l = 100000l;
2007年10月15日月曜日
boolean 型と char 型
boolean 型
true か false を格納
デフォルト値は false
if 文の条件になる
(例)
if (1 < 10) {};
char 型
1つの文字、Unicode、16ビット符号なし整数(65535以下の正の整数)が使用できる。
(例)
char name = '円';
char name = '\u004F';
デフォルト値は \u0000
true か false を格納
デフォルト値は false
if 文の条件になる
(例)
if (1 < 10) {};
char 型
1つの文字、Unicode、16ビット符号なし整数(65535以下の正の整数)が使用できる。
(例)
char name = '円';
char name = '\u004F';
デフォルト値は \u0000
ラベル:
Java 基本メモ
String 型
String 型はダブルクウォーテーションで囲む。
String 型は他のクラスと違いダブルクウォーテーションで囲む方法でインスタンスを生成できる。
その後同じ名前をダブルクウォーテーションで囲んで違う変数名で宣言した場合、すでにプールに納められている同じ文字を格納する String 型インスタンスが使われます。これは他のクラスにはない特殊な例です。
<サンプル>
String name1 = "Albert";
String name2 = new String("Albert");
String name3 = "Albert";
System.out.println(name1 == name2);
System.out.println(name1 == name3);
System.out.println(name1 == name3);
<出力結果>
false
true
false
String 型は他のクラスと違いダブルクウォーテーションで囲む方法でインスタンスを生成できる。
その後同じ名前をダブルクウォーテーションで囲んで違う変数名で宣言した場合、すでにプールに納められている同じ文字を格納する String 型インスタンスが使われます。これは他のクラスにはない特殊な例です。
<サンプル>
String name1 = "Albert";
String name2 = new String("Albert");
String name3 = "Albert";
System.out.println(name1 == name2);
System.out.println(name1 == name3);
System.out.println(name1 == name3);
<出力結果>
false
true
false
ラベル:
Java 基本メモ
1次元配列
配列の宣言
要素数を必ず宣言して初期化する。
各要素は0で初期化される。
int[] myArray = new int[3];
宣言と代入
int[] myArray = {1, 2, 3};
配列はオブジェクトとして扱われる
Integer[] myArray = new Integer[3];
配列はオブジェクトとして扱われているが、Interger クラスのコンストラクタは呼び出されず、各要素は null で初期化される。
<サンプル>
Integer[] myArray = new Integer[3];
System.out.println(myArray[2]);
<出力結果>
null
要素数を必ず宣言して初期化する。
各要素は0で初期化される。
int[] myArray = new int[3];
宣言と代入
int[] myArray = {1, 2, 3};
配列はオブジェクトとして扱われる
Integer[] myArray = new Integer[3];
配列はオブジェクトとして扱われているが、Interger クラスのコンストラクタは呼び出されず、各要素は null で初期化される。
<サンプル>
Integer[] myArray = new Integer[3];
System.out.println(myArray[2]);
<出力結果>
null
ラベル:
Java 基本メモ
2次元配列
2次元配列は1次元配列の各要素にさらに1次元配列が収められています。
2次元配列の初期化
int[][] myArray = new int[3][];
2次元配列の最初の要素数を指定して初期化します。
各要素は null で初期化されます。
値の代入
int[][] myArray = new int[2][2];
myArray[0][0] = 1;
...
myArray[1][1] = 4;
int[][] myArray = new int[2][];
myArray[0] = {1, 2};
myArray[1] = {3, 4};
int[][] myArray = {{1, 2}, {3, 4}};
2次元配列の初期化
int[][] myArray = new int[3][];
2次元配列の最初の要素数を指定して初期化します。
各要素は null で初期化されます。
値の代入
int[][] myArray = new int[2][2];
myArray[0][0] = 1;
...
myArray[1][1] = 4;
int[][] myArray = new int[2][];
myArray[0] = {1, 2};
myArray[1] = {3, 4};
int[][] myArray = {{1, 2}, {3, 4}};
ラベル:
Java 基本メモ
オブジェクト参照変数
オブジェクト参照変数
<サンプル>
public class Sample {
public static void main(String[] args) {
Sub objSub = new Sub();
Super objSup = objSub;
}
}
class Super { }
class Sub extends Super { }
objSub, objSup はオブジェクト参照変数です。メモリー上にあるインスタンスを参照する変数(オブジェクト)です。
<サンプル>
public class Sample {
public static void main(String[] args) {
Sub objSub = new Sub();
Super objSup = objSub;
}
}
class Super { }
class Sub extends Super { }
objSub, objSup はオブジェクト参照変数です。メモリー上にあるインスタンスを参照する変数(オブジェクト)です。
ラベル:
Java 基本メモ
インスタンス変数
クラスのメソッドの外側で宣言した変数はインスタンス変数としてオブジェクト参照変数からアクセスできます。
インスタンス変数は自動で初期化されます。
<サンプル>
public class Sample {
public static void main(String[] args) {
Sub objSub = new Sub();
Super objSup = objSub;
System.out.println(objSub.x);
System.out.println(objSup.x);
}
}
class Super {int x;}
class Sub extends Super {int x;}
インスタンス変数は自動で初期化されます。
<サンプル>
public class Sample {
public static void main(String[] args) {
Sub objSub = new Sub();
Super objSup = objSub;
System.out.println(objSub.x);
System.out.println(objSup.x);
}
}
class Super {int x;}
class Sub extends Super {int x;}
ラベル:
Java 基本メモ
Java 予約語
変数名、メソッド名などに Java 予約語は使用できません。
Java 予約語一覧
abstract
boolean
break
byte
case
catch
char
class
const
continue
default
do
double
else
extends
final
finally
float
for
goto
if
implements
import
instanceof
int
interface
long
native
new
package
private
protected
public
return
short
static
strictfp
super
switch
synchronized
this
throw
throws
transient
try
void
volatile
while
assert
Java 予約語一覧
abstract
boolean
break
byte
case
catch
char
class
const
continue
default
do
double
else
extends
final
finally
float
for
goto
if
implements
import
instanceof
int
interface
long
native
new
package
private
protected
public
return
short
static
strictfp
super
switch
synchronized
this
throw
throws
transient
try
void
volatile
while
assert
ラベル:
Java 基本メモ
クラスの構造
<サンプル>
package sample;
import java.util.*;
public class MyClass {
int x;
public static void main(String[] args) {
MyClass obj = new MyClass();
obj.func1();
}
void func1() {
System.out.println(func2());
}
int func2() {
return 100;
}
}
パッケージの宣言
クラスはパッケージで管理することが推奨されています。
インポート宣言
Java のクラスライブラリで java.lang パッケージ以外のライブラリはインポートする必要があります。
java.util.*; とすると java.util パッケージのすべてのインターフェース、クラスのインポートを宣言します。
java.util.Date; とすると java.util.Date クラスのインポートを宣言します。
main メソッド
Java プログラムは main メソッドからスレッドがスタートします。
main メソッドは
public static void main(String[] args)
というシグネチャですが args の部分は任意です。
main メソッドなどの静的メソッド(static メソッド)から自クラスの動的メソッドを呼び出す場合、自クラスのインスタンス(参照変数)から呼び出す必要があります。
(例)
MyClass obj = new MyClass();
obj.func1();
自クラスの動的メソッドから動的メソッドを呼び出す場合は、メソッド名を記述するだけです。
(例)
void func1() {
func2();
}
package sample;
import java.util.*;
public class MyClass {
int x;
public static void main(String[] args) {
MyClass obj = new MyClass();
obj.func1();
}
void func1() {
System.out.println(func2());
}
int func2() {
return 100;
}
}
パッケージの宣言
クラスはパッケージで管理することが推奨されています。
インポート宣言
Java のクラスライブラリで java.lang パッケージ以外のライブラリはインポートする必要があります。
java.util.*; とすると java.util パッケージのすべてのインターフェース、クラスのインポートを宣言します。
java.util.Date; とすると java.util.Date クラスのインポートを宣言します。
main メソッド
Java プログラムは main メソッドからスレッドがスタートします。
main メソッドは
public static void main(String[] args)
というシグネチャですが args の部分は任意です。
main メソッドなどの静的メソッド(static メソッド)から自クラスの動的メソッドを呼び出す場合、自クラスのインスタンス(参照変数)から呼び出す必要があります。
(例)
MyClass obj = new MyClass();
obj.func1();
自クラスの動的メソッドから動的メソッドを呼び出す場合は、メソッド名を記述するだけです。
(例)
void func1() {
func2();
}
ラベル:
Java 基本メモ
final クラスと abstract クラス
final で修飾されたクラス
・継承(拡張)することができないのでサブクラスを作成できない。
・したがってどのメソッドもオーバーライドできない。
String クラスなどは final クラスです。
abstract クラス(抽象クラス)
abstract で修飾されたクラス
・インスタンス化できない。
・継承されることを目的とする
・abstract メソッド(抽象メソッド)を含むクラスは必ず abstract クラス(抽象クラス)である必要がある。
・抽象クラスに非抽象メソッドを含めることはできる。
<サンプル>
public class Sample {
public static void main(String[] args) {
Super obj = new Sub();
obj.func();
}
}
abstract class Super {
abstract void func();
}
class Sub extends Super {
@Override
void func() {}
}
・継承(拡張)することができないのでサブクラスを作成できない。
・したがってどのメソッドもオーバーライドできない。
String クラスなどは final クラスです。
abstract クラス(抽象クラス)
abstract で修飾されたクラス
・インスタンス化できない。
・継承されることを目的とする
・abstract メソッド(抽象メソッド)を含むクラスは必ず abstract クラス(抽象クラス)である必要がある。
・抽象クラスに非抽象メソッドを含めることはできる。
<サンプル>
public class Sample {
public static void main(String[] args) {
Super obj = new Sub();
obj.func();
}
}
abstract class Super {
abstract void func();
}
class Sub extends Super {
@Override
void func() {}
}
ラベル:
Java 基本メモ
インターフェース
インターフェースの目的は抽象クラスと似ていますがすべてのメソッドが abstract です。
インターフェースのメソッドは中身を実装しません。したがってインターフェースの役割は、それを実装するクラスの方向性を定め柔軟な設計を可能にすると言うことができます。
インターフェースの変数
public static final でなければならい。省略は可能でコンパイラが補足する。
インターフェースの変数は「定数」として利用できる。
インターフェースのメソッド
public abstract でなければならない。省略は可能でコンパイラが補足する。
インターフェースの定義
interface で定義します。
インターフェースの実装
implements で定義します。
複数のインターフェースを実装できます。
インターフェースは他のインターフェースを継承できます。
インターフェースAを継承するインターフェースαを実装しているサブクラスはインターフェースαのメソッドだけでなくインターフェースAのメソッドも実装しなければならない。
<サンプル>
interface Human {
void speak();
}
class Japanese implements Human{
public void speak() {
System.out.println("こんにちは");
}
}
class English implements Human {
public void speak() {
System.out.println("Hello");
}
}
public class Sample {
public static void main(String[] args) {
Human person1 = new Japanese();
Human person2 = new English();
person1.speak();
person2.speak();
}
}
<出力結果>
こんにちは
Hello
Human クラスを実装(implements)するサブクラスは必ず speak メソッドを実装しなければなりせん。
Human インターフェースを実装することで Japanese クラス、English クラスは同じ特性を持つことになります。
person1.speak();
person2.speak();
ではそれぞれ Japanese クラスと English クラスでオーバーライドされた speak メソッドが呼び出されています。
これは「多様性」といいます。
インターフェースのメソッドは中身を実装しません。したがってインターフェースの役割は、それを実装するクラスの方向性を定め柔軟な設計を可能にすると言うことができます。
インターフェースの変数
public static final でなければならい。省略は可能でコンパイラが補足する。
インターフェースの変数は「定数」として利用できる。
インターフェースのメソッド
public abstract でなければならない。省略は可能でコンパイラが補足する。
インターフェースの定義
interface で定義します。
インターフェースの実装
implements で定義します。
複数のインターフェースを実装できます。
インターフェースは他のインターフェースを継承できます。
インターフェースAを継承するインターフェースαを実装しているサブクラスはインターフェースαのメソッドだけでなくインターフェースAのメソッドも実装しなければならない。
<サンプル>
interface Human {
void speak();
}
class Japanese implements Human{
public void speak() {
System.out.println("こんにちは");
}
}
class English implements Human {
public void speak() {
System.out.println("Hello");
}
}
public class Sample {
public static void main(String[] args) {
Human person1 = new Japanese();
Human person2 = new English();
person1.speak();
person2.speak();
}
}
<出力結果>
こんにちは
Hello
Human クラスを実装(implements)するサブクラスは必ず speak メソッドを実装しなければなりせん。
Human インターフェースを実装することで Japanese クラス、English クラスは同じ特性を持つことになります。
person1.speak();
person2.speak();
ではそれぞれ Japanese クラスと English クラスでオーバーライドされた speak メソッドが呼び出されています。
これは「多様性」といいます。
ラベル:
Java 基本メモ
演算子
代入演算子
x = y (x に y を代入)
x += y (x = x + y)
x -= y (x = x - y)
x *= y (x = x * y)
x /= y (x = x / y)
x %= y (x = x % y)
インクリメント・デクリメント
x++ (x = x + 1) x を利用してからインクリメント
x-- (x = x - 1) x を利用してからデクリメント
++x (x = x + 1) x をインクリメントしてから利用
--x (x = x - 1) x をデクリメントしてから利用
論理演算子
x & y x と y が true の場合 true を返す
x y x か y のとちらかが true の場合 true を返す
x ^ y 排他的論理輪
!x x でない場合 true を返す
x && y x と y が true の場合 true を返す
左辺が false の場合右辺を評価しない
x y x と yの どちらかが true の場合 true を返す
左辺が true の場合右辺を評価しない
文字列連結演算子
String s1 = "Hello " + "world"; (Hello world)
String s2 = "Hello " + 100; (Hello 100)
どちらか片方が String の場合 + 演算子は文字列連結演算子となる。
ビットシフト演算子
x >> n x を2の n 乗で割る(右に n ビットシフト)
x << n x に2の n 乗を掛ける(左に n ビットシフト)
x >>> n 右に n ビットシフトして最初の符号を 0 にする
<サンプル>
public class Sample {
public static void main(String[] args) {
int a = 0;
int b = 0;
for (int i = 0; i < 5; i++) {
if ((++a < 2) && (++b < 2)) {
a++;
}
}
System.out.println("a = " + a + " b = " + b);
}
}
<出力結果>
a = 6 b = 3
x = y (x に y を代入)
x += y (x = x + y)
x -= y (x = x - y)
x *= y (x = x * y)
x /= y (x = x / y)
x %= y (x = x % y)
インクリメント・デクリメント
x++ (x = x + 1) x を利用してからインクリメント
x-- (x = x - 1) x を利用してからデクリメント
++x (x = x + 1) x をインクリメントしてから利用
--x (x = x - 1) x をデクリメントしてから利用
論理演算子
x & y x と y が true の場合 true を返す
x y x か y のとちらかが true の場合 true を返す
x ^ y 排他的論理輪
!x x でない場合 true を返す
x && y x と y が true の場合 true を返す
左辺が false の場合右辺を評価しない
x y x と yの どちらかが true の場合 true を返す
左辺が true の場合右辺を評価しない
文字列連結演算子
String s1 = "Hello " + "world"; (Hello world)
String s2 = "Hello " + 100; (Hello 100)
どちらか片方が String の場合 + 演算子は文字列連結演算子となる。
ビットシフト演算子
x >> n x を2の n 乗で割る(右に n ビットシフト)
x << n x に2の n 乗を掛ける(左に n ビットシフト)
x >>> n 右に n ビットシフトして最初の符号を 0 にする
<サンプル>
public class Sample {
public static void main(String[] args) {
int a = 0;
int b = 0;
for (int i = 0; i < 5; i++) {
if ((++a < 2) && (++b < 2)) {
a++;
}
}
System.out.println("a = " + a + " b = " + b);
}
}
<出力結果>
a = 6 b = 3
ラベル:
Java 基本メモ
if 文
if else
if (x == y) {
System.out.println("Hello");
} else {
System.out.println("こんにちは");
}
if 文条件判断結果は boolean 型でなければならない。
if (x = y) { } なら条件判断は行わず代入が行われる。(代入演算子)
if - else if - else
else if を使うと条件分岐を増やすことができる。
if (x == y) {
...
} else if (x == z) {
...
} else {
...
}
if 文のボディを表す { } の中に実行文が1行しかない場合は { } は省略できます。
しかし、可読性が落ちることは確かです。
if (x == y) {
a = b;
}
System.out.println("Hello");
上記と同じ
if (x == y)
a = b;
System.out.println("Hello");
if (x == y) {
System.out.println("Hello");
} else {
System.out.println("こんにちは");
}
if 文条件判断結果は boolean 型でなければならない。
if (x = y) { } なら条件判断は行わず代入が行われる。(代入演算子)
if - else if - else
else if を使うと条件分岐を増やすことができる。
if (x == y) {
...
} else if (x == z) {
...
} else {
...
}
if 文のボディを表す { } の中に実行文が1行しかない場合は { } は省略できます。
しかし、可読性が落ちることは確かです。
if (x == y) {
a = b;
}
System.out.println("Hello");
上記と同じ
if (x == y)
a = b;
System.out.println("Hello");
ラベル:
Java 基本メモ
switch 文
int number = 7;
switch (number) {
case 2:
System.out.println("小吉");
break;
case 5:
System.out.println("中吉");
break;
case 7:
System.out.println("大吉");
break;
default:
System.out.println("吉");
}
条件判断には int 型か int 型に拡張変換できる型(byte, short, char)のみ使用できます。
break キーワードがないとすべてのケースの実行文が実行されます。
default 文の位置は最後でなくてもいいです。
switch (number) {
case 2:
System.out.println("小吉");
break;
case 5:
System.out.println("中吉");
break;
case 7:
System.out.println("大吉");
break;
default:
System.out.println("吉");
}
条件判断には int 型か int 型に拡張変換できる型(byte, short, char)のみ使用できます。
break キーワードがないとすべてのケースの実行文が実行されます。
default 文の位置は最後でなくてもいいです。
ラベル:
Java 基本メモ
ループで使うキーワード
break そのループを即座に抜ける。
continue 現在の反復を中断して次の反復に即座に移る。
ループの中でのみ使用可能。
return 戻り値か無を返してメソッドを終了する。
下記の break キーワードにより "Break " の出力が一回になります。
for ( ) の中の i++ や j++ の処理は for 文のボディでの処理が終わってから実行されます。
したがって i++ と ++i では同じ結果になります。
<サンプル1>
public class Sample {
public static void main(String[] args) {
for (int i = 0; i < 5; i++) {
for (int j = 0; j < i; j++) {
System.out.print("Break ");
break;
}
System.out.println(i);
}
}
}
<出力結果>
0
Break
1
Break
2
Break
3
Break
4
ラベルつきループ
先ほどのサンプルに outer ラベルをつけて break キーワードで即座に outer を抜けてみます。
<サンプル2>
public class Sample {
public static void main(String[] args) {
outer:
for (int i = 0; i < 5; i++) {
for (int j = 0; j < i; j++) {
System.out.println("Break ");
break outer;
}
System.out.println(i);
}
}
}
<出力結果>
0
Break
continue 現在の反復を中断して次の反復に即座に移る。
ループの中でのみ使用可能。
return 戻り値か無を返してメソッドを終了する。
下記の break キーワードにより "Break " の出力が一回になります。
for ( ) の中の i++ や j++ の処理は for 文のボディでの処理が終わってから実行されます。
したがって i++ と ++i では同じ結果になります。
<サンプル1>
public class Sample {
public static void main(String[] args) {
for (int i = 0; i < 5; i++) {
for (int j = 0; j < i; j++) {
System.out.print("Break ");
break;
}
System.out.println(i);
}
}
}
<出力結果>
0
Break
1
Break
2
Break
3
Break
4
ラベルつきループ
先ほどのサンプルに outer ラベルをつけて break キーワードで即座に outer を抜けてみます。
<サンプル2>
public class Sample {
public static void main(String[] args) {
outer:
for (int i = 0; i < 5; i++) {
for (int j = 0; j < i; j++) {
System.out.println("Break ");
break outer;
}
System.out.println(i);
}
}
}
<出力結果>
0
Break
ラベル:
Java 基本メモ
継承(拡張)
オブジェクト指向言語 Java の特徴のひとつに「継承」があます。
継承により、サブクラス(子クラス)はスーパークラス(親クラス)の機能を使用できます。
継承は extends キーワードで宣言します。
class Super {
int super_x;
void sayHello() {System.out.println("Hello");}
void func() {System.out.println("Super");}
}
class Sub extends Super {
int sub_x;
void func() {System.out.println("Sub");}
}
__________________
Sub 型でインスタンスの生成
Sub objSub = new Sub();
スーパークラスのメンバーへアクセス
System.out.println(objSub.super_x);
obj.sayHello();
サブクラスの変数へアクセス
System.out.println(objSub.sub_x);
objSub.func();
Super 型でインスタンスの生成
Super objSuper = new Super();
Super 型からサブクラスのメンバーにはアクセスできない。
__________________
is-a 型でインスタンス生成
継承関係にあるスーパークラスとサブクラスの機能をフルに利用するには下記のようにインスタンスを生成します。
Super obj = new Sub();
Super 型で Sub のインスタンスを生成しています。
この場合、is-a 関係が成り立ちます。
is-a 関係とはその名のとおり Sub is a Super という関係です。
__________________
多様性
Super のメソッド func() は Sub でオーバーライドされています。
obj.func() を呼び出すと Super 型の obj から Sub の func() が呼び出されます。
これを多様性といいます。
多様性はインターフェースとそれを実装するサブクラス間でも利用できます。
このような Super 型の obj から Sub 固有のメソッドを呼び出すことは出来ません。
Sub 固有のメソッドを呼び出すには Sub 型にキャストして呼び出します。
((Sub)obj).subFunc();
__________________
<サンプル>
class Super {
void func() {
System.out.println("Super");
}
}
class Sub extends Super {
@Override
void func() {
System.out.println("Override");
}
void subFunc() {
System.out.println("Sub");
}
public class Sample {
public static void main(String[] args) {
Super obj1 = new Super();
Super obj2 = new Sub();
obj1.func();
obj2.func();
((Sub)obj2).subFunc();
}
}
<出力結果>
Super
Override
Sub
継承により、サブクラス(子クラス)はスーパークラス(親クラス)の機能を使用できます。
継承は extends キーワードで宣言します。
class Super {
int super_x;
void sayHello() {System.out.println("Hello");}
void func() {System.out.println("Super");}
}
class Sub extends Super {
int sub_x;
void func() {System.out.println("Sub");}
}
__________________
Sub 型でインスタンスの生成
Sub objSub = new Sub();
スーパークラスのメンバーへアクセス
System.out.println(objSub.super_x);
obj.sayHello();
サブクラスの変数へアクセス
System.out.println(objSub.sub_x);
objSub.func();
Super 型でインスタンスの生成
Super objSuper = new Super();
Super 型からサブクラスのメンバーにはアクセスできない。
__________________
is-a 型でインスタンス生成
継承関係にあるスーパークラスとサブクラスの機能をフルに利用するには下記のようにインスタンスを生成します。
Super obj = new Sub();
Super 型で Sub のインスタンスを生成しています。
この場合、is-a 関係が成り立ちます。
is-a 関係とはその名のとおり Sub is a Super という関係です。
__________________
多様性
Super のメソッド func() は Sub でオーバーライドされています。
obj.func() を呼び出すと Super 型の obj から Sub の func() が呼び出されます。
これを多様性といいます。
多様性はインターフェースとそれを実装するサブクラス間でも利用できます。
このような Super 型の obj から Sub 固有のメソッドを呼び出すことは出来ません。
Sub 固有のメソッドを呼び出すには Sub 型にキャストして呼び出します。
((Sub)obj).subFunc();
__________________
<サンプル>
class Super {
void func() {
System.out.println("Super");
}
}
class Sub extends Super {
@Override
void func() {
System.out.println("Override");
}
void subFunc() {
System.out.println("Sub");
}
public class Sample {
public static void main(String[] args) {
Super obj1 = new Super();
Super obj2 = new Sub();
obj1.func();
obj2.func();
((Sub)obj2).subFunc();
}
}
<出力結果>
Super
Override
Sub
ラベル:
Java 基本メモ
オーバーライド
スーパークラスのメソッドと同じ名前のメソッドをサブクラスで定義することをオーバーライドといいます。
class Super {
void func() throws IOException {
System.out.println("Super");
}
}
class Sub extends Super {
@Override
void func() {
System.out.println("Sub");
}
}
<ルール>
・ 引数リスト、戻り値型は変更不可。
・ アクセスレベルを緩く出来るが厳しくは出来ない。
・ 新たな例外や、上位クラスの例外を throw できない。
・ 例外の数を減らしたり、下位クラスの例外を throw することは出来る。
・ final メソッドはオーバーライドできない。
class Super {
void func() throws IOException {
System.out.println("Super");
}
}
class Sub extends Super {
@Override
void func() {
System.out.println("Sub");
}
}
<ルール>
・ 引数リスト、戻り値型は変更不可。
・ アクセスレベルを緩く出来るが厳しくは出来ない。
・ 新たな例外や、上位クラスの例外を throw できない。
・ 例外の数を減らしたり、下位クラスの例外を throw することは出来る。
・ final メソッドはオーバーライドできない。
ラベル:
Java 基本メモ
オーバーロード
メソッドは同じ名前でも引数の型、数、並び順のいずれかを変えることで違うメソッドとして記述できます。
これをオーバーロードといいます。
if 文などの条件分岐を減らすことも出来ます。
<ルール>
・引数の型、数、並び順のいずれかを変える
・戻り値型を変更できる
・修飾子を変更できる
・例外を追加できる
有効なオーバーロードの例
void func() {}
void func(int x){}
void func(int x, int y) {}
void func(double x, double y) {}
String func(double x, int y) {return null;}
private void func(File file) throws IOException {}
これをオーバーロードといいます。
if 文などの条件分岐を減らすことも出来ます。
<ルール>
・引数の型、数、並び順のいずれかを変える
・戻り値型を変更できる
・修飾子を変更できる
・例外を追加できる
有効なオーバーロードの例
void func() {}
void func(int x){}
void func(int x, int y) {}
void func(double x, double y) {}
String func(double x, int y) {return null;}
private void func(File file) throws IOException {}
ラベル:
Java 基本メモ
super() と this()
基本的に、コンストラクタには super() が自動生成されます。
super() はスーパークラスのコンストラクタを呼び出します。
this() はそのクラスの引数なしのコンストラクタを呼び出します。
最終的にはすべてのクラスのスーパークラスである Object クラスのコンストラクタが呼び出されます。
super()、this() に引数をつけることは可能です。
super() と this() の併用は不可です。
super() と this() はコンストラクタ内の処理の最初に記述する。
super() はスーパークラスのコンストラクタを呼び出します。
this() はそのクラスの引数なしのコンストラクタを呼び出します。
最終的にはすべてのクラスのスーパークラスである Object クラスのコンストラクタが呼び出されます。
super()、this() に引数をつけることは可能です。
super() と this() の併用は不可です。
super() と this() はコンストラクタ内の処理の最初に記述する。
Sample sample = new Sample(1)
下記の例では引数ありのコンストラクタ内で super() が自動生成されます。
class Sample {
Sample() { }
Sample(int x) { } // super()が自動生成される
}
下記の例では引数なしコンストラクタ内に super() が自動生成されます。
class Sample {
Sample() { } // super() が自動生成される
Sample(int x) {this();}
}
下記の例では引数ありのコンストラクタ内で super() が自動生成されます。
class Sample {
Sample() { }
Sample(int x) { } // super()が自動生成される
}
下記の例では引数なしコンストラクタ内に super() が自動生成されます。
class Sample {
Sample() { } // super() が自動生成される
Sample(int x) {this();}
}
ラベル:
Java 基本メモ
コンストラクタチェーン
コンストラクタは呼び出された順番でスタートし、その逆の順序で初期化処理を行いコンストラクタを完了します。
<サンプル>
class Sample {
Sample() {
// super() が自動生成され Object クラスのコンストラクタが呼び出される
System.out.println("引数なしコンストラクタ");
}
Sample(int x) {
this(); // 引数なしコンストラクタが呼び出される
System.out.println("引数ありコンストラクタ");
}
public static void main(String[] args) {
Sample sp = new Sample(1);
}
}
<出力結果>
引数なしコンストラクタ
引数ありコンストラクタ
<サンプル>
class Sample {
Sample() {
// super() が自動生成され Object クラスのコンストラクタが呼び出される
System.out.println("引数なしコンストラクタ");
}
Sample(int x) {
this(); // 引数なしコンストラクタが呼び出される
System.out.println("引数ありコンストラクタ");
}
public static void main(String[] args) {
Sample sp = new Sample(1);
}
}
<出力結果>
引数なしコンストラクタ
引数ありコンストラクタ
ラベル:
Java 基本メモ
例外
例外 = フローの中のエラー
例外の種類
チェック例外 : Exception クラスを継承する例外(RuntimeException を除く)
Runtime 例外 : RuntimeException とそれを継承する例外
Error : Error クラスとそれを継承する例外
Runtime 例外と Error は非チェック例外となります。
_______________
try - catch - finally ブロック
チェック例外は try - catch - finally ブロックで処理します。
finally ブロックは任意ですが、例外が発生してもしなくても必ず実行されます。
public class Sample {
public static void main(String[] args) {
Sample sample = new Sample();
sample.func();
}
/* dangerousMethod を try - catch - finally で処理 */
void func() {
try {
dangerousMethod();
} catch (Exception e) {
System.out.println("例外が発生しました");
} finally {
System.out.println("必ず実行される処理");
}
}
/* 例外が発生する可能性を throws キーワードで宣言 */
void dangerousMethod() throws Exception {
throw new Exception();
}
}
_______________
例外には「処理か宣言」の原則があります。
例外の発生する可能性のあるメソッドで「処理か宣言」のどちらかを行います。
<処理>
try - catch ブロックで囲む。
<宣言>
throws キーワードで発生する可能性のある例外を宣言する。
_______________
throw キーワード
throw キーワードで例外を投げることができます。
try - catch ブロックで例外をキャッチしてさらにそのメソッドの呼び出し元に例外を投げることもできます。
void func() throws Exception {
try {
dangerousMethod();
} catch (Exception e) {
throw e;
}
}
こうすると呼び出し元でさらに try - catch する必要があります。
_______________
複数の例外を処理する際の注意
複数の例外を処理する際は、例外クラスの継承関係の下位にある例外から順番に処理します。
継承関係の上位にある例外を try - catch ブロックで先に処理するとコンパイルエラーになります。
void func() {
try {
dangerousMethod();
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
void dangerousMethod() throws IOException {
throw new IOException();
}
Exception を先に catch ブロックに書くと次の IOException のキャッチブロックは到達不能になり、コンパイル不可なります。
_______________
RuntimeException
RuntimeException は非チェック例外ですが、Exception クラスを継承しているので try - catch ブロックで処理することができます。
RuntimeException は throws キーワードで RuntimeException の発生の可能性を宣言する必要はありません。
void func1() throws IOException {
throw new IOException();
}
void func2() {
throw new RuntimeException();
}
_______________
finally ブロック
finally ブロックは例外が発生してもしなくても処理を実行するので
ストリームの切断など確実にしておきたい処理を記述しておくとよいでしょう。
しかし、下記のコードはコンパイルできません。
public class Sample {
public static void main(String[] args) {
BufferedReader br = null;
try {
br = new BufferedReader(new FileReader("C:/test.txt"));
String line;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
br.close();
}
}
}
br.close(); の部分を try - catch ブロックで囲む必要があります。
例外の種類
チェック例外 : Exception クラスを継承する例外(RuntimeException を除く)
Runtime 例外 : RuntimeException とそれを継承する例外
Error : Error クラスとそれを継承する例外
Runtime 例外と Error は非チェック例外となります。
_______________
try - catch - finally ブロック
チェック例外は try - catch - finally ブロックで処理します。
finally ブロックは任意ですが、例外が発生してもしなくても必ず実行されます。
public class Sample {
public static void main(String[] args) {
Sample sample = new Sample();
sample.func();
}
/* dangerousMethod を try - catch - finally で処理 */
void func() {
try {
dangerousMethod();
} catch (Exception e) {
System.out.println("例外が発生しました");
} finally {
System.out.println("必ず実行される処理");
}
}
/* 例外が発生する可能性を throws キーワードで宣言 */
void dangerousMethod() throws Exception {
throw new Exception();
}
}
_______________
例外には「処理か宣言」の原則があります。
例外の発生する可能性のあるメソッドで「処理か宣言」のどちらかを行います。
<処理>
try - catch ブロックで囲む。
<宣言>
throws キーワードで発生する可能性のある例外を宣言する。
_______________
throw キーワード
throw キーワードで例外を投げることができます。
try - catch ブロックで例外をキャッチしてさらにそのメソッドの呼び出し元に例外を投げることもできます。
void func() throws Exception {
try {
dangerousMethod();
} catch (Exception e) {
throw e;
}
}
こうすると呼び出し元でさらに try - catch する必要があります。
_______________
複数の例外を処理する際の注意
複数の例外を処理する際は、例外クラスの継承関係の下位にある例外から順番に処理します。
継承関係の上位にある例外を try - catch ブロックで先に処理するとコンパイルエラーになります。
void func() {
try {
dangerousMethod();
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
void dangerousMethod() throws IOException {
throw new IOException();
}
Exception を先に catch ブロックに書くと次の IOException のキャッチブロックは到達不能になり、コンパイル不可なります。
_______________
RuntimeException
RuntimeException は非チェック例外ですが、Exception クラスを継承しているので try - catch ブロックで処理することができます。
RuntimeException は throws キーワードで RuntimeException の発生の可能性を宣言する必要はありません。
void func1() throws IOException {
throw new IOException();
}
void func2() {
throw new RuntimeException();
}
_______________
finally ブロック
finally ブロックは例外が発生してもしなくても処理を実行するので
ストリームの切断など確実にしておきたい処理を記述しておくとよいでしょう。
しかし、下記のコードはコンパイルできません。
public class Sample {
public static void main(String[] args) {
BufferedReader br = null;
try {
br = new BufferedReader(new FileReader("C:/test.txt"));
String line;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
br.close();
}
}
}
br.close(); の部分を try - catch ブロックで囲む必要があります。
ラベル:
Java 基本メモ
アサーション
アサーションは仮説を検証するメカニズムです。(JDK 1.4 より導入)
アサーションは有効無効を切り替えられます。
不必要な try - catch ブロックや if 文などはプログラムの完成後に取り除くのは手間がかかりますが、
アサーションは有効無効の切り替えだけですみます。
JDK 1.4 ではデフォルトでアサーションが無効になっているのでアサーションのコードは実行時に無視されます。
アサーションを有効にするjava -ea
java -enableassertions
アサーションを無効にする
java -da
java -disableassertions
sample.Sample クラスのアサーションを有効にする
java ea:sample.Sample
sample パッケージとそのすべてのサブパッケージのアサーションを有効にする
java ea:sample
全体のアサーションを有効にし、システムクラスのアサーションのみを無効にする
java -ea -dsa
全体のアサーションを有効にし、sample パッケージのみを無効にする
java -ea -da:sample
アサーションの使い方
int x = 2 + 2;
assert (x == 4); // true でないとき AssertionError を投げる
アサーションは有効無効を切り替えられます。
不必要な try - catch ブロックや if 文などはプログラムの完成後に取り除くのは手間がかかりますが、
アサーションは有効無効の切り替えだけですみます。
JDK 1.4 ではデフォルトでアサーションが無効になっているのでアサーションのコードは実行時に無視されます。
アサーションを有効にするjava -ea
java -enableassertions
アサーションを無効にする
java -da
java -disableassertions
sample.Sample クラスのアサーションを有効にする
java ea:sample.Sample
sample パッケージとそのすべてのサブパッケージのアサーションを有効にする
java ea:sample
全体のアサーションを有効にし、システムクラスのアサーションのみを無効にする
java -ea -dsa
全体のアサーションを有効にし、sample パッケージのみを無効にする
java -ea -da:sample
アサーションの使い方
int x = 2 + 2;
assert (x == 4); // true でないとき AssertionError を投げる
ラベル:
Java 基本メモ
文字列の扱い
String クラス
オブジェクト参照変数の参照先に注意
String a = "Albert";
String b = "Bob";
System.out.println(a);
a = b;
System.out.println(b);
出力結果
Albert
Bob
String オブジェクトは不変
<サンプル>
String a = "Albert";
a.concat(" Einstein");
System.out.println(a);
<出力結果>
Albert
a が参照する String オブジェクトを変更することはできない。
<サンプル>
String a = "Albert";
a = a.concat(" Einstein");
System.out.println(a);
a に新しいオブジェクトを再代入している。
<出力結果>
Albert Einstein
_________
StringBuilder クラス
StringBuilder クラスは StringBuffer クラスと同じような機能を持ち StringBuffer クラスよりほとんどの面で高速に動作します。
文字列の連結などの操作は String クラスは使わず StringBuilder を使うほうが高速で有効。
<サンプル>
StringBuilder a = new StringBuilder("Albert");
a.append(" Einstein");
System.out.println(a);
<出力結果>
Albert Einstein
a が参照する StringBuilder オブジェクトを変更できる。
オブジェクト参照変数の参照先に注意
String a = "Albert";
String b = "Bob";
System.out.println(a);
a = b;
System.out.println(b);
出力結果
Albert
Bob
String オブジェクトは不変
<サンプル>
String a = "Albert";
a.concat(" Einstein");
System.out.println(a);
<出力結果>
Albert
a が参照する String オブジェクトを変更することはできない。
<サンプル>
String a = "Albert";
a = a.concat(" Einstein");
System.out.println(a);
a に新しいオブジェクトを再代入している。
<出力結果>
Albert Einstein
_________
StringBuilder クラス
StringBuilder クラスは StringBuffer クラスと同じような機能を持ち StringBuffer クラスよりほとんどの面で高速に動作します。
文字列の連結などの操作は String クラスは使わず StringBuilder を使うほうが高速で有効。
<サンプル>
StringBuilder a = new StringBuilder("Albert");
a.append(" Einstein");
System.out.println(a);
<出力結果>
Albert Einstein
a が参照する StringBuilder オブジェクトを変更できる。
ラベル:
Java 基本メモ
Math クラス
java.lang.Math クラスは final なので継承することはできません。
java.lang.Math クラスのコンストラクタは private なので Math クラスのインスタンスを作成することはできません。
<サンプル>
double number = Math.random() * 10;
System.out.println(number);
System.out.println("abs = " + Math.abs(number));
System.out.println("ceil = " + Math.ceil(number));
System.out.println("floor = " + Math.floor(number));
System.out.println("round = " + Math.round(number));
出力結果は毎回異なります。
1.8282950594054825
abs = 1.8282950594054825
ceil = 2.0
floor = 1.0
round = 2
java.lang.Math クラスのコンストラクタは private なので Math クラスのインスタンスを作成することはできません。
<サンプル>
double number = Math.random() * 10;
System.out.println(number);
System.out.println("abs = " + Math.abs(number));
System.out.println("ceil = " + Math.ceil(number));
System.out.println("floor = " + Math.floor(number));
System.out.println("round = " + Math.round(number));
出力結果は毎回異なります。
1.8282950594054825
abs = 1.8282950594054825
ceil = 2.0
floor = 1.0
round = 2
ラベル:
Java 基本メモ
ラッパークラス
プリミティブ(基本データ型変数)をオブジェクトとして扱うためにラッパークラスがあります。
プリミティブ ラッパークラス
byte Byte
short Short
int Integer
long Long
float Float
double Double
boolean Boolean
char Character
ラッパークラスのオブジェクト生成の際のコンストラクタ引数はそれぞれのプリミティブ型が使用できます。
Character クラス以外は String 型引数も使用できます。
<オブジェクトの生成>
(例)
・ Double d = new Double(5.0);
・ Double d = Double.valueOf(5.0);
・ Double d = Double.valueOf("5.0");
・ Double d = Double.valueOf("5.0f");
・ Short s = d.shortValue(d);
<プリミティブの抽出>
(例)
・ double value = Double.parseDouble("5.0");
・ double value = Double.parseDouble("5.0d");
<オブジェクトの比較>
オブジェクトの比較は == 演算子や equals メソッドで行います。
equals メソッドは Object クラスで定義されていて、String クラス、ラッパークラスでオーバーライドされています。
Object クラスの equals メソッドと String クラスやラッパークラスの equals メソッドは振る舞いが違います。
Object クラスの equals メソッドは比較する2つのオブジェクトがまったく同じオブジェクトの場合 true を返します。
String クラス、ラッパークラスの equals メソッドは2つのオブジェクトがまったく同じでなくても意味的に等しい場合 true を返します。
<サンプル>
Object o1 = new Object();
Object o2 = new Object();
System.out.println("o1 == o2 : " + (o1 == o2));
System.out.println("o1.equals(o2) : " + o1.equals(o2));
Integer i1 = new Integer(5);
Integer i2 = new Integer(5);
System.out.println("i1 == i2 : " + (i1 == i2));
System.out.println("i1.equals(i2) : " + i1.equals(i2));
<出力結果>
o1 == o2 : false
o1.equals(o2) : false
i1 == i2 : false
i1.equals(i2) : true
プリミティブ ラッパークラス
byte Byte
short Short
int Integer
long Long
float Float
double Double
boolean Boolean
char Character
ラッパークラスのオブジェクト生成の際のコンストラクタ引数はそれぞれのプリミティブ型が使用できます。
Character クラス以外は String 型引数も使用できます。
<オブジェクトの生成>
(例)
・ Double d = new Double(5.0);
・ Double d = Double.valueOf(5.0);
・ Double d = Double.valueOf("5.0");
・ Double d = Double.valueOf("5.0f");
・ Short s = d.shortValue(d);
<プリミティブの抽出>
(例)
・ double value = Double.parseDouble("5.0");
・ double value = Double.parseDouble("5.0d");
<オブジェクトの比較>
オブジェクトの比較は == 演算子や equals メソッドで行います。
equals メソッドは Object クラスで定義されていて、String クラス、ラッパークラスでオーバーライドされています。
Object クラスの equals メソッドと String クラスやラッパークラスの equals メソッドは振る舞いが違います。
Object クラスの equals メソッドは比較する2つのオブジェクトがまったく同じオブジェクトの場合 true を返します。
String クラス、ラッパークラスの equals メソッドは2つのオブジェクトがまったく同じでなくても意味的に等しい場合 true を返します。
<サンプル>
Object o1 = new Object();
Object o2 = new Object();
System.out.println("o1 == o2 : " + (o1 == o2));
System.out.println("o1.equals(o2) : " + o1.equals(o2));
Integer i1 = new Integer(5);
Integer i2 = new Integer(5);
System.out.println("i1 == i2 : " + (i1 == i2));
System.out.println("i1.equals(i2) : " + i1.equals(i2));
<出力結果>
o1 == o2 : false
o1.equals(o2) : false
i1 == i2 : false
i1.equals(i2) : true
ラベル:
Java 基本メモ
equals メソッドと hashCode メソッドのオーバーライド
自作クラスの2つのオブジェクトを equals メソッドを使って意味的に等しい場合 true を返すようにするには
自作クラスで equals メソッドをオーバーライドする必要があります。
Object クラスの equals メソッドはまったく同じオブジェクトの場合 true を返します。
equals メソッドのオーバーライドの例
public class Sample {
public static void main(String[] args) {
Tiger t1 = new Tiger(1);
Tiger t2 = new Tiger(1);
System.out.println(t1.equals(t2));
}
}
class Tiger {
private final int t;
Tiger(int t) {
this.t = t;
}
public int tigerValue() {
return t;
}
public boolean equals(Object obj) {
if (obj instanceof Tiger) {
return ((Tiger)obj).tigerValue() == t;
} else {
return false;
}
}
}
<出力結果>
true
_______
hashCode メソッドのオーバーライド
自作クラスに equals メソッドをオーバーライドしたら hashCode メソッドもオーバーライドしましょう。
コレクションの HashMap などの Hash がつくクラスはオブジェクトを格納する際にハッシュコードを使用します。
これは検索速度の向上が意図されています。
Object クラスの hashCode メソッドは一意のハッシュコードを返します。
したがって、自作クラスでオーバーライドする際は
意味的に等しい場合は同じハッシュコードを返すようにするのが適切です。
適切かつ最も簡単な方法を Tiger クラスに実装すると
public int hashCode() {
return t;
}
となります。
自作クラスに hashCode メソッドをオーバーライドしないとコレクションで安全に使用できません。
自作クラスで equals メソッドをオーバーライドする必要があります。
Object クラスの equals メソッドはまったく同じオブジェクトの場合 true を返します。
equals メソッドのオーバーライドの例
public class Sample {
public static void main(String[] args) {
Tiger t1 = new Tiger(1);
Tiger t2 = new Tiger(1);
System.out.println(t1.equals(t2));
}
}
class Tiger {
private final int t;
Tiger(int t) {
this.t = t;
}
public int tigerValue() {
return t;
}
public boolean equals(Object obj) {
if (obj instanceof Tiger) {
return ((Tiger)obj).tigerValue() == t;
} else {
return false;
}
}
}
<出力結果>
true
_______
hashCode メソッドのオーバーライド
自作クラスに equals メソッドをオーバーライドしたら hashCode メソッドもオーバーライドしましょう。
コレクションの HashMap などの Hash がつくクラスはオブジェクトを格納する際にハッシュコードを使用します。
これは検索速度の向上が意図されています。
Object クラスの hashCode メソッドは一意のハッシュコードを返します。
したがって、自作クラスでオーバーライドする際は
意味的に等しい場合は同じハッシュコードを返すようにするのが適切です。
適切かつ最も簡単な方法を Tiger クラスに実装すると
public int hashCode() {
return t;
}
となります。
自作クラスに hashCode メソッドをオーバーライドしないとコレクションで安全に使用できません。
ラベル:
Java 基本メモ
コレクションフレームワーク
コレクションフレームワークには List、Set、Map インターフェースを実装するものがあります。
詳細は Javadoc を参照ください。
コレクションの要素にプリミティブ型は使用できません。
<サンプル>
List list = new ArrayList();
for (int i = 0; i < 5; i++) {
list.add(new Integer(i));
}
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
<出力結果>
0
1
2
3
4
詳細は Javadoc を参照ください。
コレクションの要素にプリミティブ型は使用できません。
<サンプル>
List
for (int i = 0; i < 5; i++) {
list.add(new Integer(i));
}
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
<出力結果>
0
1
2
3
4
ラベル:
Java 基本メモ
ガーベージコレクション
Java のガーベージコレクションは
- どこからも参照されないオブジェクト
- 到達不能のオブジェクト
を自動で削除します。
<オブジェクトに null を代入>オブジェクト参照変数に null を代入するとそのオブジェクト参照変数はもはやどこも参照していないので削除対象になります。
<参照先の変更>
参照先を変更すると、元の参照先は削除対象になります。
Integer a = new Integer(1);
Integer b = new Integer(2);
a = b;
この時点で new Integer(1) というインスタンスはどこからも参照されなくなり削除対象となります。
<参照の孤立>
A⇔B
A = null
B = null
A と B の相互参照が孤立しガーベージコレクトの対象になる。
<ガーベージコレクションは即座に実行できるか?>
答えは No です。
カーベージコレクトを要求することはできます。
実行のタイミングは JVM が決定します。
<カーベージコレクションの要求>
・ System.gc();
・ Runtime.getRuntime().gc();
<finalize メソッド>
finalize メソッドはオブジェクトがガーベージコレクションによって削除される直前に呼び出されます。
finalize メソッドはオブジェクトに対し一度だけ呼び出される。
finailze メソッドに重要な処理を記述することは推奨されません。
ラベル:
Java 基本メモ
インナークラス
内部クラスと呼ばれるものにはにはインナークラスのほかに静的ネストクラス、ローカルインナークラス、無名クラスがある。
インナークラス
インナークラスはアウタークラスのインスタンスから呼び出される。
<サンプル>
public class Sample {
public static void main(String[] arvs) {
Outer.I1 objInner = new Outer().new I1();
objInner.func();
Outer objOuter = new Outer();
objOuter.func();
}
}
class Outer {
class Inner1 {
void func(){
System.out.println("Innerclass1");
}
}
class Inner2 {
void func(){
System.out.println("Innerclass2");
}
}
void func() {
new Inner2().func();
}
}
<出力結果>
Innerclass1
Innerclass2
インナークラス
インナークラスはアウタークラスのインスタンスから呼び出される。
<サンプル>
public class Sample {
public static void main(String[] arvs) {
Outer.I1 objInner = new Outer().new I1();
objInner.func();
Outer objOuter = new Outer();
objOuter.func();
}
}
class Outer {
class Inner1 {
void func(){
System.out.println("Innerclass1");
}
}
class Inner2 {
void func(){
System.out.println("Innerclass2");
}
}
void func() {
new Inner2().func();
}
}
<出力結果>
Innerclass1
Innerclass2
ラベル:
Java 基本メモ
ローカルインナークラス
ローカルインナークラスはメソッドの中に定義する。
ローカールインナークラスのインスタンスをメソッド内に生成する。
アクセス修飾子は使用できない。final もしくは abstract を使用できる。
ローカルインナークラスから final 以外のローカル変数にアクセスできない。
ローカルインナークラスからアウタークラスのメンバーにアクセスできる。
<サンプル>
public class Sample {
public static void main(String[] arvs) {
final int x = 1;
class Local {
void func() {
System.out.println(x);
}
}
Local local = new Local();
local.func();
}
}
<出力結果>
1
ローカールインナークラスのインスタンスをメソッド内に生成する。
アクセス修飾子は使用できない。final もしくは abstract を使用できる。
ローカルインナークラスから final 以外のローカル変数にアクセスできない。
ローカルインナークラスからアウタークラスのメンバーにアクセスできる。
<サンプル>
public class Sample {
public static void main(String[] arvs) {
final int x = 1;
class Local {
void func() {
System.out.println(x);
}
}
Local local = new Local();
local.func();
}
}
<出力結果>
1
ラベル:
Java 基本メモ
無名インナークラス
名前のないインナークラス。
匿名クラスとも言う。
メソッド内にも記述できる
<サンプル>
public class Sample {
public static void main(String[] arvs) {
Super objSuper = new Super() {
@Override
void func() {
System.out.println("無名インナークラス");
}
};
objSuper.func();
}
}
class Super {
void func() {
System.out.println("Superclass");
}
}
<出力結果>
無名インナークラス
匿名クラスとも言う。
メソッド内にも記述できる
<サンプル>
public class Sample {
public static void main(String[] arvs) {
Super objSuper = new Super() {
@Override
void func() {
System.out.println("無名インナークラス");
}
};
objSuper.func();
}
}
class Super {
void func() {
System.out.println("Superclass");
}
}
<出力結果>
無名インナークラス
ラベル:
Java 基本メモ
マルチスレッド
スレッドは Java プログラムの動作単位です。
マルチスレッドプログラムにより複数のスレッドを同時に(1CPU環境ではスレッドスケジューリングにより交互に)動かすことができます。
<マルチスレッドの実装方法>
java.lang.Thread クラスを拡張する
java.lang.Runnable インターフェースを実装する
<スレッドのライフサイクル>
生成 → 実行可能 → 実行 → 終了
<スレッドを実行不可状態にするメソッド>
sleep
wait
<スレッドを実行不可状態から実行可能状態にするメソッド>
notify
notifyAll
<実行中のスレッドを実行可能状態へ戻すメソッド>
yield
<スレッドの同期化>
マルチスレッドで動作するプログラムは必要に応じて各スレッドを同期化する必要があります。
マルチスレッドプログラムにより複数のスレッドを同時に(1CPU環境ではスレッドスケジューリングにより交互に)動かすことができます。
<マルチスレッドの実装方法>
java.lang.Thread クラスを拡張する
java.lang.Runnable インターフェースを実装する
<スレッドのライフサイクル>
生成 → 実行可能 → 実行 → 終了
<スレッドを実行不可状態にするメソッド>
sleep
wait
<スレッドを実行不可状態から実行可能状態にするメソッド>
notify
notifyAll
<実行中のスレッドを実行可能状態へ戻すメソッド>
yield
<スレッドの同期化>
マルチスレッドで動作するプログラムは必要に応じて各スレッドを同期化する必要があります。
ラベル:
Java 基本メモ
Thread クラス
基本プログラム
Thread クラスを継承して run メソッドをオーバーライドする
class Sample1{
public static void main(String[] args){
Thread t1 = new Thread(){
public void run(){
for(int i=0;i<100;i++){
System.out.println("Hello");
}
}
};
Thread t2 = new Thread(){
public void run(){
for(int i=0;i<100;i++){
System.out.println("World");
}
}
};
t1.start();
t2.start();
}
}
出力結果は Hello と World が時々入れ替わって出力される。
Thread クラスを継承して run メソッドをオーバーライドする
class Sample1{
public static void main(String[] args){
Thread t1 = new Thread(){
public void run(){
for(int i=0;i<100;i++){
System.out.println("Hello");
}
}
};
Thread t2 = new Thread(){
public void run(){
for(int i=0;i<100;i++){
System.out.println("World");
}
}
};
t1.start();
t2.start();
}
}
出力結果は Hello と World が時々入れ替わって出力される。
ラベル:
Java 基本メモ
Runnable インターフェース
基本プログラム
Runnable インターフェースを実装するクラスのオブジェクトを引数に Thread オブジェクトを生成する。
run メソッドをオーバーライドする。
class RA implements Runnable {
public void run(){
for (int i = 0; i < 100; i++) {
System.out.println("スレッド "
+ Thread.currentThread().getName());
}
}
}
class RB implements Runnable {
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println("スレッド "
+ Thread.currentThread().getName());
}
}
}
public class Sample {
public static void main(String[] args) {
RA ra = new RA();
RB rb = new RB();
Thread ta = new Thread(ra);
Thread tb = new Thread(rb);
ta.setName("A");// スレッド名をセット
tb.setName("B");// スレッド名をセット
ta.start();
tb.start();
}
}
出力結果は時々交互になる
Runnable インターフェースを実装するクラスのオブジェクトを引数に Thread オブジェクトを生成する。
run メソッドをオーバーライドする。
class RA implements Runnable {
public void run(){
for (int i = 0; i < 100; i++) {
System.out.println("スレッド "
+ Thread.currentThread().getName());
}
}
}
class RB implements Runnable {
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println("スレッド "
+ Thread.currentThread().getName());
}
}
}
public class Sample {
public static void main(String[] args) {
RA ra = new RA();
RB rb = new RB();
Thread ta = new Thread(ra);
Thread tb = new Thread(rb);
ta.setName("A");// スレッド名をセット
tb.setName("B");// スレッド名をセット
ta.start();
tb.start();
}
}
出力結果は時々交互になる
ラベル:
Java 基本メモ
join メソッド
マルチスレッドにおいて1つのスレッドが終了してからもうひとつのスレッドを動作させるには join メソッドを使います。
ta と tb というスレッドがある場合
ta.join() で ta が完了するまで他のスレッドは実行を待機する。
class RA implements Runnable {
public void run(){
for (int i = 0; i < 100; i++) {
System.out.println("スレッド"
+ Thread.currentThread().getName());
}
}
}
class RB implements Runnable {
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println("スレッド"
+ Thread.currentThread().getName());
}
}
}
public class ThreadRunnable1 {
public static void main(String[] args) {
RA ra = new RA();
RB rb = new RB();
Thread ta = new Thread(ra);
Thread tb = new Thread(rb);
ta.setName("A"); // スレッド名をセット
tb.setName("B"); // スレッド名をセット
ta.start();
try {
ta.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
tb.start();
}
}
出力結果は
スレッドA がすべての回数出力されてから スレッドB の出力が始まる。
ta と tb というスレッドがある場合
ta.join() で ta が完了するまで他のスレッドは実行を待機する。
class RA implements Runnable {
public void run(){
for (int i = 0; i < 100; i++) {
System.out.println("スレッド"
+ Thread.currentThread().getName());
}
}
}
class RB implements Runnable {
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println("スレッド"
+ Thread.currentThread().getName());
}
}
}
public class ThreadRunnable1 {
public static void main(String[] args) {
RA ra = new RA();
RB rb = new RB();
Thread ta = new Thread(ra);
Thread tb = new Thread(rb);
ta.setName("A"); // スレッド名をセット
tb.setName("B"); // スレッド名をセット
ta.start();
try {
ta.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
tb.start();
}
}
出力結果は
スレッドA がすべての回数出力されてから スレッドB の出力が始まる。
ラベル:
Java 基本メモ
スレッドの同期化
複数のスレッドからアクセスされるオブジェクトのメソッドは同期化処理をするべきです。
同期化は synchronized 修飾子を使用します。
下記のプログラムは 2人が同じ講座からお金を引き出すプログラムです。
残高が 10 未満なら引き出しをしません。
残高が 10 以上なら 10 ずつ引き出しをします。
したがって残高がマイナスになることはありません。
<サンプル>
public class Sample {
public static void main(String[] arvs) {
Account account = new Account(100);
Family taro = new Family(account, "太郎");
Family jiro = new Family(account, "次郎");
taro.start();
jiro.start();
}
}
class Family extends Thread {
private Account account;
private String name;
Family (Account account, String name) {
this.account = account;
this.name = name;
}
public void run() {
for (int i = 0; i < savings =" savings;">= amount) {
return true;
} else {
return false;
}
}
/* 引き出し処理の結果を返す */
public synchronized boolean withdraw(int amount) {
if (withdrawable(amount)) {
// 動きをわかりやすくするために1秒スリープ
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
savings -= amount;
return true;
} else {
return false;
}
}
public String toString() {
return String.valueOf(savings);
}
}
<出力結果>
太郎は引き出せました。残高 90
太郎は引き出せました。残高 80
太郎は引き出せました。残高 70
太郎は引き出せました。残高 60
太郎は引き出せました。残高 50
太郎は引き出せました。残高 40
次郎は引き出せました。残高 30
次郎は引き出せました。残高 20
次郎は引き出せました。残高 10
次郎は引き出せました。残高 0
次郎は引き出せませんでした。残高 0
次郎は引き出せませんでした。残高 0
同期化しない場合の出力結果
(例)
次郎は引き出せました。残高 80
太郎は引き出せました。残高 80
太郎は引き出せました。残高 60
次郎は引き出せました。残高 60
次郎は引き出せました。残高 50
太郎は引き出せました。残高 50
次郎は引き出せました。残高 30
太郎は引き出せました。残高 30
太郎は引き出せました。残高 10
次郎は引き出せました。残高 10
次郎は引き出せました。残高 -10
太郎は引き出せました。残高 -10
このように同期化をしないと残高がマイナスになるというおかしなことが起こります。
synchronized ブロックによる同期化
上記のコードは共通の Account オブジェクトをロックする形でも同期化できます。
public void run() {
synchronized (account) {
for (int i = 0; i < 6; i++) {
if (account.withdraw(10)) {
System.out.println(
name + "は引き出せました。残高 "
+ account.toString());
} else {
System.out.println(
name + "は引き出せませんでした。残高 "
+ account.toString());
}
}
}
}
この場合は実行中のスレッド以外は Account オブジェクトのすべてのメソッドへのアクセスができません。
同期化 = ロックの取得
ということができます。
同期化は synchronized 修飾子を使用します。
下記のプログラムは 2人が同じ講座からお金を引き出すプログラムです。
残高が 10 未満なら引き出しをしません。
残高が 10 以上なら 10 ずつ引き出しをします。
したがって残高がマイナスになることはありません。
<サンプル>
public class Sample {
public static void main(String[] arvs) {
Account account = new Account(100);
Family taro = new Family(account, "太郎");
Family jiro = new Family(account, "次郎");
taro.start();
jiro.start();
}
}
class Family extends Thread {
private Account account;
private String name;
Family (Account account, String name) {
this.account = account;
this.name = name;
}
public void run() {
for (int i = 0; i < savings =" savings;">= amount) {
return true;
} else {
return false;
}
}
/* 引き出し処理の結果を返す */
public synchronized boolean withdraw(int amount) {
if (withdrawable(amount)) {
// 動きをわかりやすくするために1秒スリープ
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
savings -= amount;
return true;
} else {
return false;
}
}
public String toString() {
return String.valueOf(savings);
}
}
<出力結果>
太郎は引き出せました。残高 90
太郎は引き出せました。残高 80
太郎は引き出せました。残高 70
太郎は引き出せました。残高 60
太郎は引き出せました。残高 50
太郎は引き出せました。残高 40
次郎は引き出せました。残高 30
次郎は引き出せました。残高 20
次郎は引き出せました。残高 10
次郎は引き出せました。残高 0
次郎は引き出せませんでした。残高 0
次郎は引き出せませんでした。残高 0
同期化しない場合の出力結果
(例)
次郎は引き出せました。残高 80
太郎は引き出せました。残高 80
太郎は引き出せました。残高 60
次郎は引き出せました。残高 60
次郎は引き出せました。残高 50
太郎は引き出せました。残高 50
次郎は引き出せました。残高 30
太郎は引き出せました。残高 30
太郎は引き出せました。残高 10
次郎は引き出せました。残高 10
次郎は引き出せました。残高 -10
太郎は引き出せました。残高 -10
このように同期化をしないと残高がマイナスになるというおかしなことが起こります。
synchronized ブロックによる同期化
上記のコードは共通の Account オブジェクトをロックする形でも同期化できます。
public void run() {
synchronized (account) {
for (int i = 0; i < 6; i++) {
if (account.withdraw(10)) {
System.out.println(
name + "は引き出せました。残高 "
+ account.toString());
} else {
System.out.println(
name + "は引き出せませんでした。残高 "
+ account.toString());
}
}
}
}
この場合は実行中のスレッド以外は Account オブジェクトのすべてのメソッドへのアクセスができません。
同期化 = ロックの取得
ということができます。
ラベル:
Java 基本メモ
wait、notify、notifyAll メソッド
wait、notify、notifyAll メソッドの使い方
これらのメソッドは同期化されたブロック内で使用できます。
これらのメソッドはロックを取得しているときに動作します。
wait
ロックを開放する
notify/notifyAll
同期コードを抜けた後ロックを開放する
メソッドの詳細は Javadoc を参照ください。
これらのメソッドは同期化されたブロック内で使用できます。
これらのメソッドはロックを取得しているときに動作します。
wait
ロックを開放する
notify/notifyAll
同期コードを抜けた後ロックを開放する
メソッドの詳細は Javadoc を参照ください。
ラベル:
Java 基本メモ
ジェネリクス
JDK 5.0 より導入された記述法
コレクションの記述
/* 従来型 */
List list1 = new ArrayList();
/* ジェネリクス */
List list2 = new ArrayList();
List list3 = new ArrayList();
list1.add("Conventional");
list2.add("Generics");
list3.add(new Integer(7));
String conventional = (String) list1.get(0);
String generics = list2.get(0);
/* java.lang.ClassCastException 発生 */
Integer i = (Integer)list1.get(0);
/* コンパイルエラー */
Integer i2 = (Integer)list2.get(0);
ClassCastException
継承関係のない型にキャストすると実行時エラーとなる。
ジェネリクスの使用によってこのようなキャストミスはコンパイル時に発見できる。
コレクションの記述
/* 従来型 */
List list1 = new ArrayList();
/* ジェネリクス */
List
List
list1.add("Conventional");
list2.add("Generics");
list3.add(new Integer(7));
String conventional = (String) list1.get(0);
String generics = list2.get(0);
/* java.lang.ClassCastException 発生 */
Integer i = (Integer)list1.get(0);
/* コンパイルエラー */
Integer i2 = (Integer)list2.get(0);
ClassCastException
継承関係のない型にキャストすると実行時エラーとなる。
ジェネリクスの使用によってこのようなキャストミスはコンパイル時に発見できる。
ラベル:
Java 基本メモ
アノテーション
アノテーションとはプログラムに記述できる注釈のようなものです。
JDK 5.0 より導入された記述方法
@Override
適切にオーバーライドされていないとコンパイルエラー。
class SP {
void func(){
System.out.println("Super");
}
}
class SU extends SP {
@Override
int func() {
System.out.println("Sub");
}
}
___________
@Deprecated
非推奨メソッドを定義し警告を出す。
public static void main(String[] args) {
func();
}
@Deprecated
static void func() { }
}
___________
@SuppressWarnings("deprecation")
非推奨警告の抑制
@SuppressWarnings("fallthrough")
case に fall-through する可能性を警告
@SuppressWarnings("finally")
finally 節が正常に完了してない警告を抑制
@SuppressWarnings("serial")
serialVersionUID 未定義警告の抑制
2つ以上の警告をまとめて抑制
@SuppressWarnings({"deprecation", "finally"})
JDK 5.0 より導入された記述方法
@Override
適切にオーバーライドされていないとコンパイルエラー。
class SP {
void func(){
System.out.println("Super");
}
}
class SU extends SP {
@Override
int func() {
System.out.println("Sub");
}
}
___________
@Deprecated
非推奨メソッドを定義し警告を出す。
public static void main(String[] args) {
func();
}
@Deprecated
static void func() { }
}
___________
@SuppressWarnings("deprecation")
非推奨警告の抑制
@SuppressWarnings("fallthrough")
case に fall-through する可能性を警告
@SuppressWarnings("finally")
finally 節が正常に完了してない警告を抑制
@SuppressWarnings("serial")
serialVersionUID 未定義警告の抑制
2つ以上の警告をまとめて抑制
@SuppressWarnings({"deprecation", "finally"})
ラベル:
Java 基本メモ
登録:
投稿 (Atom)