#はじめに
仕事でJavaを使う必要があり、とりあえず体系的に学ぶためにJava Silverを取ろうと思ったので、そこで学んだことをキーワード的に簡単にまとめて行きます。
#Javaの基本
##クラス宣言
クラス宣言はフィールドとメソッドで構成される。コンストラクタはメソッドの一部
##パッケージの目的
- 名前空間を提供し、名前の衝突を避ける
- アクセス修飾子と組み合わせてアクセス制御機能を提供する
- クラスの分類を可能とする
##パッケージ宣言
- パッケージ宣言は、必ずソースコードの先頭行に記述する
- パッケージ宣言よりも前に記述出来るのはコメントだけ
##クラスのインポート
- java.langパッケージは基本的なクラスがまとめられたパッケージであり、インポート宣言省略可能
- 指定したパッケージに属するクラスはインポートされるが、サブパッケージはインポートされない
##パッケージとアクセス制御
パッケージに属するクラスは、同じパッケージのクラスからしかアクセスできない。無名パッケージに属するクラスは同じ無名パッケージに属するクラスからしかアクセスできない
##staticインポートの書式
本来、staticなフィールドやメソッドは、クラス名.フィールド名(メソッド名)の書式でどのクラスのものか明示する必要がある。それらを名称だけで省略表記するようにするための物がstaticインポート
import static パッケージ名.クラス名.フィールド名(メソッド名)
メソッドのstaticインポート宣言では、メソッド名にかっこや引数をつけない
##staticインポートの仕様
- インポートしたクラスに、インポートされたメソッドやフィールドと同名の物が存在した場合、そのインポートは無視される
- 複数の同名のフィールドや、メソッドをインポートした場合、コンパイルエラーになる
##mainメソッド
クラスには複数のメソッドを定義出来るが、処理を始めるためのメソッド、エントリーポイントの記述やルールは以下のようになる
public static void main(String[] args) {
}
- 公開されてること(Public)
- インスタンスを生成しなくても実行出来ること(Static)
- 戻り値は戻せない(Void)
- メソッド名はmain
- 引数はString配列型を1つ受け取ること
##javaコマンド
javaコマンドは、JVMを起動するためのコマンド。構文は以下の通り
java 完全修飾クラス名 [引数 引数 ・・・]
#Javaのデータ型の操作
##Javaのデータ型
Javaのデータ型は、プリミティブ型(整数、浮動小数点数、真偽値、文字)と参照型(オブジェクト型、列挙型、配列型)がある。
プリミティブ型のデータ型は以下の通り
bool型はない
データ型 | 値 |
---|---|
boolean | true,false |
char | 16ビットUnicode文字 |
short | 16ビット整数 |
int | 32ビット整数 |
long | 64ビット整数 |
float | 32ビット単精度浮動小数点数 |
double | 64ビット単精度浮動小数点数 |
##整数リテラル
リテラルとはソースコードに記述する値のことで、Javaでは、整数値はint型、浮動小数値であれば、double型、真偽値であれば、boolean型、文字であればchar型で扱われる。
###接尾辞、接頭辞
接尾辞、接頭辞をつけることで、データ型を明示したり、10進数以外の表記が可能
・接尾辞の例
long型・・・L、float型・・・f
・接頭辞の例
0・・・8進数
0x・・・16進数
0b・・・2進数
###アンダースコア
アンダースコアを使った数値表記は、桁数の多い数値リテラルの見やすさを向上させる目的で使用され、以下のルールがある
- リテラルの先頭と末尾には記述ができない
- 記号の前後には記述できない
##文字リテラル、文字列リテラル
charは文字を表すデータ型
chara型に代入できるのは以下の通り
- シングルクォーテーションで括った文字(文字リテラル)
- シングルクォーテーションで括った¥uから始まるUnicode番号(文字リテラル)
- 0~65535までの数値(数値リテラル)
文字リテラルはシングルクォーテーションで括る
文字列リテラルはダブルクォーテーションで括る
##識別子の命名規則
識別子とは、変数、メソッド、クラスなどの名前の事。基本は自由に決められるが、以下の規則がある
- 予約語は使えない(int,ifなど文脈表現など)
- 使える記号は、アンダースコアと通貨記号($)のみ
- 数字から始めてはいけない(2文字目以降)
##null
nullは参照型の変数が参照を保持していないことを表現するためのリテラル。空文字("")とは異なる
##メソッドの呼び出し方
メソッドの呼び出し方は以下となる
- メソッド名(引数)・・・同じインスタンスに定義されているメソッド
- 変数.メソッド名(引数)・・・インスタンスに定義されているメソッドの場合
- クラス名.メソッド名(引数)・・・staticなメソッドの場合
##シグニチャ
シグニチャとは、メソッド名と引数のリストのセットのこと。Javaにはオーバーロードという仕組みがあり、同名のメソッドが複数存在する可能性があるため、シグニチャを使って、メソッドを見分ける。
##ガーベッジコレクション
C言語などではメモリを確保したり、解放したりするコードをプログラムに記述する必要があるが、Javaには自動メモリ管理機能がある。
カーベッジコレクタが不要なインスタンスを探し、破棄することをガーベッジコレクションという。ガーベッジコレクションの対象は、どこからも参照されなくなったインスタンスで、代表的なタイミングとして、変数にnullが代入されたとき。
#演算子と判定構造の使用
##代入演算子
代入演算子の種類と意味は以下の通り
演算子 | 使用例 | 意味 |
---|---|---|
= | a = 10; | aに10を代入する |
+= | a += 10 | aにa+10を代入する |
-= | a -= 10 | aにa-10を代入する |
*= | a *= 10 | aにa*10を代入する |
/= | a /= 10 | aにa/10を代入する |
##マイナス演算子
マイナス演算子(-)には、引き算と正負反転の2種類がある。
##型変換
大きな範囲の値を小さな変数に代入するときは、明示的なキャストが必要
int a = 15;
short b = (short) a;
整数の数値リテラルはint型、浮動小数点の場合はdouble型が基本のため、その値を小さな変数にいれる場合、原則明示的なキャストをしなくてはならない。byte型、short型の変数に代入する変数リテラルの場合、その値が方の範囲内であれば、コンパイルエラーとならない。
・byte型とshort型の範囲
型名 | 範囲 |
---|---|
byte | -128~127 |
short | -32768~32767 |
##インクリメントとデクリメント
インクリメント(++)とデクリメント(--)は変数の値に1を加算したり、減算するための演算子。
他の演算子と組み合わさった場合、前置きした場合、インクリメント(デクリメント)されてから代入され、後置きした場合、代入されてからインクリメント(デクリメント)される。
int a = 10
int b = 10
int c = ++a //aをインクリメントしてからcに代入 a=11,c=11
int d = b++ //bを代入してからインクリメント d=10,b=11
##関係演算子
左右の値を比較し、真偽値を戻す演算子が関係演算子。
演算子 | 例 | 意味 |
---|---|---|
== | a == b | aとbが等しければtrue |
!= | a != b | aとbが等しくなければtrue |
> | a > b | aがbより大きければtrue |
>= | a >= b | aがb以上であればtrue |
instanceof | a instanceof b | aがbと同じクラスかbのサブクラスのインスタンスであればtrue |
> ,>=は数値の大小の比較のみできる
##論理演算子
複数の関係演算子を組み合わせ、複雑な条件を指定するために使用するのが論理演算子
演算子 | 例 | 意味 |
---|---|---|
& | a>10 & b>10 | 両辺の式がtrueであればtrue |
&& | a>10 && b>10 | 両辺の式がtrueであればtrue |
| | a>10 | b>10 | 両辺のどちらかの式がtrueであればtrue |
|| | a>10 || b>10 | 両辺のどちらかの式がtrueであればtrue |
! | !a>0 | 式がtrueであればfalse,falseであればtrue |
&&、||は、ショートカット演算子と呼ばれ、左辺の式がfalseであれば、全体としてfalseが確定するため、右辺の式を評価しない。右辺の式にインクリメント等、値が変わる処理が入っていた場合、&や|とは結果が異なる。
##演算子の優先順位
演算子には優先順位があり、同じ優先順位であれば、左から、異なる優先順位の物は、優先順位の高い順に演算される。
優先順位 | 演算子 |
---|---|
1 | [配列] . (引数) a++ a-- |
2 | ++a --a +a ~ ! |
3 | new (型) |
4 | * / % |
5 | + - |
6 | << >> >>> |
7 | < > <= >= instanceof |
8 | == != |
9 | & |
10 | ^ |
11 | | |
12 | && |
13 | ?: |
14 | = += *= /= %= &= ^= != <<= >>= >>>= |
##同一性、同値
同じインスタンスであることを同一、同じ値であることを同値と呼ぶ。
同一性は、==演算子で判定する
Object a = new Object;
Object b = a; //bに変数aの参照のコピーを代入
System.out.println(a == b); //trueとなる
同値性とは、インスタンスは異なるけれど、同じ値を持っている性質のこと
同値であるかどうかはequalsメソッドを使う。
Objectクラスのeaualsメソッドは、Object型を引数に受け取り、boolean型の戻り値を戻す。おバーライドするのが一般的。
//Objectクラスのequalsメソッド
Public boolean equals(Object obj){
return(this == obj);
}
equalsメソッドについては、APIドキュメントに記載されている。
null以外の参照値xについて、x.equals(null)はfalseを返す。
クラスObjectのドキュメント
##文字リテラルの同一性
Stringのインスタンスは、文字列を記述するのみであり、異なる参照を == で比較した時も、同じ文字リテラルが使用されている場合、trueが返される。これは、コンスタントプールという処理負荷を軽減するための仕組み
String a = "test";
String b = "test";
System.out.print(a == b); //参照は異なるが、trueと表示される
コンスタントプールは、文字列リテラルを使った時のみ有効で、new演算子を使って新しいインスタンスを作った場合は、その都度インスタンスが作られ、異なる参照を持つ。equalsメソッドの場合は、文字列のみが同じが確認する。
String a = new String("test");
String b = "text";
System.out.print(a == b); //falseとなる
Syttem.out.println(a.equals(b)); //trueとなる
##if文
if文の構文は以下の通りです。
if (条件式) {
//条件に一致したときの処理を書く
}
if文の{}を省略した場合、最初の1文のみif構文の処理となる。以下のコードを実行すると、bのみ表示される。
public class Main{
public static void main(String[] args){
int a = 1;
int b = 2;
if (a = b)
System.out.println("a")
System.out.println("b")
}
}
##if-else文
if-else文の構文は以下の通りです。
if (条件式) {
// 条件に一致したときの処理
} else {
// 条件に一致しなかった時の処理
}
if-else if-else文
if-else if-else文の構文は以下の通りです。注意点として、elseとifの間で改行してしまうと、else文の中にif文が入っているという構文となります。
if (条件式A) {
//条件式Aに一致した時の処理
} else if (条件式B) {
//条件式Bに一致した時の処理
} else if (条件式C) {
//条件式Cに一致した時の処理
} else {
//全ての条件に一致しなかった時の処理
}
##switch文
switch文の構文は以下の通り
switch (条件式) {
case 値 : 処理
break;
case 値 : 処理
break;
default : 処理
break;
}
条件式が戻せる値の型には制限があり、戻せる型は、int型以下の整数型とラッパークラス、文字と文字列、列挙型に限られる。doubleやfloat、booleanなどは戻せない。
- char
- byte
- short
- int
- Character
- Byte
- Integer
- String
- enum
case値に使用できる値も制限があり、以下の通り
- 条件式が戻す値と同じ型か互換性がある型
- 定数であるか、コンパイル時に値を決めることができる(final変数及びリテラル)
- nullでない
case値にマッチした処理の後、breakを記述して、処理を抜けるが、breakがなければ、次のbreakが現れるまで、全ての処理が実行される。以下の処理では、a,b,c,dが表示される
int num = 1;
switch (num) {
case(1): System.out.println("a")
case(2): System.out.println("b")
case(3): System.out.println("c")
default: System.out.println("d")
}
##三項演算子
三項演算子は、条件に合致するかで、戻す値を変更する演算子で、構文は以下の通り
真偽値式 ? true場合の式 : falseの場合の式
三項演算子は、ネストすると見にくいがさらに1行で書くと見にくくなる。構文としては、?と:が交互に現れ、最後に:で終われば正しい構文
変数 = 式A ? 式Aがtrueの場合の式
: 式B ? 式Bがtrueの場合の式
: 式C ? 式Cがtrueの場合の式
: 全てがfalseの場合の処理
変数 = 式A ? 式Aがtrueの場合の式 : 式B ? 式Bがtrueの場合の式 : 式C ? 式Cがtrueの場合の式 : 全てがfalseの場合の処理
#配列
##配列インスタンスの生成
配列を使うには、newキーワードを使って、配列のインスタンスを宣言する必要がある。
配列には以下の特徴がある。
- 同じ型、もしくは互換性のある型の値しか使えない
- 扱える要素数はインスタンス生成時に決める。あとで要素数を変えることはできない。
int[] array = new int[4]
printlnメソッドは、引数に渡された値をコンソールに表示するメソッド。このメソッドにオブジェクトの参照を渡すと、参照先にあるインスタンスのtoStringメソッドを呼び出し、結果を表示する。このメソッドに配列の参照を渡すと、配列インスタンスのtoStringメソッドを呼び出し、クラス名とインスタンスを一意に見分けるためのハッシュコードを組み合わせた値を戻す。
##配列の宣言
配列型変数は、[]を使って宣言する。[]はデータ型の後ろに記述するだけでなく、変数名の後ろに記述することもできる。
int[] array;
int array2[];
配列は、2次元配列、3次元配列のような多次元配列を扱うことができ、[]の位置は一度にまとめて記述する必要はない。
int[][] array2; //2次元配列
int[] array22[]; //2次元配列
int array3[][][]; //3次元配列
int[][] array33[]; //3次元配列
配列は、インスタンス生成時に要素数を定義し、配列の変数の宣言時に要素数を指定するとコンパイルエラーとなる。
int[2] array; //コンパイルエラー
##配列インスタンスの生成方法
配列インスタンス生成時には、以下のようなルールがある。
- 必ず扱える要素数を指定する。
- 要素数の指定は、int型で行い、浮動小数点数ではできない。
- 2次元配列のインスタンス生成時、1次元目の要素数は省略できない。2次元目の要素数は別々に記述することが可能
- 変数とインスタンスの間で次元数は必ず一致させる。
コンパイルエラーの例
int[] array = new int[]; //要素数を指定していない
int[] array = new int[1.5]; //浮動小数点になっている
int[][] array = new int[][3]; //1次元目の要素数を指定していない
OKな例
int[][] array = new int[3][];
array[0] = new int[2];
array[1] = new int[2];
array[2] = new int[2];
//2次元目の要素数を別々に宣言
##配列インスタンスと要素の値
配列インスタンスを生成した後は、要素のへ値の代入をする必要がある。
int[] array = new int[3]
array[0] = 10;
array[1] = 15;
array[2] = 20;
配列の要素のデフォルト値は以下のように決まっている
型 | デフォルト値 |
---|---|
整数型 | 0 |
浮動小数点型 | 0.0 |
真偽型 | false |
文字型 | ¥u0000 |
オブジェクト型 | null |
初期化演算子を用いて、配列の要素の初期化することもできる。
int[] array = {10,20,30};
##配列の要素
配列のインスタンス生成時に要素の数を指定し、配列インスタンスは、指定された要素数分の変数を内部に持つ。各変数には、添字を使ってアクセスする。
要素にnullを代入した場合、その要素はどこも参照しなくなる。
public class Main {
public static void main(String[] args) throws Exception {
// Your code here!
String[] array = {"A","B","C"};
array[0] = null;
for(String str : array){
System.out.print(str); //nullBCと表示される
}
}
}
##配列インスタンスの生成と初期化、配列型変数の宣言と参照の代入
配列インスタンスの生成と初期化、配列型変数の宣言と参照の代入は、初期化演算子を使う方法が一般的。
int[] array = {1,2};
//下記のコードも同じ意味
int[] array = new int[]{1,2};
通常、newを使って配列のインスタンスを生成するときは、[]の中に要素数を指定するが、初期化演算子を使用した場合は、[]の中に要素数を指定してはいけない。
要素数0の配列インスタンスの生成は意味はないが、文法的に間違っているわけではない。
int[] array = {};
int[] array = new int[0];
多次元配列の場合、初期化演算子の中に初期化演算子をカンマ区切りで記述する
int[][] array = { {1,2,},{3,4} };
変数の次元数と参照先の次元数が一致しないと、コンパイルエラーになる。
int[][] array = new int[]{}; //コンパイルエラー
int[][] array = new int[][]{}; //エラーにならない
その他、newを使わずに初期化演算子だけで、記述すると、コンパイルエラーは発生しない。これは、初期化演算子が自動的に必要な次元数を算出して、必要な初期化を行うため。
int[][] array = {}; //コンパイルエラーにはならない
自動的に必要な次元数を算出する初期化演算子の機能は、変数宣言と同時にしか使えない。変数宣言と配列のインスタンス生成を分けて2行に記述する場合、初期化演算子は使えず、使う場合、次元数を明示的に記述する必要がある。
int[][] array;
array = new int[][]{}; //コンパイルエラーにならない
int[] array2;
array2 = {1,2}; // コンパイルエラー
##多次元配列
多次元配列では、2次元目以降の配列の要素数を揃える必要がない。
2次元目以降の要素数が異なる配列のことを非対称な多次元配列とよむ
下記コードは、2次元目の要素数が異なるが、コンパイルエラーとはならない。しかし、tmp.lengthで要素数を数える箇所で、参照を持たないnullの要素数を数えることができないので、実行時に例外がスローされる(実行時エラー)
public class Main{
public static void main(String[] args){
string[][] array = { {"あ", "い"}, null, {"う","え","お"} };
int total = 0;
for (String[] tmp : array) {
total += tmp.length;
}
System.out.println(total);
}
}
##継承・実現関係にあるクラスやインターフェースのインスタンスの動作
あるクラスが継承関係にある時、スーパークラス型の配列型変数で、サブクラスのインスタンスの集合を扱える。Object型しか扱わない配列型変数と、Stringしか扱わない配列インスタンスは、扱う型が異なるが、StringクラスはObjectクラスを継承しているため、以下のコードは、問題なく、コンパイル、実行出来る。
Object[] obj = {"A", "B", "C"};
これらの関係は、インターフェースと実現クラス、抽象クラスとそれを継承した具象クラスの間にも適用できる。
Aというインターフェースがあり、それをimplementsしたBというクラスがあったとすると、Bしか扱わない配列インスタンスの参照を、Aしか扱わない配列型変数に代入できる。
public interface A {}
public class B implements A {}
A[] array = new B[]{ new B(), new B() };
##配列のコピー(clone)
cloneメソッドを使用すると、配列のコピーを生成できる。あくまでコピーを生成する処理で、参照先は異なる。
int[] arrayA = {1,2,3,4};
int[] arrayB = arrayA.clone();
System.out.println(arrayA == arrayB); //参照先は異なるため、falseと表示される
多次元配列のcloneを行う場合、1次元目のインスタンスは異なるが、2次元目以降のインスタンスは共有される。
##配列のコピー(arraycopy)
配列の任意の部分のみを切り出してコピーする際は、Systemクラスのarraycopyメソッドを使用する。
arraycopyメソッドは、5つの引数を受け取る
引数 | 説明 |
---|---|
第一引数 | コピー元となる配列 |
第二引数 | コピー元のどの位置からコピーを開始するか(0始まり) |
第三引数 | コピー先の配列 |
第四引数 | コピー先のどの位置からコピーを開始するか(0始まり) |
第五引数 | 第二引数の位置から、幾つの要素をコピーするか |
char[] arrayA = {'a','b','c','d','e'};
char[] arrayB = {'f','g','h','i','j'};
System.arraycopy(arrayA,1,arrayB,1,3);
System.out.println(arrayB); //fbcdjが表示される
#ループ構造
javaには、以下4つの繰り返し構文がある。
- while文
- do-while文
- for文
- 拡張for文
##while文
while文は、条件式がtrueを戻す間、処理を繰り返すための構文。条件式は必ず真偽値を戻さなければならない。while文の繰り返し条件として記述できる式は1つだけ。
条件式にリテラル:trueを記述すると、無限ループになり、リテラル:falseを記述すると1度も実行されない。
while (条件式) {
//繰り返し処理
}
##do-while文
do-while文は繰り返し処理を実行してから、条件判定を行う。そのため条件にかかわらず、最低1回は実行される。
do-whileの条件式の後ろには、;が必要。
doの後に()はつかない
do {
//繰り返し処理
} while(条件式);
##do-while分の{}の省略記法
if文と同じように{}を省略することが可能。省略した場合、1つの文だけが、繰り返し処理の対象となる。
int i = 0;
while(i++ < 10)
System.out.println("a"); //繰り返し対象
System.out.println("b"); //繰り返し対象外
do-while文で{}を省略した場合は、doの後ろには一つしか文を記述できない。複数記述するとコンパイルエラーとなる。
int i = 0;
do
System.out.println("a");
System.out.println("b"); //コンパイルエラー
while (i++ < 10);
##随時追記しています。