Java bean 是個(gè)什么概念?
Java語言欠缺屬性、事件、多重繼承功能。所以,如果要在Java程序中實(shí)現(xiàn)一些面向?qū)ο缶幊痰某R娦枨螅荒苁謱懘罅磕z水代碼。Java Bean正是編寫這套膠水代碼的慣用模式或約定。這些約定包括getXxx、setXxx、isXxx、addXxxListener、XxxEvent等。遵守上述約定的類可以用于若干工具或庫。
舉個(gè)例子,假如有人要用Java實(shí)現(xiàn)一個(gè)單向鏈表類,可能會這樣寫:
// 編譯成 java-int-list_1.0.jarpublic final class JavaIntList {
?static class Node {
? ?public Node next;
? ?public int value;
?}
?public Node head;
?public int size;}
上述實(shí)現(xiàn)為了能夠快速獲取鏈表的大小,把鏈表大小緩存在size變量中。用法如下:
JavaIntList myList = new JavaIntList();System.out.println(myList.size);
JavaIntList的作者很滿意,于是開源了java-int-list庫的1.0版。文件名是java-int-list_1.0.jar。發(fā)布后,吸引了許多用戶來使用java-int-list_1.0.jar。
有一天,作者決定要節(jié)省內(nèi)存,不要緩存size變量了,把代碼改成這樣:
// 編譯成 java-int-list_2.0.jarpublic final class JavaIntList {
?static final class Node {
? ?public Node next;
? ?public int value;
?}
?public Node head;
?public int getSize() {
? ?Node n = head;
? ?int i = 0;
? ?while (n != null) {
? ? ?n = n.next;
? ? ?i++;
? ?}
? ?return i;
?}}
然后發(fā)布了2.0版:java-int-list_2.0.jar。發(fā)布后,原有java-int-list_1.0.jar的用戶紛紛升級版本到2.0。這些用戶一升級,就發(fā)現(xiàn)自己的程序全部壞掉了,說是找不到什么size變量。于是這些用戶就把作者暴打一頓,再也不敢用java-int-list庫了。
這個(gè)故事告訴我們,如果不想被暴打致死,你就必須保持向后兼容性。太陽公司在設(shè)計(jì)Java語言時(shí),也懂得這個(gè)道理。所以Java標(biāo)準(zhǔn)庫中,絕對不會出現(xiàn)public int size這樣的代碼,而一定會一開始就寫成:
private int size;public int getSize() { return size; }
讓用戶一開始就使用getSize,以便有朝一日修改getSize實(shí)現(xiàn)時(shí),不破壞向后兼容性。這種public int getSize() { return size; }的慣用手法,就是Java Bean。
現(xiàn)在是2014年,C#、Scala等比Java新的面向?qū)ο笳Z言自身就提供了語言特性來實(shí)現(xiàn)這些常用需求,所以根本不需要Java Bean這樣繁瑣的約定。
比如,假如有個(gè)Scala版的ScalaIntList:
// 編譯成 scala-int-list_1.0.jarobject ScalaIntList {
?final case class Node(next: Node, value: Int)}final class ScalaIntList {
?var head: ScalaIntList.Node = null
?var size: Int = 0}
用戶這樣用:
val myList = new ScalaIntListprintln(myList.size)
有一天你心血來潮改成這樣:
// 編譯成 scala-int-list_2.0.jarobject ScalaIntList {
?final case class Node(next: Node, value: Int)}final class ScalaIntList {
?var head: ScalaIntList.Node = null
?final def size: Int = {
? ?var n = head
? ?var i = 0
? ?while (n != null) {
? ? ?n = n.next
? ? ?i++
? ?}
? ?i
?}}
用戶還是照樣能用,根本不破壞向后兼容性。所以Scala程序只要不考慮和Java交互,一般就不需要類似Java Bean這樣的約定。
順便說一句,向后兼容性分為源代碼級和二進(jìn)制級,Scala的var或val改為final def的話,無論源代碼級的向后兼容性,還是二進(jìn)制級的向后兼容性,都不遭受破壞。但C#的字段改為屬性的話,雖然不破壞源代碼級的向后兼容性,但是會破壞二進(jìn)制級的向后兼容性。這是C#的設(shè)計(jì)缺陷,導(dǎo)致微軟的編碼規(guī)范不得不禁止使用公有字段。