今更Java入門

Javaとは

名前の由来

開発元のサン・マイクロシステムズ社の近くのコーヒーショップのウェートレスがつけていたシャツのロゴ「It's a jungle out there, So drink your java!」からとったと言われている。

もともとOakという名前だったが、Oakという名称は当時すでに商標登録されていたため,正式リリースのために別名を付けた。

コンパイルの方法

javac ファイル名で実施。

$ javac sample.java

定数の定義方法

final int 変数名

用語

  • ネスト

カッコの入れ子のこと

  • リテラル

文字や数字の表記のための値

  • イミュータブル

作成後に値の変更ができないこと

  • ラッパー

あるクラスやデータ型などが提供する機能やデータを含みつつ、 別の形で提供するもののことをラッパーという。 元の機能を包み、覆い隠す役割を果たすためにこのように呼ばれる。

  • JAR(Java Archive)

コンパイルされた複数のJavaバイトコードや、画像などのリソースを一つにまとめてZIP圧縮したファイルのこと。

クラスファイルをすべて1つのファイルにまとめる

  • マニフェストファイル

バージョンや、jarファイルの作成に使用したツールなどのJARファイルの内容が記述されている

Manifest-Version: 1.0
Ant-Version: Apache Ant 1.6.5
Created-By: 1.4.2_09-b05 (Sun Microsystems Inc.)
Main-Class: Sample

データの型

  • プリミティブ型

格納サイズが決まっているもの(int, short, long, fload, double, char, boolean)

  • 参照型

格納サイズが決まっていないので、格納したメモリの先頭アドレスを参照する型

  • 変換

    • 明示的・・・プログラマが意図的に行う(キャスト)
    • 暗黙的・・・計算機が自動的に行う(int i = 1, double d = i;)

列挙型(enum)

可読性を上げるために複数の定数を一つの型に定義する方法。

// 列挙型の例
public class EnumMonthList {
    enum Month {
        JANUARY , FEBRUARY , MARCH, APRIL,
        MAY , JUNE , JULY, AUGUST,
        SEPTEMBER , OCTOBER , NOVEMBER, DECEMBER,
    }
}

Javaの場合は、列挙型は、Enumクラスのサブクラスとして扱われる特殊なクラスとなっている。

列挙型を使用するメリットとして、下記の点がある。

  • 可読性が上がる

列挙型を使用することによって、引数が何を示しているか分かりやすくなるので、可読性が高くなる。


// 列挙型を使わないケース
method1(int m, int a);

// 列挙型を使うケース
method1(FileMode m,FileAccess a);
  • 引数の値が範囲外になった場合の例外処理の考慮が不要

取り得る値の範囲が予め決まっているので、引数の値が範囲外になった場合の処理を考慮しなくても良い。

// 列挙型を使わないケース
method2(int m);

// 列挙型を使うケース
method2(Month m);

また、定数との違いとして、列挙型を使った方が呼び出し側はどの値を指定すればよいかが明確になり、ソースコードの可読性がより上がる。

public enum SignalStatus {

    STOP("赤"),
    GO("青"),
    CAUTION("黄色");

    // フィールドを宣言
    private String status;

    // enum型のコンストラクタは必ずprivateにする必要がある
    private SignalStatus2(String str) {
        this.status = str ;
    }

    // 信号の色を表示するメソッド
    public void print() {
        System.out.println( "信号の色は" + this.status + "です。");
    }

public static void main(String[] args) {
    SignalStatus.GO.print();
    SignalStatus.STOP.print();
    SignalStatus.CAUTION.print();
}

FQCN(Full Quanlifed Class Name)

完全修飾クラス名。

ソースコード中で特定のクラスをインポートする際の、 クラス名の指定方法。

FQCNでは、import パッケ-ジ名.クラス名のようにパッケージ名を先頭に記載する。

省略すると、 import パッケ-ジ名.*; ※*は全てのクラスを表す

JVM(Java Virtual Maschine)

  • 各OS用にバイトコ-ド(マシン語)を翻訳
  • Javaのマシン語は特定のCPUに依存しない本用的なマシン語

オブジェクト指向

現実の概念を真似たもの。

インスタンス

  • インスタンスの生成
クラス名.変数名 = new クラス名();
  • this

インスタンス自身を示す

フィ-ルド

クラスブロック内の変数。

コンストラクタ

インスタンス生成時に実行されるメソッドのこと。 主にはフィールドの初期化に使われ、初期化忘れを防ぐことができる。

  • コンストラクタの定義

public クラス名()の用に定義する。

  • this()

自クラスのコンストラクタの呼び出し

・super()

ス-パ-クラスのコンストラクタの利用

・コンストラクタは複数記述でき、引数などに応じて処理を変えることなども可能なので、 フィ-ルド変数の宣言時の初期化より拡張性が高い ・コンストラクタの中にメソッドは基本的には書かない

なぜオブジェクト指向(クラス分け)を使うのか?

バグが発覚したときや、仕様変更したいときなど、 対象がコードとして独立していると、作業がやりやすい。

○ 処理をどのように分けるべきか?

・独立性が高いものを分割 外部に依存しないもの、内部に隠蔽する情報(変数)を探す。 ・仕様変更が起きそうな機能で分割 「今後どういう変更が予想されるか」が保守性の維持に重要。

一般に、分かれている物を統合する方が、 統合するものを分離するよりも簡単なので、 処理を分離できそうな部分は積極的に分離する判断をする事が多い。

分けることが大事であって、 「関数を別にする」するか「クラス自体を分ける」ことで 実現するかは時と場合による(プログラムの規模とか)。 ソートとカウントは並行した方が効率がいいなど統合した方がよい場合も。

○ オブジェクト指向の流れ

  1. 仕様決定
  2. クラス(役割)分け
  3. メッセージ(オブジェクト間の関係)
  4. メソッド(何を行うか)
  5. フィールド(名前、数などの保持すべき情報)

○ 上手く分け方が分からないとき

  1. 全体を1クラスの1メソッドに押し込んでみる。
  2. メソッドとして独立させたい部分を独立させていく。
  3. いくつかのメソッドで共有される変数をクラスに切り出す。

・メイン処理(ロジック)とそれ以外で分けてみる 「データを読み込む」「ソートする」「ソートした結果を出力する」 「出現頻度を計算する」「出現頻度を出力する」 ↓ 入出力はメイン処理ではない。 メイン処理はソートと頻度のカウント。 ↓ 「データの入出力」と「メイン処理(ロジック)」で処理をを分ける。 ソート対象を標準入力から受け取ったり、結果をDBに書き込む、 などの仕様変更が起きてもメイン処理を使い回せる。

「データの入出力」

・入力クラス
ファイルを読み込み、ファイルのデータを1行ずつ返す

・出力クラス
データを渡すと、ファイルに書き出す

・制御クラス
エラー表示などを担当するとともに、
各クラスを組み合わせて全体の制御をするクラス

「メイン処理(ロジック)」

・入力値検証クラス
値チェックする

・ソートクラス
ソートする

・カウントクラス
出現頻度を計算する

静的(static)

クラスに属し、インスタンス化しなくても使用することができるメソッド、フィールドなどを示す。

○ 静的メソッド(クラスメソッド) インスタンス化しなくても呼び出せる main()メソッドなど

○ 静的フィ-ルド(クラスフィールド) 同じクラスのインスタンスの間で共有できるフィ-ルド ※RPGのパ-ティの財布などに使える

カプセル化

・オブジェクト内部の公開する必要のない情報を隠す機能。

○ アクセス修飾子 ・フィ-ルドはprivate(自クラス以外のアクセス禁止)が基本 ・メソッドはpublic(全てのクラスからアクセス可能)が基本 ・publicクラスは1ファイルにつき1クラス ・ファイル名とそのpublicクラスのクラス名が一致していなくてはならない ・同ファイルにpublicクラスが混在すると、容易にアクセスができるので、スペゲッティプログラムになりうる(セキュリティの問題も)。 ・publicクラスを1ファイルに1つとすれば、”部品化”が行いやすい。

継承(インヘリタンス)

・expends : 親クラスを継承した子クラスを作成

public class 子クラス extends 親クラス{
}

・public final : finalをつけると、継承、オ-バ-ライド禁止

public final class 子クラス extends 親クラス{
}

・super : 親クラスのメソッドを呼び出し

super.メソッド()

抽象クラス

抽象メソッド(処理が未確定のメソッド)が含まれるクラス。

複数のクラスを作成する際に、クラス間で一部のメソッドで処理内容が異なるが、同じ処理を行う共通メソッドを持っている場合に利用する

abstract class クラス名{}
  • インスタンス化できない
  • オ-バ-ライドが強制される
  • 分かりやすいコ-ドが書ける
public abstract void method(引数){};

インタフェ-ス

抽象メソッドしか持たないクラス。

interface インターフェース名{}

インタフェ-スでは、

  • フィ-ルドは定数しか利用できないのでpublict static finalとなる

また、

  • 複数のインタフェ-スを親とする多重継承が可能 ⇒ 全部抽象メソッドなので、衝突が起きない
  • 処理の統一化 ⇒ interfaceで決めたの仕様の通りに実装することが強制されるので、classが提供するメソッドの呼び出し方を統一できる

実装(インプリメント)

インタフェ-スを子クラスでオ-バ-ライドしてメソッドの処理を決定すること。 実装して小クラスを作成するにはimplementsを用いる

public class Fool implements Human {
}

implementsとexpendsの使い分け

  • implementsとexpendsの併用も可能
public class Fool extends Character implements Human {
}
  • インタフェ-スからのインタフェ-スへの継承にはextendsを用いる
  • クラスからクラスへの継承にはextendsを用いる
  • インタフェ-スからクラスへの継承にはimplementsを用いる

多態性

インスタンスを曖昧=子と親はほぼ同じに捉える

  • まとめて処理可能(引数、戻り値、条件文などの記述が簡単になる)

  • 同じメソッドでも、子クラスごとに異なる動作をする

  • シグネチャ

メソッド名、引数の型、順番の組合せ

  • オ-バ-ロ-ド

メソッド名が同じメソッドでシグネチャが異なるメソッドを定義すること。 シグネチャが異なるなら同じメソッドでも定義可能。 メソッド名が同じの方が、処理の概要だけ決め、呼び出すとき内部の細かな処理を意識しなくてよい

// 例 : toStringをオーバロード
toStirng(int i)
toString(double d)
  • オ-バ-ライド

ス-パ-クラスのメソッドをサブクラスで上書き。

// public final : finalをつけると、継承、オ-バ-ライド禁止
public final class 子クラス extends 親クラス{
}

標準クラス(API)

  • 標準クラスのパッケ-ジ名
パッケ-ジ名 提供内容
java.applet アプレット関連の機能
java.awt 抽象的なWindowsの部品
java.io ファイルやネットワ-クでの入出力
java.lang Javaの基本的なクラス
java.net ネットワ-クに関係するさまざまな機能
java.util ユ-ティリティ機能
  • ArrayListクラス

    • オブジェクトの集合を配列のように扱う
    • 生成時に容量を指定しなくて良い
    • インデックスを気にせず追加可能
    • 要素の排除が簡単
  • Systemクラス

printメソッドを使うとtoStringが同時に呼び出される。

Objectクラス

  • すべてのクラスの祖先
  • すべてのインスタンスをObject型変数に格納可能である
  • toString()やequals()が定義されている
  • ==はアドレスの一致(等値)、equals()は内容(等価)

ラッパ-クラス

  • 基本デ-タ型に対応したラッパ-クラスがjava.langパッケ-ジにある
  • 上記の型変換は自動で行われる(int ⇒ Integerなど)

基本デ-タ型

boolean 1bit
byte 8bit
char 16bit
short 16bit
int 32bit
float 32bit
long 64bit
double 64bit

文字列

String.concatとStringBuilder.appendの違い

  • 単一の文字列を追加する場合はconcatメソッド、
  • 複数個の文字列を追加する場合はappendメソッド

StringBuilderとStringBufferの違い

  • StringBuilder

高速 、普段使い

  • StringBuffer

同期化保証(固有ロック(synchronized)が適用されている)、 遅い、同じインスタンスで複数のスレッドにアクセスするとき用

内部クラス(インナークラス)

classブロックの中で定義されたクラスのこと。

  • エンクロージングクラス

クラスを囲っている外側のクラスのこと。

特定のクラスでのみ利用するクラスなどは、内部クラスとして定義することで、 関係ない他のクラスから誤って参照されてしまうのを防げる。

class エンクロージングクラス名 {
class インナークラス名 {
...インナークラスの実装...
}
...エンクロージングクラスの実装...
  • 匿名クラス(無名クラス)

名前を持たいない他では使わず、その場でしか使わない一時的なクラス。

継承/実装からインスタンス化までをまとめて一文で表現できる。 新しくファイルを作る必要がないなど、手軽に作れるというメリットがある。

コピー&ペーストの多用やプログラムが複雑になりやすいといったデメリットも多い。

new インターフェイス名() { メソッドのオーバーライド }

  • コレクション(コンテナ)クラス

オブジェクトの集合を扱うため。 List、Map、Setの3種類。

ジェネリックス(総称性)

List<型引数>で指定する。 指定した型専用のリストを生成可能。

List gene = new ArrayList();
gene.add("Java");
String str = gene.get(0);

ジェネリックスを利用しないで記述した場合は下記のようになる。

List list = new ArrayList();
list. add("Java");
String str = (String)list.get(0);

リストから取り出した要素はすべてObject型と見なされ、 いちいち型キャストしなければならない。

キャストの手間や、キャストミスによる例外の発生、 リストに型と異なる値が挿入されるなどを防げる。

シングルトン

オブジェクト指向において、クラスに対するインスタンスが必ず一つになることを保証する設計パターン。

public class Member {

	private static Member singleton = new Member();

  // privateでコンストラクタを記載することで、外部からインスタンスが作成できなくなる
	private Member() {};

  // 外部からインスタンスを利用する際は、インスタンスを取得するメソッドからインスタンスを利用する
	public static Member getInstance() {
		return singleton;
	}

エラー

  • 文法エラー

コンパイルエラーになる文法の誤り。

  • 論理エラー

結果が想定と異なる。

  • 実行エラー

強制終了するようなエラー。
例外処理で対応できる。

例外クラス

  • Error

回復見込みがない (メモリ不足、クラスファイルの破損)

  • Exception

回復見込みがある (ファイルに読み書きできない、ネットに接続できない)

  • RuntimeException

回復が必須でない (変数の添字が不正、変数がnull)

例外の送出

  • throw文

意図的に起こしたい例外を起こす。 独自の例外を作ることで、多様な例外処理を記述し、 様々な例外に対応でき、コードも分かりやすくなる。

throw 例外インスタンス

1度だけ使いたい場合は、下記のように指定。

throw new 例外クラス名("エラーメッセージ");

例外処理

  • try-catch文
try{エラーが起きる可能性がある処理;}
catch(例外クラス 変数名){処理内容;}
finally{処理内容;}

例外の伝搬

呼び出し先のメソッドで 例外処理が記述されておらず、例外がキャッチできない場合呼び出し元のメソッドに例外の対応が委ねられること。

  • throws(スロー宣言)

throwsを付けたメソッドは例外のキャッチをしなくてもよい。
呼び出し元のメソッドが請け負うことになる。

//修飾子 型 メソッド名()
throws 例外クラス1, 例外クラス2{処理内容;}