しかし、メソッドを使うようにドキュメントへ書いておいても、それだけではAppを下記のようにコーディングしてしまう人は必ず出てきてしまいます。UserInfoManagerのuserInfoArrayフィールドは、特にアクセス制御されていないため、Appが直接アクセスして操作できてしまうからです。ドキュメントで説明をするだけでは、不十分なのです。
package sample14.app3a;
class App {
public static void main(String[] args) {
UserInfo u = new UserInfo();
u.name = "taro";
u.eMail = u.name + "@example.jp";
UserInfoManager manager = new UserInfoManager();
manager.userInfoArray[0] = u;
System.out.println(manager.userInfoArray[0].name);
System.out.println(manager.userInfoArray[0].eMail);
}
}
このように、ほかのクラスからアクセスできるようにコーディングされてしまうと、あるクラス内のデータ構造を変更することが必要になったときに、影響が出てしまいます。これを防ぐ仕組みとして、Javaでは「public」「protected」「private」といったキーワードが用意されています。
public、protected、privateは、クラス宣言、インターフェイス宣言、メンバ(フィールド、メソッド)宣言時に指定できます。これらを使うことにより、ほかのクラスやオブジェクトからフィールドにアクセスできるようにしたり、制限したり、といったことができます。
クラス自身にも、アクセス修飾子を付けられます。クラスの場合は、publicを付けるか、付けないか、といった選択が基本です。publicを付けたクラスは、ほかのクラスからアクセスできます。
また、このクラスから生成されたオブジェクトについても、同様にアクセスできます。付いていない場合は、同じパッケージにあるクラス以外のクラスからはアクセスができなくなります。
クラス自身に付けるアクセス修飾子について補足しておきます。まだ説明していませんが、「ネストされたクラス」というものがJavaにはあります。「ネストされたクラス」では、protected、privateを付けることもできます。ネストされたクラスについては、別途紹介する予定です。
アクセス修飾子がどういうものか知ったところで、「UserInfoManagerクラスの問題を解決するには、どうすればいいのか」を考えてみましょう。
このクラスは同一パッケージに含まれないクラスからも利用できるように、publicとします。userInfoArrayフィールドへほかのクラスが直接アクセスできないようにするためには、privateを使います。すべてのメソッドは、ほかのクラスから利用可能にするため、publicを付けることにします。
まとめたのが、次のコードです。
package sample14.app4;
public class UserInfoManager {
private java.util.List userInfoArray = new java.util.ArrayList();
public void add(UserInfo userInfo) {
userInfoArray.add(userInfo);
}
public UserInfo get(int id) {
return (UserInfo)userInfoArray.get(id);
}
public String getUserName(int id) {
return get(id).name;
}
public String getUserEmail(int id) {
return get(id).eMail;
}
}
次のようなクラスを作り、コメント部を有効にすると、エラーになりアクセス制御がきちんとできていることが分かります。privateなフィールドへは、ほかのクラスからはアクセスができません。
また、アクセス修飾子指定がないクラスは、ほかのパッケージのクラスからはアクセスできません。
package sample14.app4;
class App {
public static void main(String[] args) {
UserInfo u = new UserInfo();
u.name = "taro";
u.eMail = u.name + "@example.jp";
UserInfoManager manager = new UserInfoManager();
manager.add(u);
System.out.println(manager.getUserName(0));
System.out.println(manager.getUserEmail(0));
// privateなフィールドへはアクセスできない
//manager.userInfoArray.add(u);
//System.out.println(manager.userInfoArray.get(0).name);
//System.out.println(manager.userInfoArray.get(0).eMail);
// アクセス修飾子指定がないクラスへはアクセスできない
//sample14.app1.UserInfo u1 = new sample14.app1.UserInfo();
}
}
ここまでの話で、フィールドをprivateにしておけば、クラス内のデータ構造を変更するような大きな実装変更があっても、ほかのプログラムへの影響を限定的にできることが理解できたでしょうか。
今回までの連載では、publicはおまじないとして付けてもらうことがありましたが、今後は正しく意味を理解して使うようにしましょう。
フィールドは基本的にprivateとして非公開にするのが安全ですが、ほかのクラスがフィールド値を操作できた方が便利な場合もあります。その場合は、直接フィールドにアクセスさせるのではなく、専用メソッドを用意します。これは、「アクセサメソッド(accessor method)」と呼ばれます。
Eclipseでは、アクセサメソッドを簡単に用意できるようになっています。アクセサメソッドは、フィールドの値をgetしたりsetしたりするために使うものなので、「getter」「setter」と呼ばれることもあり、メソッド名は「get」「set」で始まります。
ただし、フィールドの型がbooleanの場合は、getに対応するメソッド名が「is」で始まります。
UserInfoについて、アクセサメソッドを作成してみましょう。まず、次のクラスを作成します。
package sample14.app5;
public class UserInfo {
private String name;
private String eMail;
private boolean member;
}
Eclipseでは、下記の手順でアクセサメソッドを簡単に作成できます。
次ページでは、生成されたアクセサメソッドがソースコードではどうなっているのかを確認し、最後にprotected宣言について、解説します。
Copyright © ITmedia, Inc. All Rights Reserved.