はじめに
-
弊社の代表が javaプログラマー向け学習のための本(新人から5年めくらいまで)を考えてみた みたいな記事で600ストック超(2016/7/15現在)してるようですが、その中の以下の技術書を弊社新人向けに読書会形式で読み進めてます。
-
まずはJavaとオブジェクト指向の基礎です。新人向けには良く出来た技術書なので、全力でお勧めしてます。
-
自分はその取り組みの講師をしてる訳ですが、世に出した方が良さそうな質問をよく受けるのでそんな質問の回答を記事にしてます。
-
因みに読書会では、QiitaTeam、Slack、Githubを活用してやってたりします。ココらへんの活動は今後記事化するとして。
-
パブリックなQiitaには読書会の参加者が以下のような記事が投稿されています。
-
前置き長くなりましたが、今回は「JavaBeans」についてです。
-
さらに題名にあるPOJOについては、あまり言及してません。
JavaBeansに関する質問・疑問
- 読書会で「JavaBeans」というワードが出てきたのは スッキリわかる サーブレット&JSP入門 第7章 リクエストスコープ です。
- その章の読書会での質問と回答になります。
JavaBeansってSerializable インターフェースを実装する必要あるんですか?
- 答えは「あります」です。
- まず、java.io.Serializable インターフェースを実装することで、当該クラスは直列化可能となる訳ですが。
- JavaBeansは「直列化可能である」ということが仕様となりますので、直列化可能とするためにjava.io.Serializable インターフェースを実装する必要があります。
- Serializable インターフェースが実装されてないBeanっぽいクラスを見かけますが、JavaBeansの仕様から外れるので、それはPOJO(Plain Old Java Object)です。
- POJOは、特定のルールや制約、アーキテクチャに縛られていない単純なJavaオブジェクトと覚えれば良いでしょう。
ところでJavaBeansって何のために直列化するの?
- 直列化については、[Java]java.io.SerializableのSerializable(直列化可能)とは何なのか? を参照してもらうのが良いと思います。(以下で引用させてもらってます)
- まず、直列というのは、”「オブジェクトを1次元のデータ列に変換(シリアライズ)出来たり、そこからオブジェクトを復元(デシリアライズ)する」” こととなります。
- 例えば、お馴染みのStrutsのActionFormでは、Sessionに入れたオブジェクトをメモリからディスクに書き出すことがあるため、JavaBeansの仕様を満たす必要があります。クラス ActionForm
- というのもTomcatでは再起動やリロードの際に、セッションの直列化と復元を行っていて、それに乗っかるフレームワークはJavaBeansの仕様を必要とします。
- これによって、Tomcat の再起動後、再度アクセスされた場合でも、JavaBeansで実装されたセッションオブジェクトが再利用可能となるといった嬉しいことが起こっています。(混乱するのでプロパティエディタについては触れません)
JavaBeansのフィールドの定義とプロパティの定義が謎すぎます。
- 例えば、Humanクラスに
name
というフィールドがある場合、お馴染みのアクセッサメソッド(getter/setter) であるsetName
とgetName
がプロパティの定義となり、setとgetを除くNameの頭1文字を小文字にした 'name' がプロパティとなります。(一旦isXXX
については言及してません) - ここまではピンときますが、JavaBeansの仕様的に「フィールド=プロパティ」とはなりません。という一言で参加者は一気にJavaBeansの闇に陥り落ちいりました。
- 回答としては、JavaBeansの仕様的には 命名規則に従ったgetter/setterをもつ なので厳密には「フィールド=プロパティ」とはなりません。
- 要するに「JavaBeans でのフィールドとプロパティを混同しないでください」と解釈できます。
- 結局のところカプセル化されているJavaBeansをフレームワークが利用する場合、外部からフィールドに直接アクセスされることはなく、アクセッサメソッドであるプロパティが使われるので、フィールドが何であろうとJavaBeans的には問題ありません。
- 以下の実装の場合は、「nenrei」というint型のread-writeプロパティを持っているJavaBeansとなります。外部からフィールド(age)がどんな名前であろうと問題となりません。
Human.java
public class Human implements Serializable {
private int age; // フィールド
/**
* setNenreiとgetNenreiが「nenrei」プロパティ定義
*/
public void setNenrei(int nenrei) {
this.age = nenrei;
}
public int getNenrei() {
return this.age;
}
}
- 但し、一般的には原則として「フィールド=プロパティ」であり、「フィールド≠プロパティ」としても、利用者を混乱させたり、不快な思いにさせてしまうので、相当な理由がない限り「フィールド=プロパティ」としましょう。
結局のところJavaBeansとは
- 本に記載されている通り、Javaのクラスの独立性を高め、部品として再利用しやすくするために以下のルールを守っているクラスです。
- ルール①:直列化可能である(java.io.Serializable インターフェースを実装している)。
- ルール②:クラスはpublicパッケージに所属する。
- ルール③:publicで引数のないコンストラクタをもつ。
- ルール④:フィールドはカプセル化(隠蔽化)されている。
- ルール⑤:命名規則に従った setter/getter をもつ。
- 元々、クライアント(GUIを実装した)で実行することを意識したコンポーネント技術ですが、上記のルールを活用して、サーバーサイドを含む様々なフレームワークが利用しています。
- 前途の質問・回答を読んだ後なら理解が深まるのではないでしょうか。
- コードは載せた方が良いので適当なコードを貼っておきます。
SampleBean.java
package trial;
import java.io.Serializable;
public class SampleBean implements Serializable {
private static final long serialVersionUID = 1L;
private int id;
private String title;
private String author;
public SampleBean() {
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
}