2014年12月11日木曜日

Java基礎(1章~7章メソッドまで)

Javaの特徴

開発ツールが無料

オブジェクト指向

一度作ったプログラムはどこでも動く(Write Once, Run Anywhere)
※Javaを動かすにはJRE(Java Runtime Envelopement)が必要


開発準備

JDK(Java Development Kit)をインストール
→Java開発キット(JREが含まれている)

環境変数「Path」を設定


コマンドプロンプト

検索窓に「cmd」で起動

「cd フォルダ名」でフォルダ移動(相対or絶対パスで指定)

「dir」で現在のフォルダの中身を表示



プログラムの作成と実行

class クラス名 {
    public static void main(String[] args) {
        実行するプログラム(mainメソッド)
    }
}

「クラス名.java」で保存

「javac クラス名.java」でコンパイル
→「クラス名.class」が生成(バイトコード)

「java クラス名」で実行
→mainメソッドが実行される



コメント

「//コメント」一行コメント

「/* コメント */」複数行コメント

「/** コメント */」文書化(javadoc)コメント



画面出力

改行無し
System.out.print("○○○")

改行する(引数に何も指定しないと改行だけ)
System.out.println("○○○")



文字列

「"」(ダブルクォート)で囲むと文字列
→文字列リテラルと呼ぶ

「+」で文字列を連結

「\n」で改行



記述ルール

読みやすいように「インデント」を入れる

単語の途中でスペースを入れない

文字列の途中で改行を入れない



変数

変数を使うためには「宣言」が必要
→ int x;

変数宣言は2つ以上まとめても可能
→  int x, y;

int型には「整数」が入れられる
→「123」などの数字を「整数リテラル」と呼ぶ

整数÷整数の結果は、小数以下が切り捨てられる

変数宣言と同時に値を代入することを「初期化」という
→ int x = 2;

値の入っていない変数を使うとコンパイルエラー

使用できる文字はAからZ、aからz、0から9、アンダーバー(_)、$
(例) name, old, no32

先頭文字には数字の0から9は使用できない
(例) 12pointなどは×

大文字と小文字は区別される
(例) old と Oldは別の変数

予約語は使用できない
(例) char や classなどの予約語は使用できない

長さの制限は無い



基本型

整数型
→byte, short, int, long(左から順に大きく)

浮動小数点型
→float, double(左から順に大きく)

文字列(基本型ではなくクラス)
→String



定数

finalをつける(PHPのconst)
→final int PI = 3.14;



キーボードからの入力

「import java.util.Scanner;」をファイルの最初に記述

「Scanner stdIn = new Scanner(System.in);」でstdInを生成

「stdIn.nextInt()」で整数を読み込む

「stdIn.next()」「stdIn.nextLine()」で文字列を読み込む




乱数の生成

「import java.util.Random;」をファイルの最初に記述

「Random rand = new Random();」でrandを生成

「rand.next(○○)」で乱数を取得
→「3」を設定すると「0,1,2」を取得できる

※10~99の乱数を取得する場合「rand.next(90)+10」



if文

if (○○==○○) {
    ・・・
} else if (○○==○○) {
    ・・・
} else {
    ・・・
}

ifの処理が1行の場合は{}を省略できる
if (○○○)
    ・・・


switch文

switch (x) {
    case 0:
        ・・・
        break;
    case 1:
    case 2:
        ・・・(a)
        break;
    case 3:
        ・・・(b)
    default:
        ・・・(c)
}

フォールスルー

breakされるまで処理を続ける

※上の例は…

x=1だと(a)が実行される
x=2でも(a)が実行される
x=3だと(b)(c)が実行される



do文

do {
    ・・・
} (x < 10);

【セミコロンを忘れない!】

※この例ではxが10より小さい間ループを続ける
 
(最初からxが10以上でも1回はループする



While文

while (x < 10) {
    ・・・
}

※この例ではxが10より小さい間ループを続ける

(最初からxが10以上ならループしない




インクリメント


前置

x = 3;
y = ++x;

yには「4」が入る
(インクリメントしてから代入)



後置

x = 3;
y = x++;

yには「3」が入る
(代入してからインクリメント)




for文

for (int i = 0; i < 10; i++) {
    ・・・
}

※この例では10回ループが回る



break, continue

for (int i = 1; i <= 10; i++) {
    if (i == 3) {
        continue;
    }
 
    if (i == 5) {
        break;;
    }
}

この例では3回目のループをスキップ、5回目で抜ける



ラベル付ループ

abc:
for (int i = 1; i <= 10; i++) {
    for (int j = 1; j <= 10; j++) {
        if (j == 5) {
            break abc;
        }
    }
 
}

この例では5回目のループで、一番外側のループをまで抜ける



printf

出力したい値をフォーマットできる

「%」を出力したい場合は「%%」とする
→エスケープ処理

System.out.printf("%05f", 123);
→00123

System.out.printf("%6.2f", 12.34567);
→ 12.34



基本型


整数型

char, byte, short, int, long


浮動小数点型

float, double

論理型

boolean




演算と型


型の異なる数値の演算は大きい方の型に変換される

10 / 4 = 1 (int ÷ int = int)

10 / 4.0 = 2.5 (int ÷ double = double)
→int÷doubleなので左辺のintがdoubleに変換される



キャスト

double x = 1.234;
int y = (int)y;

double型の「1.234」がint型に変換され「1」になる



配列


宣言

int[] a;(int a[];でもOKだが昔のやり方であまり使われない)


生成

int[] a = new int[5];
→aは配列本体を参照する変数(参照型)



構成要素のアクセス

int x = a[2];
→配列「a」のインデックス「2」がxに代入される
(インデックスは0から始まる)
※存在しないインデックスを指定すると実行時にエラー



規定値

配列の各要素は各型の規定値で初期化される(intならば0)


要素数の取得

int arrayCount = a.length;
→配列aの要素数を取得



初期化

int[] a = {1, 2, 3, 4, 5};
→宣言と同時だったら初期化できる

int[] a;
a = {1, 2, 3, 4, 5};
→宣言の後に代入はコンパイルエラー

int[] a;
a = new int[]{1, 2, 3, 4, 5};
→これならOK



拡張for文(for-in,for-each)

int a[] = {1, 2, 3, 4};
for (int i : a) {
    System.out.print(i);
}
→配列aの中身が順番にi代入され「1234」と表示される
※phpのforeachと同じ(括弧の中は逆、asではなく:)



短絡評価


int month = 2;
if (month >= 3 && month <= 5) {
    System.out.print("春");
}
※この場合「month >= 3」がfalseでもうifの中を実行しないのが確定、その場合「month <= 5」は評価されない



シャッフルのアルゴリズム

偏らない方法を使うと良い(Fisher-Yatesシャッフル)

Random rand = new Random();
int[] ary = {1,2,3,4,5,6,7,8};
 
for(int i = ary.length; i > 1; --i){
    int index1 = i - 1;
    int index2 = rand.nextInt(i);
 
    //交換
    int temp = ary[index1];
    ary[index1] = ary[index2];
    ary[index2] = temp;
}

文字列の比較はs1.equals(s2)で行う
→(s1 == s2)はアドレスを比較しているだけで間違い



配列のコピー

配列変数を他の変数に代入しても参照先がコピーされるだけ。
→配列の要素1つ1つはコピーされない



空参照とガーベジコレクション

参照型にnullを代入すると、何も参照していない状態になる

String s = "abcd";
s = null; //何も参照していない


どこからも参照されなくなったオブジェクトはガーベジコレクションに回収され消える


finalな変数は参照先を変えることができないが、格要素は変更できる

int [] ary = {1, 2, 3};
ary = null        //エラー
ary = new int[4]; //エラー
ary[1] = 10;      //OK



多次元配列

宣言

//2x4の2次元配列の宣言
int[][] a = new int[2][4];


初期化

//2次元配列の初期化
int[][] b = { {1,2,3}, {4,5,6} };


多次元配列は以下のように動的に要素数を決めることができる

int[][] x = new int[2][];
x[0] = new int[4];
x[1] = new int[7];


※左詰めで最低1個は要素数を指定する必要がある

int[][][] x = new int[][][];   //エラー
int[][][] x = new int[][3][];  //エラー
int[][][] x = new int[4][][2]; //エラー
int[][][] x = new int[4][2][]; //OK


多次元配列も初期化子で初期化できる

int[][] a = {
    {1,2,3},
    {4,5,6},//最後のカンマは無くてもOK
}


バブルソート

int[] ary = {2, 5, 4, 1, 3};
for (int i = 0; i < ary.length - 1; i++) {
    for (int j = i + 1; j < ary.length; j++) {
        if (ary[i] > ary[j]) {
            int temp = ary[i]; //入れ替え
            ary[i] = ary[j];
            ary[j] = temp;
        }
    }
}



メソッド

ひとまとまりの処理はメソッドとしてまとめられる


メソッド宣言

static 戻り値の型※1 メソッド名(仮引数の型 仮引数名※2,…) {
    メソッド本体の処理
}
※1 戻り値が無い場合は「void」
※2 引数は無くても良いし、いくつでも良い
→引数が無い場合は「void method1() {…」のようになる

例)
static int max(int a, int b) {
    if (b > a) {
        return b;
    }
    return a;
}


メソッド呼び出し

//変数xにmaxメソッドの結果が入る
int x = max(1, 3);

→メソッドが呼ばれると、プログラムの流れはメソッド本体に移る



return文

returnでメソッドの戻り値を返し、メソッドの処理をそこで終了する
→戻り値が無い場合は「return;」としてもOK


値渡し

メソッドの引数は値渡しで行われる
→仮引数の値を書き換えても、実引数の引数は変わらない


voidメソッド

戻り値が無いメソッドは戻り値の型の所を「void」と書く
→return文を書かなくても良い、書く場合は「return;」とする


インポートのワイルドカード

java.util.*;
→java.utilパッケージの全てのクラスをインポートする


有効範囲(スコープ)

有効範囲外の変数は使うことができない

class Example {
 
  //フィールド
  static int x;
 
 //メソッド仮引数
  void method1(int y) {

    //フィールドの使い方
    Example.x = 100;
  }
 
  void method2() {
    int z;  // 局所
    if (z == 0) {
      int a; // 局所
    }
  }
}

x:フィールドなのでどこからでもアクセスできる(最強)

y:method1の仮引数なので、method1の中でしかアクセスできない(method2からはアクセスできない)

z:method2の中で宣言された変数なので、method2の中(かつ宣言された後)しかアクセスできない

a:ifブロックの中で宣言された変数なので、ifの中(かつ宣言された後)しかアクセスできない



フィールド

メソッドの外でstaticをつけて宣言する変数でどこからでもアクセスできる
→アクセスするときは「クラス名.フィールド名」とする

class Example {

  //フィールドx
  static int x;
 
  void method() {

    //フィールドに代入
    Example.x = 100;
 
    //表示(100と表示される)
    System.out.print(Example.x);
  }
}


※注意点

フィールドと同じ名前の変数を宣言できてしまう

→その場合は「クラス名.」をつけるとフィールドにアクセスできる

→変数名のみだとローカル変数の方をアクセスしてしまう

※フィールドにアクセスする場合は「クラス名.」をつけた方が間違いがない!



class Example {

  //フィールドx
  static int x;

  public static void main(String[] args) {
 
    //フィールドに代入
    Example.x = 1;
     
    //フィールドを表示(1と表示)
    System.out.print(Example.x);
     
    //単にxとしてもOKだが…(1と表示)
    System.out.print(x);
     
    //フィールドと同じ名前のローカル変数を宣言してもOK
    int x = 2;
     
    //変数名だけだとローカル変数が優先して表示される(2と表示)
    System.out.print(x);
     
    //クラス名.をつければフィールドが表示される(1と表示)
    System.out.print(Example.x);

  }
}


P240~247は授業でやらない



配列を扱うメソッド


メソッドの引数に配列を使うことができる

//引数にint型の配列を使う
static int maxOf(int[] a) {
    ・・・
}



メソッドの戻り値にも配列を使うことができる

//戻り値にint型の配列を使う
static int[] searchOf(int a) {
    ・・・
}



配列の引数

引数に配列を渡すと、配列の参照(アドレス)が渡される
→メソッド内で配列の要素を更新すると、呼び出し元の配列の要素も更新される

class Example {
  static void test1(int[] ary) {
    //引数で渡された配列の要素を書き換える
    ary[0] = 999;
  }
 
  public static void main(String[] args) {
    int[] a = {123, 456, 789};
 
    //123と表示される
    System.out.println(a[0]);
 
    //メソッド内でa[0]が書き換えられる
    test1(a);
 
    //999と表示される
    System.out.println(a[0]);
  }
}



三項演算子(条件演算子)

if-elseの代わりに使うことができる
→以下の処理は同じ結果となる

int x = 10;

//三項演算子
String s = x == 10 ? "YES" : "NO";

//YESと表示される
System.out.print(s);

==========================

int x = 10;
String s = null;

if (x == 10) {
s = "YES";
} else {
s = "NO";
}

//YESと表示される
System.out.print(s);



JavaDocコメント

特別なフォーマットでコメントを書くと、ドキュメントとして出力することができる

/**
 * 受験人数の桁数を取得
 *
 * @param cnt 受験人数
 * @return 受験人数の桁数
 */


1.「/**」で始まり「*/」で終わる
2.「@param 仮引数の変数名」の後にメソッドの引数の説明を記載
3.「@return」の後にメソッドの戻り値の説明を記載
4.「@see」の後に参照先を記載


※文字化けする場合は以下のオプションを追加

-encoding UTF-8
-charset UTF-8




オーバーロード(多重定義)


同じ名前のメソッドを作ることができる
ただし、同じシグネチャのメソッドは作れない


シグネチャ

メソッド名、仮引数の個数、仮引数の型



//このメソッドが既にあったとすると…
static int ave(int x, int y) {
・・・
}

//仮引数の個数が違うのでOK(オーバーロード)
static int ave(int x, int y, int z) {
・・・
}

//仮引数の型が違うのでOK(オーバーロード)
static int ave(String x, String y) {
・・・
}

//返却型が違うだけなので×
static double ave(int x, int y) {
・・・
}

//仮引数の変数名が違うだけなので×
static int ave(int abc, int xyz) {
・・・
}

2014年12月9日火曜日

配列が苦手な方へ

配列が苦手な方はとりあえず、以下の問題に答えられるようになっておけばOKです。

ポイントとしては『二次元配列とは配列の中に配列が入っている』ということです。




【問題】

二次元配列を使用して以下のように数字を出力せよ

ただし、初期化子を使って配列を初期化しないこと

表示時にはfor文と拡張for文と2種類使うこと




【出力結果】

1
1 2
1 2 3

1
1 2
1 2 3









【回答例】


class ArrayTest {
 
  public static void main(String[] args) {
   
    //二次元配列は配列の中に配列を格納
   
    //一次元目のみの要素を確保
    //(二次元目は後から動的確保)
    int[][] a = new int[3][];
   
    //0番目の要素の二次元目を動的確保
    //一次元目の要素には一次元配列を格納
    a[0] = new int[1];
    a[0][0] = 1;
   
    //1番目の要素の二次元目を動的確保
    a[1] = new int[2];
    a[1][0] = 1;
    a[1][1] = 2;
   
    //2番目の要素の二次元目を動的確保
    a[2] = new int[3];
    a[2][0] = 1;
    a[2][1] = 2;
    a[2][2] = 3;
   
   
   
    //for文でインデックスを使って表示
    for (int i = 0; i < a.length; i++) {
      for (int j = 0; j < a[i].length; j++) {
        System.out.printf("%d ", a[i][j]);
      }
      System.out.println();
    }
   
    System.out.println();
   
   
    //拡張for文で各要素を取得しながら表示
    //一次元目は配列を取得
    for (int[] t : a) {
      //二次元目でintの値を取得
      for (int num : t) {
        System.out.printf("%d ", num);
      }
      System.out.println();
    }
  }
}

2014年12月3日水曜日

参照型の引数は参照渡しではない

Javaのメソッドの引数は、参照型の場合は参照渡しになると思っていませんか?

そもそも、値渡しとはメソッドを呼ぶときに、引数にはその値のコピーを渡すもので、メソッド内でそのコピーされた値を書き換えても、元の引数は変更されないという動きになります。

一方、参照渡しとはメソッドの引数を呼ぶときに、引数にはその値の参照を渡すもので、メソッド内でその参照先を書き換えると、元の引数も書き換わってしまうという動きになります。

確かに、下のようなコードだと参照渡しのような動きをします。


class Ref1 {
  public static void main(String[] args) {
    // サンプル1
    int[] array = {10, 20, 30};
    System.out.println("呼び出し前:" + array[0]);
    method(array);
    System.out.println("呼び出し後:" + array[0]);
  }

  static void method(int[] array){
    //引数の配列のindex0を書き換える
    array[0] = 100;
  }
}


実行結果

呼び出し前:10
呼び出し後:100



しかし、以下のようなコードだとどうなるでしょう?

class Ref2 {
  public static void main(String[] args) {
    // サンプル2
    int[] array = {10, 20, 30};
    System.out.println("呼び出し前:" + array[0]);
    method(array);
    System.out.println("呼び出し後:" + array[0]);
  }

  static void method(int[] array){
    int[] nums = {100, 200, 300};
    //引数で渡された配列を書き換える
    array = nums;
  }
}


実行結果

呼び出し前:10
呼び出し後:10


メソッドの引数で渡された配列を書き換えているのに、メソッド実行後も配列の中身は変わっていません。

これはメソッドの引数が参照型の場合は、アドレス値をコピーしたものが引数として渡されているからです。
つまりは、基本型も参照型も値渡しをしているということです。

引数として渡されたアドレスの参照先である実体を操作することは可能です。
しかし、アドレス値そのものを書き換えても、コピーしたものを上書きしただけなので、元のアドレス値は何も変わらないというわけです。

カプセル化の意義をRPG風にたとえてみた

なぜクラスをカプセル化する必要があるのか疑問に感じる人も多いのではないでしょうか。

カプセル化とはインスタンス変数をprivateにして、直接アクセスできないようにし、メソッドを通じてのみ扱えるようにすることです。

では、これをRPG風に例えて説明してみましょう。

戦士のステータスとして「力」「武器の強さ」「攻撃力」を持っているとします。

これをクラスにするとこんな感じ

class Fighter {

  //力
  int strength;

  //武器の強さ
  int weapon;

  //攻撃力
  int attack;
}


大体のRPGでは「攻撃力」は「力」と「武器の強さ」の合計で決まるので、このクラスもそうしたい…

でも、現状の書き方では以下のように設定できてしまいます。


//戦士ジョンを生成
Fighter jon = new Fighter();

//ジョンの力を「10」に設定
jon.strength = 10;

//ジョンの武器の強さを「25」に設定
jon.weapon = 25;

//ジョンの攻撃力を「99」に設定??
//10 + 25で35じゃないの??
jon.attack = 99;



この場合は「攻撃力」を直接設定できてしまうので、ありえない値にできてしまう…

だったら、「攻撃力」は直接アクセスできないようにして、「力」または「武器の強さ」を設定したら自動的に計算してくれるようにしてしまえ!

それを踏まえたクラスがこちら

class Fighter {

  //力(直接アクセスできない)
  private int strength;

  //武器の強さ(直接アクセスできない)
  private int weapon;

  //攻撃力(直接アクセスできない)
  private int attack;


  //力を設定するメソッド
  void setStrength(int strength) {
 
    //力を設定
    this.strength = strength;
 
    //攻撃力を設定
    setAttack();
  }

  //武器の強さを設定するメソッド
  void setWeapon(int weapon) {
 
    //武器の強さを設定
    this.weapon = weapon;
 
    //攻撃力を設定
    setAttack();
 
  }

  //攻撃力を設定(他のクラスからは呼べない)
  private setAttack() {
 
    //攻撃力 = 力 + 武器の強さ
    attack = strength + weapon;
  }

  //攻撃力を取得
  int getAttack() {
    return attack;
  }
}


このクラスであれば、設定できるのは力と武器の強さだけで攻撃力は自動で計算してくれることになる

//戦士ジョンを生成
Fighter jon = new Fighter();

//ジョンの力を「10」に設定
jon.setStrength(10);

//ジョンの武器の強さを「25」に設定
jon.setWeapon(25);

//攻撃力は35と表示される
System.out.printf("攻撃力は%d", getAttack());





さらに、攻撃力の計算を「力」+「武器の強さ」の2倍に変更したい場合は、Fighterクラスの「setAttac()」を修正するだけで済みます。



//FighterクラスのsetAttackを修正
private setAttack() {

  //攻撃力 = (力 + 武器の強さ)の2倍に修正
  attack = (strength + weapon) * 2;
}



/*
  以下のコードはそのまま
*/

//戦士ジョンを生成
Fighter jon = new Fighter();

//ジョンの力を「10」に設定
jon.setStrength(10);

//ジョンの武器の強さを「25」に設定
jon.setWeapon(25);

//攻撃力は70と表示される
System.out.printf("攻撃力は%d", getAttack());


このようにあるステータスに対する約束事を必ず守らせるため、カプセル化しておくとそうすることしかできなくなるので、間違いが無くなる。

変更する場合でも、Fighterクラス側を修正するだけで良くなり保守性高まる。

つまり、カプセル化したほうが便利ですよね?

staticメソッドからインスタンス変数にアクセスできないたった一つの理由

なぜ、staticメソッドからインスタンス変数、インスタンスメソッドにアクセスできないのかと思う人が多いと思います。

例えば、以下のようなコードはコンパイルエラーになります。



class Student {

  //インスタンス変数
  String name;

  //コンストラクタ
  Student(String name) {
 
    this.name = name;
 
  }

  //クラスメソッド
  static void showName() {
 
    //インスタンス変数を表示???
    System.out.print(name);
  }

}

class StudentTester {
  public static void main(String[] args) {

    Student st1 = new Student("山田太郎");
 
    //クラスメソッドを呼ぶ
    Student.showName();
  }
}


これはStudentクラスのstaticメソッド「showName()」がインスタンス変数の「name」を表示しようとしているからです。

なぜこれがダメなのかは少し考えれば分かります。

StudentTesterのメインメソッドが以下のように記述されていたとします。



Student st1 = new Student("山田太郎");

//山田太郎と表示
System.out.print(st1.name);


Student st2 = new Student("田中花子");

//田中花子と表示
System.out.print(st2.name);



この後で、クラスメソッド「showName()」を呼ぼうとすると以下の処理を実行することになります。


//クラスメソッド
static void showName() {

  //nameを表示したいけど誰の名前??
  System.out.print(name);
}


インスタンス変数はnewでインスタンスが生成されてから、その中身を入れることができます。

仮にStudentクラスから1つのインスタンスしか生成できないならば、nameはそのインスタンス変数の中身で良いでしょう。

上の例で言えば、山田太郎しかインスタンスを生成できないならnameといえば「山田太郎」となります。

しかし、1つのクラスからはインスタンスはいくつでも生成することができます。

上の例でも、「山田太郎」「田中花子」と2つ生成しています。

その後でインスタンス変数のnameと言われても、「山田太郎」「田中花子」のどちらを指しているのか分かりませんよね?

なので、staticメソッドからインスタンス変数にアクセスできないようにしているのです。

staticメソッドからインスタンスメソッドを呼べないのも同様です。

山田太郎くんの持っているメソッドなのか、田中花子さんの持っているメソッドなのか誰にも分からないからです。

このように考えれば理解できますよね?

2014年12月2日火曜日

クラスとはなんぞやをRPGで例えてみた

クラスとは何なのか?
なぜ必要なのか?
そう思う人も多いでしょう。

そこで具体例として、RPGでモンスターとの戦闘を作る場合について考えてみましょう。

まず、モンスターにどのようなステータスが必要か決めなければならない。
例えば、「名前、HP、攻撃力、防御力、素早さ」が要るとする。

それをプログラムで書くとこんな感じ。

String  name = "スライム"; //名前
   int  hp = 5;            //HP
   int  attack = 12;       //攻撃
   int  defense = 8;       //防御
   int  agility = 10;      //素早さ

モンスターが複数現れた場合はこれをたくさん書かなければならない。

String  name2 = "ドラゴン"; //名前
   int  hp2 = 150;          //HP
   int  attack2 = 220;      //攻撃
   int  defense2 = 180;     //防御
   int  agility2 = 45;      //素早さ


はっきり言って超メンドクサイ!!

ならば、これらのステータスをモンスタークラスとしてまとめてしまおう!
各ステータスをインスタンス変数にして、そこに値を設定するコンストラクタを作成する。

class Monster {

  String  name;    //名前
     int  hp;      //HP
     int  attack;  //攻撃
     int  defense; //防御
     int  agility; //素早さ

  //コンストラクタ、引数は(名前,HP,攻撃力,防御力,素早さ)
  Monster(String name, int hp, attack, defense, agility) {
    this.name = name;       //名前を設定
    this.hp = hp;           //HPを設定
    this.attack = attack;   //攻撃を設定
    this.defense = defense; //防御を設定
    this.agility = agility; //素早さを設定
  }
}


このクラスを作って先ほどのモンスター2体を表現すると

Monster slime = new Monster("スライム", 5, 12, 8, 10);
Monster dragon = new Monster("ドラゴン", 150, 220, 180, 45);


モンスター2体を2つの変数で表現できてシンプルでわかり易い!
このようにクラスを使った方が便利ですねえ。

さらにMonsterクラスに攻撃された場合のメソッドをつくると…

int attacked(int hit) {

  //被弾値-防御=ダメージ
  int damage = hit - defense;

  //ダメージを受けた場合
  if (damege > 0) {
    //HPからダメージを引く
    hp -= damage - defense;
  } else {
    damege = 0;
  }
  return damege;
}


そうすると、モンスターを攻撃した場合の処理は…

//スライムを生成
Monster slime = new Monster("スライム", 5, 12, 8, 10);

//スライムに攻撃力40で攻撃
int damege = slime.attacked(40);

//32のダメージを与えた
System.out.printf("%dのダメージを与えた", damege);


と直感的にわかりやすくなる。



このようにクラスとはモンスターを作るのに決めなければならない項目の集まりである。

モンスターには攻撃力や防御力などのステータスが必要!
だから、フィールドにそれらを持たせる。

モンスターを攻撃したときにHPを減らしたい!
だから、メソッドとしてそういう機能を作る。

そうすることで、モンスターを生成し攻撃してダメージを与えるという処理が直感的で簡潔にコーディングすることができるわけです。
クラスって便利ですよね?

2014年11月30日日曜日

テスト対策、用語問題

javaはソースコードをコンパイルすると[バイトコード]が生成される




javaはコンパイルするのに[JDK]が必要である



javaを実行するには[JRE]がインストールされている必要がある



一行のみのコメントの場合は「//」から始める



複数行のコメントの場合は「/*」から「*/」の間に書く



文書化したいコメントは「/**」から「*/」の間に書く



文書化コメントを出力した文書を俗に「javadoc」という



変数ではなく「1」や「"abc"」などソースに直接記載した値を「リテラル」と呼ぶ



定数を宣言する場合は頭に「final」を付ける



キーボードから入力させる場合は「Scanner」クラスを使う



乱数を生成する場合は「Random」クラスを使う



キーボード入力や乱数生成をするクラスを使う場合はファイルの頭に「import」と書かなければならない



do-while文は最後に「;」を付ける必要がある



ループを途中で抜けたい場合は「break」と書く



ループの処理を途中でスキップしたい場合は「continue」と書く



ループに「ラベル」を付けることで多重ループを一度に抜けることができる



printfで整数値をフォーマットしたい場合は「%d」と書く



printfで小数値をフォーマットしたい場合は「%f」と書く



printfで文字列をフォーマットしたい場合は「%s」と書く



数値や変数などの型を違う型に変換することを「キャスト」という



変数には2種類あり、数値などの値を直接代入する「基本」型と、本体のアドレスが代入される「参照」型がある



配列やクラス型の変数に「null」を代入すると、どこのアドレスも指していない状態になる



配列やクラスで、実体のアドレスを持っている変数が一つも無くなった場合、「ガーベジコレクション」に回収され消滅する



メソッド内で宣言された変数などは他のメソッドからアクセスできない、これは「スコープ」が違うからである。



クラス内のメソッドの外で宣言する変数を「フィールド」という



同じ名前で、引数の型や個数が違うメソッドを定義できる、これを「オーバーロード」という



メソッド名、引数の型、個数を合わせたものを「シグネチャ」という



クラス型の実体で「new クラス名()」などで生成したものを「インスタンス」という



クラスや配列の実体を総称して「オブジェクト」という



クラスの実体を生成するときに呼ばれるメソッドを「コンストラクタ」という



クラスの実体の自分自身のことを「this」と表現する



クラスに属するメソッドやフィールドを定義する場合は頭に「static」と付ける



自分のメソッドやフィールドを他のクラスから隠したい場合は「private」、公開したい場合は「public」と書く、これらを「アクセス修飾子」という



他のクラスからアクセスできないフィールドから値を取得するメソッドを「ゲッタ」、設定するメソッドを「セッタ」、それらを合わせて「アクセサ」という。



フィールドを他のクラスからアクセスできない状態にして、その値の更新をメソッドで行いクラスの独立性を高めることを「カプセル化」と呼ぶ



配列をもっと便利にしたような使い方ができるクラスを「コレクション」と言い、代表格として「ArrayList」などがある



基本型が使えない場合は、それと同じ機能を持つクラスを使用するが、それらを「ラッパークラス」と言い、基本型とそれらを自動変換することを「オートボクシング」という




回答はこちら