コアJava 5日目

複数のプログラムをコンパイルする方法

ワイルドカード(*)を使用してJavaコンパイラを起動

javac Employee*.java

これで、ワイルドカードに一致するすべてのソースファイルがコンパイルされてクラスファイルが作成される。

javac Employee .java

この方法ではEmployee.javaを明示的にコンパイルしていないのに、このファイルをコンパイルされる!
Javaコンパイラにはmake機能がすでに組み込まれていると考えられる。

Employeeクラスを細かくみていきます
1つのコンストラクタと4つのメソッドを持つ

public Employee(String n, double s, int year, int month, int day)
public String getName()
public double getSalary()
public Date getHireDay()
public void raiseSalary(double byPercent)

「public」というキーワードは、任意のクラスのどのようなメソッドでもこのメソッドを呼び出せることを意味する。

クラスのインスタンスの中で操作するデータを保持するためのインスタンスフィールド

private String name;
private double salary;
private Date hireDay;

  • 「private」は、クラスそのもののメソッドだけがこれらのフィールドにアクセスできることを意味する。外部のクラスのメソッドはアクセスできない。
  • クラスにう、クラス型のインスタンスフィールドを持たせることは珍しくない
注意

インスタンスフィールドを「public」にするのは、他のプログラムのどの部分からも参照、変更が可能なので非常にまずい。
カプセル化が打ち砕かれますよってお話(´・_・`)
やけん、インスタンスフィールドは「private」にしましょう。

コンストラクタをみていくよ!
public Employee(String n, double s, int year, int month, int day)
{
 name = n;
 salary = s;
 GregorianCalendar calendar = new GregorianCaledar(year, month - 1, day);
 hireDay = calendar.getTime();
}

コンストラクタの名前は、クラスの名前と同じ。クラスのオブジェクトを生成するときに呼び出される。
コンストラクタには、必要に応じてオブジェクトの初期状態を表すインスタンスフィールドを渡す。

new Employee("James Bond", 10000, 1950, 1, 1);

この場合、次のようにインスタンスフィールドが設定される。

name = "James Bond";
salary = 10000;
hireDay = January 1, 1950;

コンストラクタと他のメソッドの違い

コンストラクタは必ずnew演算子に関連して呼び出される。
Javaではすべてのオブジェクトはヒープに構築されるため、コンストラクタはnewと共に使用せなあかん。

コンストラクタまとめ
  • クラスと同じ名前
  • クラスは1つ以上のコンストラクタを持つ
  • 0個以上の引数を受け取る
  • 戻り値を持たない
  • 常にnew演算子と共に呼び出される
Employeeクラスのメソッド

プライベートなインスタンスフィールドに名前でアクセスできる。インスタンスフィールドは常に同じクラスのメソッドからアクセス可能。

public void raiseSalary(double byPercent)
{
  double raise = saraly * byPercent / 100;
  salary = salary + raise; // 個人的に、インクリメントは敢えて使いません
}

raiseSalary()メソッドは2つの引数を持つ。最初の引数は暗黙的な引数と呼ばれ、メソッド名の前に志麻される型(ここではEmployee)のオブジェクトである。
2番目の引数は、メソッドの後ろのカッコ内で指定される数値であり、明示的な引数である。
raiseSalary()メソッドで言ったら、salary が暗黙的な引数で、byPersent が明示的な引数、という理解でええんかな(´・_・`)

this

すべてのメソッドにおいて、「this」は暗黙的な引数を参照する

public void raiseSalary(double byPercent)
{
  double raise = this.salary * byPercent /100;
  this.salary = this.salary + raise;
}

インスタンスフィールドとローカル変数を明確に区別できる。

(setter)、getterをみていくよ
// nameを返すメソッド
public String getName()
{
   return name;
}
 
// 給与の値を返すメソッド
public double getSalary()
{
   return salary;
}

// 

これらのメソッドは単にインスタンスフィールドの値を返すだけなので、フィールド照会型メソッドと呼ばれる。

疑問

nameフィールド、salaryフィールド、hireDayフィールドのそれぞれに対して照会型メソッドを作成するより、単にこれらをパブリックフィールドにする方が簡単なのでは?

回答

重要なのは、nameフィールドが「読み取り専用」である点。コンストラクタ以外、このフィールドを変更するメソッドはないので、決して辺区されないことが保証される。
salaryフィールドは、読み取り専用ではないが、raiseSalar()メソッドでのみ変更可能なので、salaryフィールドが間違っている場合、デバッグするのはraiseSalary()メソッドだけでよい。

パブリックデータフィールドを記述しない利点
  1. クラスのメソッド以外のコードにまったく影響せずに内部的な実装を変更できる。
  2. 単純にフィールドに値を設定するコードではできないことだが、更新型メソッドはエラーチェックを実行できる。

たとえば、setSalary()というメソッドで、給与が0身難にならないようにチェックしたりすることが可能。

プライベートデータへのメソッドのアクセス

メソッドは、そのクラスの持つすべてのオブジェクトのプライベートフィールドデータを参照できる。

class employee
{
   ,,,
   boolean equals(Employee other)
   {
     return name.equals(other.name);
   }
}

このメソッドは、通常次のように呼び出される。

if (harry.equals(boss))...

harryのプライベートフィールドを参照するし、また、bossのプライベートフィールドも参照する。EmployeeクラスのメソッドはEmployee型の任意のオブジェクトのプライベートフィールドを参照することを許されているから。

プライベートメソッド
  • クラスのユーザーにまったく関連性のないメソッド
  • クラスの実装が変更になったとき簡単に対応できないメソッド

このようなときに、プライベートメソッドにするとよい。

finalインスタンスフィールド

インスタンスフィールドをふfainalとして定義できる。このようなフィールドは、オブジェクトが生成されるときに初期化されなければならない。つまり、このフィールドの値は、すべてのコンストラクタが終了した時点で確実に設定されている必要がある。その後、このフィールドは決して変更されない。

class Employee
{
private final String name;
}

明日明後日は東京遊びに行くのでお休み。