在主界面菜單中選擇Tools-->Resources-->DBMS.
再彈出的菜單中選擇需要擴展的數據庫類型。
點擊左上角Property圖標,彈出模板設置窗口。
在窗口中設置相應的Sql生成模板。
2006年8月24日 #
今天遇到了需要在 javascript 中繼承的問題:
查了一些帖子,自己又寫了幾個例子測試了一下,總結如下:
js 中實現繼承有三種方法:
假設父類為 Parent, 子類為 Child,
第一種,子類強制調用父類構造
function Child(){
?????? Parent.call(this);
}
第二種,子類間接調用父類構造
function Child(){
?????? this.base = Parent;
?????? this.base();
}
第三種:設置原型
function Child(){}
Child.prototype = new Parent();
這種方式雖然不夠直觀,卻應該是最有效率的方式。
其實 js 本身是沒有什么繼承之類的概念的,只是為了使用利用 js 的一些特性而加的。
js 的原型方式 prototype, 使得許多的工作變得容易。
一個 function 對象和根據 function 構造出來的對象是不同的。
一個 function 對象的原型其實就是一個根據 function 對象構建出來的對象。
記住:這個對象可與 new 出來的對象不一樣。在 function 內部的代碼并不會被執行,如:
this.funcName = function() 這樣的代碼。而 new 出來的對象則不然,他具有執行后的對象特性。
function 的局部變量相當于 class 里的私有變量,無法在子類中獲取和操作。但 this. 的部分是可以的。
(這是我推斷的,沒有任何的根據,當然也是可以測試的):
當一個 Child 被 new 時,第一二種方法中, js 執行器
1 、先分配一個空間,(相當于 this = new Object() ) (msdn 中有具體的描述 )
2 、拷貝原型:
3 、執行構造:也就是 Child.call(this) (相當于 child(), 此時 this 對象有值)( msdn 中有描述)
然后執行 Parent(); 這個時候 parent 的構造函數執行以下幾步:
1 、將 parent 的 prototype 拷貝到 object 區域,這時覆蓋了前面的區域 ( 好像測試證明 parent 的原型并不會被拷貝,此步不會被執行 )
2 、對這個區域執行初始化,也就是正常的 function 調用的過程。(相當于 Parent(),this 變量有值)
而普通的 function 調用應該是這個樣子:由于沒有 new 操作符,所以沒有為其分配當前的 this( 也沒有空間 ),
this 被放到了 window 對象上。但是 new 的時候顯然不是這樣。
obj.func() 的調用和 func() 調用是完全不一樣的, obj.func 中 this 對象是 obj 對象,而 func() 調用 this 對象是 window 對象,這個應該和 jvm 中靜態方法和類實例方法調用的區別的原理一樣。
在實現了對象繼承之后,我開始面臨到第二個問題,重載。
js 怎樣實現重載。
1 、簡單的重載:
在這種重載中,子類的方法無需調用父類的方法,直接在執行父類構造之后,再執行子類的重載方法,如 Parent 的 toString() 方法,這時只需執行 this.toString = function(){....} 就可以了。
2 、調用父類方法的重載:
由于 js 實際運行時并沒有父類、子類兩個實例空間,所以 super.toString() 肯定是不行的,而在子類的 toString 方法中進行 this.toString() 調用只能引起內存溢出,其實這種也可以想辦法做到。
this.super_toString = this.toString();
this.toString=function(){
?????? ..............
?????? this.super_toString();
?????? ..............
}
基本的方法,網上到處都是,在 java 中就是在 web.xml 注冊一個 Listener ,如下:
<listener>
??? <listener-class>xp.web.SessionCounter</listener-class>
</listener>
SessionCounter.java 實現 javax.servlet.http.HttpSessionListener 接口,分別在 sessionCreated 方法和 sessionDestroyed 方法中處理 session 數目。
這樣的方法有一定的問題:
1 、對于真正從網頁訪問的和搜索引擎的 spider 無法區分。
2 、當 Tomcat 重啟時,加載了上次持久化的 session 時,無法準確計算在線數。
第二個問題我們可以不予考慮,這是 tomcat 容器實現不標準的問題,我們要解決的是的第一個問題,如何知道你的訪問的是真實的。
用 js 繞過搜索引擎 :
做過 pv 統計的都知道,可以用 script 的方式得到你真實的 pageView 數目,我們現在要做的就是這樣的一件事情,我們在所有的頁面都加入一段話:
<script type="text/javascript">
document.write ("<iframe src='/sessionCountServlet' width=0 height=0 frameborder=no border=0 MARGINWIDTH=0 MARGINHEIGHT=0 SCROLLING=no></iframe>");
</script>
然后我們寫上一個 servlet 來記錄這些真正的訪問者。
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class SessionCounterServlet extends HttpServlet {
??? public SessionCounterServlet() {
??????? super();
??? }
??? public void doGet(HttpServletRequest request,
????????????????????? HttpServletResponse response) throws IOException,
??????????? ServletException {
??????? process(request, response);
??? }
??? public void doPost(HttpServletRequest request,
?????????????????????? HttpServletResponse response) throws IOException,
??????????? ServletException {
??????? process(request, response);
??? }
??? public void process(HttpServletRequest request,
??????????????????????? HttpServletResponse response) throws IOException,
??????????? ServletException {
??????? SessionCounter.put(request.getSession().getId());
}
}
我們可以看到這個 servlet 只是做了一件事情,在 process 里面做了 SessionCounter.put(request.getSession().getId()); 這個動作。
我們來看看我們的 SessionCounter 做了些什么:
import javax.servlet.http.*;
import java.util.Hashtable;
public class SessionCounter implements HttpSessionListener {
??? public SessionCounter() {
??? }
??? public static Hashtable m_real = new Hashtable();
??? private static long count = 0;
??? public void sessionCreated(HttpSessionEvent e) {
??????? count++;
??? }
??? public void sessionDestroyed(HttpSessionEvent e) {
??????? if (count > 0) {
??????????? count--;
??????? }
??????? m_real.remove(e.getSession().getId());
??? }
??? public static long getSessionCount() {
??????? return count;
??? }
??? public static void put(String sessionId){
??????? m_real.put(sessionId,"1");
??? }
??? public static int getRealCount(){
??????? return m_real.size();
??? }
}
我們記錄了一個靜態的 hash 表來記錄激活狀態的 sessionid ,并在 session 銷毀的時候將這個 sessionid 置為空。
怎么把 servlet 配置到 web 應用中我就不羅唆了。
???最近做網頁的時候無意中發現一個有意思的問題,只在Ie中測試過,不知道在firefox中有什么現象。
先定義樣式表:
<STYLE>
DIV .head1
{
?background-color: yellow;
}
DIV.head2
{
?background-color: red;
}
</STYLE>
展現樣式:
<div class="head1">div1</div>
<span class="head1">span1</span>
<div class="head2">div1</div>
<span class="head2">span1</span>
<div>
<div class="head1">div2</div>
<span class="head1">span2</span>
</div>
<p>
<div class="head1">div2</div>
<span class="head1">span2</span>
</p>
2004-12-03
第一部分:JSP和J2EE
1、1什么是javabean
javabean的屬性分為四類:
1、simple:簡單屬性
propName
getter:getpropName()
setter:setpropName()
2、Index:索引屬性
propName
getter:[] getpropName()
setter:setpropName()
getterI: obj getpropName(int i)
setterI: setpropName(int i,obj)
3、bound:觸發propertychange事件的屬性
接口和普通屬性沒有什么不同,只是在setter里支持觸發事件propertychange.
4、constrained:限制類屬性
接口和普通屬性一致,setter支持bound,另外:
在setter中支持觸發事件讓相關監聽組件來判斷是否可以設置,如果不行,其他組件會拋出propertyvetoException
事件模型:
基于源和listener的的事件模型。observer模式。
事件:java.util.EventObject及其子類。
監聽者:java.util.EventListener及其子類。
源對象:接口必須標準
public void add< ListenerType>(< ListenerType> listener)
public void remove< ListenerType>(< ListenerType> listener)
事件適配器:
可以用作確定會做出反映的事件響應者的用途。
2、在jsp中使用 3、jsp中javabean的scope 1、2 ejb 3、jsp中javabean的scope 1、2 ejb
application scope:應用程序級別的。
session scope:會話級別
request scope:請求級別
page scope:頁面級別
特殊的面向服務器端的javabeans.
包含sessionbean和entitybean兩種
home
Home 接口定義了創建查找刪除EJB 遠程接口對象或者EJB 服務的方法客戶端
應用程序通過使用JNDI 技術定位Home 接口的位置一旦獲得Home 接口的實例就可以
利用它的create()方法創建EJB 遠程接口的實例對象
remote接口
遠程調用接口 (或者簡稱為遠程接口Remote Interface)是對EJB 對象方法的總封裝
在遠程調用接口中聲明了EJB 對象的方法但是并沒有具體實現這些方法。
application scope:應用程序級別的。
session scope:會話級別
request scope:請求級別
page scope:頁面級別
特殊的面向服務器端的javabeans.
包含sessionbean和entitybean兩種
home
Home 接口定義了創建查找刪除EJB 遠程接口對象或者EJB 服務的方法客戶端
應用程序通過使用JNDI 技術定位Home 接口的位置一旦獲得Home 接口的實例就可以
利用它的create()方法創建EJB 遠程接口的實例對象
remote接口
遠程調用接口 (或者簡稱為遠程接口Remote Interface)是對EJB 對象方法的總封裝
在遠程調用接口中聲明了EJB 對象的方法但是并沒有具體實現這些方法。
2004-08-31
構建型模式和結構型模式強調的都是靜態的類實體之間的關系,行為型模式著力解決的是類實體之間的通訊關系。希望以面向對象的方式描述一個控制流程。
以往的經歷中大多是解決類實體的封裝問題,對于類之間的通訊方式上,并沒有刻意的去理解,所以有些行為型模式相對陌生。
還有一個原因就是行為型模式和面向過程的東西有很多近似之處,導致一定的理解的混淆。
從筆記就可以看出理解的不夠,可以再專門針對行為型模式做些細節的學習。
1 chain of responsibility(職責鏈)-行為型對象模式
這是個“請求”處理的模式。他提供一個思路,來解決“請求”在一組具有一定結構的類之間傳遞時的問題,所以,我認為這只是一種思路,一種將“請求”象鏈條一樣傳導出去的方式。他的具體傳遞方式,除了和鏈的設計有關之外,最重要的是和對象組的結構有關。
當然,如果沒有結構的對象組,我們也可以強行的動態構建一個鏈,這種方式雖然復雜和略土,但肯定更加的靈活,不僅能控制處理,還能控制鏈的走向。
一般來看,composite模式和這種模式經常在一起,Microsoft IE中的文檔事件模型應該采用的就是這樣的模式。
2 command(命令)-行為型對象模式
將請求封裝為一個對象,從而可以對請求做一些統一性處理,如:排隊、日志、撤銷等。
適用性:
1、是回調機制的一個面向對象的替代品
2、在不同時期指定、排列、和執行請求
3、支持取消操作,但是,此處對象的狀態存儲是個麻煩的東西。
4、支持原語操作上構建高層操作的系統。這種在支持“事務”的系統中很常見。
理解還是不很透徹
3、Iterator(迭代器)-行為型對象模式
將聚合類的遍歷算法封裝為Iterator,從而封裝對象的內部表示。
Iterator分為外部和內部,外部更加靈活,內部傳入參數簡單(只需要操作),內部Iterator自動遍歷所有元素。
Iterator可以封裝算法,也可以只記錄狀態,由聚合類封裝算法,封裝算法的iterator可能會破壞聚合類的封裝性。
4、mediator(中介者)
mediator希望通過一個中控對象來完成對多個對象的關系的管理。
將多數可以可以重用的組件無關聯的構建起來,而他們之間的關系由額外的對象來完成。
在圖形化編程里,可以用此模式和listener機制(observer模式)結合使用,更加方便,進一步解除了中控對象與其他對象的耦合。
5、memento(備忘錄)/token
原發器(originator)(需要保存狀態的)申請一個備忘錄(memento),并自己將狀態保存進去,然后,將備忘錄交給管理者(caretaker),當出現需要的時候,管理者將合適的備忘錄交給原發器,原發器自己恢復自己的
狀態。
memento模式,從originator中分離了保存客戶請求狀態的過程。并且memento的存儲和解釋都是由originator完成,保證了封裝的邊界。
如果備忘錄的創建及其返回(給原發器)的順序是可預測的,備忘錄可以存儲增量改變。
6、observer(觀察者)/依賴(dependents)/發布-訂閱(Publish-Subject)
suject(目標)和observer(觀察者)是關鍵對象,suject和不固定的observer發生關系,將這種關系解耦是這個模式的主要功能,listener機制可以看作這種模式的一個實現,當然mvc也是這種模式的一個好的應用場景。
與mediator的區別主要體現在,observer是一個對關聯關系的解耦過程,而mediator更加注重各個對象執行的功能。
7、state(狀態)/狀態對象(Objects for Status)
允許一個對象在改變其狀態的時候改變它的行為,使得對象似乎修改了自己的類。
1、將狀態相關的行為局部化。
2、狀態轉換顯式化
我們可以根據當前窗口的狀態來轉變窗口的菜單和操作,這種方式可以用state模式來實現。
8、strategy(策略)
將算法單獨的封裝起來,使得它獨立于其他對象的變化。
其實這種方式和面向過程里的一個算法函數封裝基本是一樣的,只是由于封裝成為了類,會有一些接口統一的便于替換的特性。
9、visitor(訪問者)
這種模式的主要目的是分離操作和對象,追求的是對象的重用和簡單,以及操作的可替代性。
相對來說,strategy模式更加追求的是封裝操作,追求操作的重用性。
observer、mediator追求分離對象之間的關系與對象本身。
以上都是對象級別的行為模式,以下是類級別的行為模式
1、template(模板)
定義一個算法的骨架,并將其中一些步驟延遲到子類中。
這種使用較多,不多說了。
2、interpreter(解釋器)
本模式描述了如何為簡單的語言定義一個文法,如何在該語言中表示一個句子,以及如何解釋這些句子。
這種方式在正則表達式中比較明顯,在以往的程序應用中,特別是上層應用中很少用到。
expression::= literal | alternation | sequence | repetition | '(' expression ')'
alternation ::= expression '|' expression
sequence ::= expression '&' expression
repetition ::= expression '*'
literal ::= 'a'|'b'|...{'a'|'b'|...}*
相關的關鍵參與者為:
1、abstractExpression(抽象表達式,統一的接口)
2、terminalExpression(終結符表達式)
3、nonterminalExpression(非終結符表達式)
2004-08-30
結構型模式:描述的是一系列將類和對象進行組合,以構建更大的類和對象。其強調的是結構化的方式,而不是怎樣去構造這些類。
結構型模式分為兩種:
a、結構型類模式:通過接口或類的繼承來實現。
b、結構型對象模式:不是對類或接口,而是對對象進行組合。
/*****************************************************************************************/
1、Adapter(適配器)/wrapper(包裝器)
適配模式最重要的作用是去將已有的、但是接口不兼容的東西接入到系統中來。進行復雜邏輯程序的有效重用。
這個模式中adaptor,adaptee的基類是具有惟一性的。
a、類適配
類適配就是通過繼承這種靜態的方式來進行適配,也就是適配器會繼承需要被適配的東西,
缺點是適配的范圍比較小,不能滿足同時適配一組對象(類及其子類)的要求。
b、對象適配
對象適配:適配器并不會靜態的繼承,而會是采用引用需要被適配類的方式,這樣,被適配類及其子類都可以被適配了,
缺點:需要動態的指定被適配對象,而且容易引起運行期錯誤
注:可能是對于其他面向對象語言的不了解,我覺得用對象適配就可以了,沒有必要使用類適配的模式,對于只有一個需要適配的類的情況,我們只需要將動態構造引用對象的過程加在適配器的構造函數中就可以了,在今后對其他類型的OO語言有了了解之后,可以再回顧一下此處。
/*****************************************************************************************/
2、bridge(橋接)/(Handle/boby)---結構型對象模式
橋接的模式最重要的作用是將抽象/表現與實現相分離,保持程序良好的可擴展性。
這個模式中window和windowimpl這兩個接口是具有惟一性的。
一個一般的繼承模式的設計
window--xwindow
?pmwindow
?iconwindow--pmiconwindow
????? xiconwindow
這種樹狀的繼承方式將抽象的表現部分iconwindow和抽象的實現部分(xwindow,pmwindow)集成到了一起。
而這兩者其實負責不同的東西,一是表現(外部特征,如icon是可以拖拽的,是由矩形組成的等等),二是具體實現平臺,負責在xwindow風格下的線如何畫,線有多粗,從什么位置開始畫等等。
于是應該有著兩條線的結構:
window--iconwindow
?applicationwindow
windowimpl--xwindow
???? pmwindow
中間通過window對windowimpl的引用來達到橋接的作用,也就是說,橋接的奧秘就在于此,合理的將這兩者的接口進行分離,是橋接模式設計的關鍵。
橋接方式的退化形式就是我們只是需要實現xwindow或者pmwindow中的一種,這樣windowimpl就失去意義了。(對于有些語言,windowimpl的存在可能有利于實現的改變不需要重新編譯客戶應用程序)??
/*****************************************************************************************/
3、composite(組合)---結構型對象模式
組合模式使得單個對象和組合對象的使用具有一致性。使得對外提供的接口變得單一,用戶忽略單個對象與組合對象的差異。
組合模式著力于解決這樣一個矛盾:
在一個程序組中有著層次的關系,需要表現(這是一個內部重用性和易讀性的問題)
但是這個程序組中的對象有著共性,并且希望外部調用程序忽視其各異性而只是關注其共性的部分(這是一個外部接口簡單化的問題)。
所以其主要元素的關系就是這樣了:
composite(復合對象)-leaf(簡單對象)
????? composite(復合對象)-leaf(簡單對象)
?????leaf(簡單對象)
而這些對象實現統一的接口或者抽象類:compositeInterface;任何client對任何對象實例的操作都是通過接口進行。
模式的實現:
在實現中會有一系列的問題,這只是實現的問題,和模式本身無關。
1、顯示父對象引用:解決方法:建立一個穩定,模式化的父子引用關系和操作方法。
2、共享組件:這將父子之間的1:N的關系變成了N:N的模式,參考flyweight模式。
3、最大化component接口:這是保證操作透明化的必須,我們應該盡力達到這個目的。
4、聲明管理子部件的操作:這個問題最大的麻煩來源于子部件和父部件最大的差異--有沒有子節點,可以通過統一的,技巧性的add,remove方法來完成。
5、compositeInterface是否應該實現一個compositeInterface列表:這是一個關于存儲的問題,就是對于子節點的引用對于葉子節點是無意義的內存消耗。
6、子部件排序:Iterator模式應該有一定的作用。
7、高速緩存改善性能。
/*****************************************************************************************/
4、decorator(裝飾)/包裝器(wrapper)---結構型對象模式
從名字我們就可以看出這個模式的基本立意:一位畫家畫完一幅畫(實現一個組件)之后,并不需要自己去做畫框(decorator),做這個畫框就是這個模式需要解決的問題。
可以看到畫框能為畫家所用是基于一種前提的,就是畫家的用紙和畫框的大小是符合的,也是基于一種結果,就是畫還是畫,不會因為畫框而改變其畫的本質和內容,只是現在是一幅有框的畫了。
回到模式中,我們可以看到這個模式的大概了:
component(組件接口)-concreteComponent(組件實現)
???? -decorator(裝飾器)-->m_cmp(對組件實現的引用)
這里我們可以看到decorator模式和adaptor模式的區別,decorator著力于裝飾器部分的重用,而adaptor只是著力于組件的重用。decorator著力于封裝組件的可以插件化的共性特征,其著眼點是組件級別以下的功能重用。adaptor著眼的還是組件一級的功能重用。
/*****************************************************************************************/
在前面的composite和decorator模式中,我們不停的追求將組件實現得更加的細粒度化,以便增加組件的可重用性,這基本是各種良好設計的共同特征。
但是這種設計方式也會導致各種問題,其中就包括零散、以及大量對象實例導致的資源消耗問題。
/*****************************************************************************************/
5、facade(外觀)--結構型對象模式
facade模式最大的特點就是將復雜、零散的子系統進行唯一入口的封裝。
這種模式在我經歷的系統印象最深的就是多層分層的層層之間的接口上,一個唯一的入口,讓層次非常的清晰。
其實這種模式與adaptor有一定的相似之處,都是屏蔽兩個不同的子系統,但是不同的是,facade是主動的構建,而adaptor是為了接入其他的系統而被動的構建的,可以看出,要對一個已經實現了facade模式的子系統構建adaptor遠比沒有沒有實現facade模式的要簡單的多,代價要小得多。
/*****************************************************************************************/
6、flyweight(享元)--結構型對象模式
享元設計模式著力解決的就是當內存中存在大量同樣的對象實例導致的資源消耗問題。
可以幾個方面來理解,
享元模式追求的是實例級別的重用。
將外部狀態(上下文)和對象實例本身分離,不是在構建時傳入外部狀態,而是在運行期,甚至這種狀態完全是過程性的,和對象實例沒有關系。而內部狀態只在創建時指定,而在運行期是絕對不可以碰的。
這種模式與原型模式的最大區別在于,一個共享實例級別的,一個是共享類的級別。
/*****************************************************************************************/
6、proxy(代理)/surrogate--結構型對象模式
常見使用情況
1、遠程代理(remote proxy)
2、虛代理(virtual proxy):根據需要創建開銷很大的對象。
3、保護代理(protection proxy):控制對原始對象的訪問。
4、智能指引(smart refrence):取代簡單指針,便于在訪問對象前做些附加操作。
這種代理使用廣泛,什么copy_on_write,lazy_loading等技術都可以考慮這種方式的實現。
proxy模式代理和被代理對象接口是一致的或者是子集,但adaptor模式則不同。
decorator模式為對象增加接口,而proxy是轉發或者限制接口。
2004-05-25
每次看設計模式這本書的時候都有著相同的感覺,上次沒有真的理解,這次才是理解了,但是還差那么一點點。
人其實挺奇怪的,這些模式在編程的幾年之內,無論是具體的項目中還是自己的練習中,都使用了很多,只是沒有作為一種模式總結出來而已,而是以經驗的形式存在于腦海之中,隨意的使用,隨意的忘卻。
可能就是必然的學習過程吧,隨意使用--形成模式--突破模式靈活應用。而模式在這里起著把經驗持久化的作用吧,減少忘卻的可能。
所以,真正的掌握模式,除了需要理解模式的表現之外,需要理解模式著力解決的問題,理解模式的缺陷和優勢,才能做到最終靈活抽取各個模式之長而靈活組合之,這可能就是我在模式領域追求的無招勝有招的境界吧。
模式的核心目的大多是兩種之一:重用和解耦
言歸正傳,還是來說說具體的模式吧:Design patterns
模式分類:構建型模式
模式一:抽象工廠(Abstract Factory)
Factory理解為對象工廠的概念,用以生成一個系列的對象組。
而Abstract Factory就是基于Factory之上的概念,目的是把多個系列的對象組抽取共性,屏蔽不同系列之間的對象的差異。
?系列???? motif?????? windows?
對象組
Button??? motifBtn??? wBtn
Bar?????? motifBar????wBar
Textbox?? motifTB???? wTB
class abstractFactory{
?Button getButton();
?Bar getBar();
?Textbox getTextbox();
}
button,bar,textbox是一組對象,而我們需要實現motif,windows等不同系列風格的對象組,Abstract Factory提供的方式下,我們對于大多應用程序而言,操作的口是abstractFactory,以及Button,Bar,Textbox這些對象組,而無需具體關心是motif風格還是windows風格的,風格系列的指定只決定于實現abstractFactory的具體工廠類。
這種方法便于這種系列的增加,但是并不有利于對象組成員的增加,比如要增加一個label對象,我們就需要增加一個抽象對象Lable,還需要修改abstractFactory以及他所有的子類。
所以使用這種方法的時候,最重要的是對象組的規劃設計。
模式二:生成器(builder)
生成器的概念是提供一系列的方法生成對象的不同部分,最終返回一個完整的對象,著力于解決將構造方法和構造步驟分離的問題,builder內部封裝的是構建方法而不是過程。
做了這樣的分離之后,再將builder做一個抽象,從而使得不同的構建方法和構建過程做到分離。
假設一個串的存儲管理:
class builder(){
?add(key,value);
?addStr(str);
}
同樣的操作集合,
add(key,value),addStr(str)
對于不同的builder,可能輸出的結果就會有多種:
key=value;str
另一種可能:
?
?str
模式三:工廠方法(Factory)
其實他的另一個名字更加能夠說明問題(虛構造)
也就是說通過抽象類的共同方法來避免構造時的硬編碼,
如:button對象有個getBtn的方法,
就可以避免寫出button btn = new motifButton();這樣的代碼,而將這樣的代碼封裝到了子類自身。
模式四:原型法(prototype)
就是在應用時并不是創建一個新的對象,而是從已有的對象中拷貝一個。
這種方式我在做配置池的時候用到過,每個業務程序從我的池中去拷貝一個對象,然后才進行相關的修改和應
用。
這種方式同樣是動態創建類的方法,著重于解決當對象組的成員不穩定的情況,而不是多個系列的問題。
與Factory相比,他并不是每一個原型都需要一個構建子類。
缺點:clone本身實現的難度。
模式五:單件(singleton)
這種模式使用無數,就不再多說了。用于保證實例的唯一性。
2004-10-25
第八章線程和鎖
這章描述的是非常底層的jvm運作的時候的概念上的部分模型,與前部分的編譯不屬于一個層次。
本章提到的變量概念是指類實例,類變量,和類數組。而參數和局部變量并不強行要求到這個變量概念之中。
8。1術語和框架
jvm中有主寄存器,當一個線程被啟動時,會創建自己的工作寄存器,當線程運行,會對主寄存器中的數據進行拷貝,存入自己的工作寄存器中。
主寄存器包含每個變量的主拷貝。
主寄存器也包含鎖,每個對象有個與其相關的鎖。線程可以競爭獲得一個鎖。
相關術語:
use,assign,load,store,lock,unlock為線程可以執行的動作。
read,write,lock,unlock為主存儲器子系統可以執行的動作。
use,assign是線程執行引擎與工作存儲之間的緊密耦合交互作用。
lock,unlock是線程執行引擎與主存儲之間的緊密耦合交互作用。
主存儲與工作存儲之間卻是松散耦合的。
分別對應的動作就是:load,store和lock,unlock
注意有三個實體在協同工作:主存儲器,工作存儲器,線程運行引擎
8。2執行順序和一致性。
1。同線程執行動作排序
2、主存儲執行的、對同一變量的動作排序
3、主存儲執行的、對同一鎖的動作排序
4、不允許一個動作跟在其自身后面。
第4點特殊說明:雖然看起來無關緊要,但必須顯式說明,以保證完整性。因為這種危險確實存在。
線程的動作和主存儲的動作間的約束:
1、每個lock和unlock動作必須由一些線程和主存儲共同執行。
2、每個load動作,唯一的與一個write動作配對,這樣write動作跟在store動作后。
8。3有關變量的規則
線程T對變量V的操作約束:
1、T執行過程中只有需要相應使用V時才調用use,或者assign動作。
2、T執行的assign動作必須插入到T對V的load或者store和后繼的由T執行的對V的store之間。(保證主存儲內值的正確,同時保證assign動作之前工作存儲內存在V)
3、在T對V執行use和store之前,必須執行assign或load操作(保證工作存儲器中有V,并且已經初始化)
4、在V創建后,每個T在use或store之前,必須執行assign或load操作。
對于第4點:volatile(易變)變量有更嚴格的約束
由主存儲器執行的read和right操作的約束:
1、T對V的load,必須先有對應的read
2、T對V的store,必須后繼對應的write
3、動作A,B是T對V的load或store動作,P,Q為對應的read或write,如果A優先于B,則P必須有些于Q
?
8.4Double和long變量的非原子處理
由于32位機器的效率問題,有些jvm實現對double和long這種64位值操作是非原子的,導致一些同步問題(如程序員總是需要顯式指定同步于對double和long上的操作),其實這只是一種軟件設計對硬件的妥協而已。
8。5有關鎖的規則
線程為T,鎖為L,T執行的關于L的操作約束如下:
1、T對L的lock操作,必須對于每個不是T的線程S,S對L的unlock操作數等于之前的S對L的lock操作數
2、T對L的unlock操作,必須要求先前T對L的unlock操作數,小于先前T對L的lock操作數(不解不擁有的鎖)
8。6有關鎖和變量交互作用的規則
線程T,鎖L,變量V,T執行的關于L和V的操作約束如下:
1、在t對V的assign和隨后的unlock之間,必須插入store操作。對應于該store的write操作必須先于unlock操作(保證L對于V的有效性)。
2、在lock和隨后執行的use或store之間,必須插入assign或load操作。
8。7有關volatile(易變)變量的規則
線程T,易變變量V和W
1、load和use操作必須成對出現,緊挨在一起,并且load操作在前
2、assign和store操作必須成對出現,緊挨在一起,并且assign操作在前
3、A、B為T對V的use或assign,F、G為對應的load或store,P、Q為對應的read或write,如果A先于B,則P必須優先于Q。
8。8先見存儲操作
如果變量沒有聲明為violate,則store操作可以提前于assign,store操作將將要賦給V的值替代V實際的值進行store操作,只要滿足:
1、如果發生store,必然發生assign。
2、重定位的store和assign間未插入鎖定操作。
3、重定位的store和assign間未插入對V的load
4、重定位的store和assign間未插入其他對V的store
5、store操作將assign操作要放到線程T的Z作為存儲器中的值傳到主存儲器。
8。9討論
8。10可能的交換
一個關于同步和鎖的小例子。
8。11范例:無序寫
另一個例子
8。12線程
線程由Thread和ThreadGroup類創建并管理。創建Thread對象就創建一個線程,而且是創建線程的唯一方式。當線程被創建時,它還不是活躍的,當其start方法被調用時,開始運行。
8。13鎖和同步
每個對象都有與其關聯的鎖。
當synchronized方法被調用時,它自動執行鎖定操作;如果該方法是實例方法,它鎖定同實例相關聯的鎖,如果方法是static的,它鎖定同Class對象相關聯的鎖
8。13等待集和通知
每個對象除了相關的鎖外,還有相關的等待集,即一組線程,首次創建的對象,等待集為空。
講述了wait,notify,notifyall幾個方法,wait方法往等待集中增加內容,而notify或notifyall方法從等待集中刪除內容。
但不能完全讀懂內容,可細研究。
第九章優化
本章描述jvm中Sun版本中實現的優化。
在此優化中,編譯的jvm代碼在運行期修改,利用運行期獲得的信息,做比源指令更少的工作,以獲得更好的性能。
9。1通過重寫動態鏈接
對重寫的指令,指令的每個實例在其第一次執行時被替換為_quick偽指令,該指令實例隨后執行的總是_quick變體。
其余是對_quick偽指令的描述,可用于查閱,因為這是Sun的jdk在運行的時候的真正指令狀態。
第十章 操作碼的操作碼助記符
這章主要是個附錄的功能,可供查閱。
×××××××××××××××××××××××××××××××××××
在延期了將近一個月了之后,終于算是看過了一遍這本書,雖然有很多沒有看的非常明白的地方,但是比我預期的效果要好了許多了,進一步的細致研究可以安排在后面。
2004-10-24
i=0;i=i++為什么等于0這個問題困擾了我好長的一段時間,結果前段時間還試圖從虛擬機那個層面進行解釋,但無論是線程還是方法調用都不能解釋其現象,發現方向性錯誤,這只是一個語言的特性而已。在java lang spec中提到:
1、java運算符的優先級++符是大于=的。
2、The result of the postfix increment expression is not a variable, but a value.后++符表達式的結果是個值而不是一個變量。
也就是說后++符先將自己的值存儲起來,然后對變量進行++;
再進行賦值操作,也就是將先存儲起來的值賦給變量i,這樣的操作就導致了i值被置為0了
對于C和C++來說不一樣,在講到m=i++操作時,C語言是先將i的值賦給了m,然后將i值++,這樣i=i++的結果自然就是1了,c的實現中是不存在那個中間的值的存儲的。
由于java和c不同的語言特性,導致了i=i++的不同之處,前面的筆記中已經提到,由于java lang spec中的一些細微規定,導致其運行結果的不同,我們可以用個例子來看i=i++在jvm中實際的運行過程。
源程序test.java:
public class test {
? public test() {
? }
? public static void main(String[] args) {
??? int i=0;
??? i=i++;
? }
}
我們用javap來看其實際的虛擬機指令集:
C:\JBuilderX\jdk1.4\bin>javap -c? -classpath "d:/" test
Compiled from "test.java"
public class test extends java.lang.Object{
public test();
? Code:
?? 0:?? aload_0
?? 1:?? invokespecial?? #1; //Method java/lang/Object."
?? 4:?? nop
?? 5:?? return
public static void main(java.lang.String[]);
? Code:
?? 0:?? iconst_0?//常數0入棧
?? 1:?? istore_1?//i賦值,常數值出棧
?//至此完成i=0;
?? 2:?? iload_1??//裝載變量i,0入棧
?//第2步是特殊的一步,這步將i值先行保存,以備賦值使用
?? 3:?? iinc??? 1, 1?//變量值增加,棧內值不變
?//至此完成i++
?? 6:?? istore_1?//i賦值,0出棧。
?//至此完成i=i++
?? 7:?? nop??//donothing
?? 8:?? return
}
對比而言,對于i++而言,i=i++指令多了兩步,2和6
其實這兩步是賦值符號引起的,有意思的是第二步出現的時機,是在iinc之前,這就是因為java lang spec中規定的。
2004-10-22
第四章:class文件格式
java.io.DataInput和java.io.Output輸入輸出的都是以高端字節序輸出字節。
與C結構的域不同,class文件中連續的項順序存儲,不進行填充或者對齊。
4.1classFile
一個class文件包含一個單獨的classFile結構,包含:
一個四字節的幻數表明class類型。具有值0XCAFEBABE;
access_flag用于表明是類還是接口,是abstract,final還是其他
另外分別有表存儲:常量、屬性、方法、域。
目前屬性只有sourceFile屬性。
4。2完全限定類名稱的內部形式
出現在classFile文件結構中的類都以完全限定類名稱的方式出現,并且不是類似于java.lang.xxx,而是變為java/lang/xxx
4.3描述符
域類型有:根類型,對象類型,數組類型
根類型有:B,C,D,F,I,J,S,Z
對象類型:L
數組類型:[
多維數組double[][][] d的表示方式:[[[D
方法返回描述符
V表示void
object mymethod(int i,double j,Thread t)的方法描述符為:
(IDLjava/lang/Thread;)Ljava/lang/Object;
java的方法不管是static還是實例方法描述符都是如此,區別在于jvm運行時給實例方法隱式的傳遞當前對象的指針this
4.4常數池
常數池由一組類似于cp_info的結構構成
cp_info{
?u1 tag;
?u1 info[];
}
4.5域
每個域由一個變長的field_info構成
field_info{
?u2 access_flags;
?u2 name_index;
?u2 descriptor_index;
?u2 attribute_count;
?attribute_info attributes[attributes_count];
}
4.6方法
每個方法由變長結構method_info構成
method_info{
?u2 access_flags;
?u2 name_index;
?u2 descriptor_index;
?u2 attribute_count;
?attribute_info attributes[attributes_count];
}
4.7屬性
屬性用于field_info,method_info,class_file結構之中,結構一般如下:
attribute_info{
?u2 attribute_name_index;
?u4 attribute_length;
?u1 info[attribute_length];
}
某些屬性被預定義作為class文件規范的一部分,這些屬性是:sourceFile,ConstantValue,code,exception,lineNumberTable和localVariableTable屬性。
4。8對java虛擬機代碼的約束
4。9class文件的檢驗
4。10java虛擬機和class文件格式的限制
2004-09-30
第六章:jvm虛擬指令集
6.1假定:“必須”的含義
對于jvm指令的一些“必須”的要求,在運行期要求javaclass的結構是滿足約束的,對于不滿足約束的情況,jvm的行為是未定義的。
6.2保留操作碼
在java class文件中使用的指令操作碼,有三個操作碼是保留的,供java虛擬機內部使用。
254(0xfe)和255(0xff),分別有助記符impdep1和impdep2,目的是在軟件或者硬件實現的特定功能提供“后門”或陷阱。
202(0xca),有助記符breakpoint,目的是由調試程序使用來實現斷點。
6.3虛擬機錯誤
當內部錯誤或者資源限制導致java語言語義不能實現時,jvm拋出一個VirtualMachineError類的子類的實例。jvm規范不規定和語言拋出的時間和地點。
6.4jvm指令集
我不一一例舉各種指令的操作碼和用法,需要時去查就行了。
第七章 為jvm編譯
7.1范例格式
java編譯成為class文件之后,以類匯編的jvm操作指令方式存在,jdk自帶的javap程序具有這樣的功能,將class文件翻譯為這樣的指令集。
下面是我測試的一個實例:
源文件為test.java
public class test {
??? public static String a = "";
??? public int i =0;
??? public test() {
??????? int i=0;
??????? String a = "xyz";
??? }
}
編譯完成為test.class,用javap生成之后輸出結果為:
C:\JBuilderX\jdk1.4\bin>javap -c? -classpath "c:/" test
Compiled from "test.java"
public class test extends java.lang.Object{
public static java.lang.String a;
public int i;
static {};
? Code:
?? 0:?? ldc???? #4; //String
?? 2:?? putstatic?????? #5; //Field a:Ljava/lang/String;
?? 5:?? nop
?? 6:?? return
public test();
? Code:
?? 0:?? aload_0
?? 1:?? invokespecial?? #1; //Method java/lang/Object."
?? 4:?? aload_0
?? 5:?? iconst_0
?? 6:?? putfield??????? #2; //Field i:I
?? 9:?? iconst_0
?? 10:? istore_1
?? 11:? ldc???? #3; //String xyz
?? 13:? astore_2
?? 14:? nop
?? 15:? return
}
7.2常數、局部變量和控制結構的使用
jvm是面向棧的,大多數操作都是從當前框架的操作數棧中取得操作數。
7。3運算
jvm一般在操作數棧上進行運算,即從棧中取操作數,并將結果存入操作數棧中。
7。4訪問常數池
byte,char,short,以及小int值都可以通過立即數的方式編譯在method的code中,但是int,long,float,double,以及string實例的引用,就需要對常數池進行訪問了。使用ldc,ldc_w,ldc2_w指令管理。
7.5更多控制范例
可供查閱
7。6接收參數
如果向java實例方法傳遞了n個參數,它們被接收,按約定,框架的編號1到n的局部變量為新的方法調用創建,順序為接收的順序。
7。7調用方法
對java實例方法的調用,是在對象的運行期類型上調度的。用invokevirtual實現,將其參數取做對常數池表項的索引,給出對象的類類型的完整限定符名稱,再調用方法的名稱和方法的描述符。
對java靜態(類)方法的調用,無需傳遞類實例,其余和實例方法相似,用invokespecial方法實現。
invokespecail指令用于調用實例初始化方法。超類方法和調用private方法。
7。8處理類實例
構建一個類實例的過程,在建立對象及其實例域之后,用invokespecial調用相應構造函數對應的
對對象域的訪問用getfield和putfield指令完成。
7。9數組
主要講的是數組操作的相關jvm指令,如:newarray,過一遍,可以查閱。
7。10編譯開關
對于java的switch指令,jvm有對應的兩種指令:tableswitch,lookupswitch.
tableswitch指定取值范圍,而lookupswitch并不指定取值范圍,兩者如何選擇完全由效率選擇決定。
7。11對操作數棧的操作
jvm有大量的指令補充,將操作數棧的內容作為無類型字或成對的無類型字操縱。便于jvm虛擬機指令的靈活組成。
如dup,dup_x2等,都是對字或者雙字進行操作。
7。12拋出或者處理異常
jvm中try...catch塊的處理對于jvm指令處理是透明的,輔助控制是由異常表來完成的,由異常表來決定到哪里去調用處理,哪些部分的異常是受控的。
7。13編譯finally
try.....finally語句與try-catch相似,只是其輔助控制是由指令jsr(子例程調用)顯式的表示,在jsr調用之前,將下一指令的地址壓入棧中。而異常表只控制try塊的范圍。
7。14同步
jvm用monitorenter和monitorexit指令對同步提供顯式支持。而java常用sychronized方法。
sychronized“方法”通常不是用monitorenter和monitorexit指令實現的。往往是由“方法調用指令”檢查常數池里的ACC_SYCHRONIZED標志
但monitorenter和monitorexit指令是為了支持sychronized“語句”而存在的。
注意這里的方法和語句的區別。
語句實例如下:test.java
public class test {
? public test() {
? }
? public static void main(String[] args) {
??? synchronized(new Object()){
??????? int i = 0;
??? }
? }
}
編譯完的結果:
C:\JBuilderX\bin>javap -c? -classpath "d:/epm40/classes" test
Compiled from "test.java"
public class test extends java.lang.Object{
public test();
? Code:
?? 0:?? aload_0
?? 1:?? invokespecial?? #1; //Method java/lang/Object."
?? 4:?? nop
?? 5:?? return
public static void main(java.lang.String[]);
? Code:
?? 0:?? new???? #2; //class Object
?? 3:?? dup
?? 4:?? invokespecial?? #1; //Method java/lang/Object."
?? 7:?? dup
?? 8:?? astore_1
?? 9:?? monitorenter
?? 10:? iconst_0
?? 11:? istore_2
?? 12:? nop
?? 13:? aload_1
?? 14:? monitorexit
?? 15:? goto??? 23
?? 18:? astore_3
?? 19:? aload_1
?? 20:? monitorexit
?? 21:? aload_3
?? 22:? athrow
?? 23:? nop
?? 24:? return
? Exception table:
?? from?? to? target type
??? 10??? 15??? 18?? any
??? 18??? 21??? 18?? any
}
而synchronized方法編譯沒有特殊之處,只是在方法名上加了synchronzied字樣。
2004-09-27
第三章:jvm結構
3.1數據類型
基本類型和引用類型
基本值和引用值
數據不需要做標記或者可被檢查以確定類型。也就導致jvm的指令集是針對特定類型的值的。
jvm包含對對象的顯式支持(引用類型)
3.2基本類型和值
基本類型--returnAddress類型(jvm指令的操作碼的指針,不是java類型)
?--數值類型--整型--byte
???--short
???--int
???--long
??? --浮點型--float
???? --double
???--char
jvm中沒有boolean類型,java中的boolean類型的操作被翻譯為int類型進行操作。
問題:在數值類型中提及的NaN值對應于java里的什么情況
3.3引用類型和值
有三種引用類型:類類型,接口類型,數組類型
3.4字
jvm中沒有指定數據類型的存儲器大小,只是指定了一個“字”的概念,一個字足以持有byte,int,char,short,float,returnAddress,refrence的值,兩個字足夠大持有double,long的值。
一般來說,一個字的大小是主機平臺的一個指針的大小,32位機上,字是32位,64位機上,字是64位的,但這是實現決定的,而不是jvm規范決定的。
3.5運行期數據
pc(程序計數器)寄存器:
每個jvm線程有自己的pc寄存器,在任何點,每個jvm線程執行一個單個方法的 代碼,這個方法被稱為那個線程的當前方法。如果方法是native,則pc寄存器的值沒有定義,如果不是,則pc寄存器中存放當前正在執行的jvm指令的地址。
pc寄存器占一個字寬。
棧:
每個jvm線程都有私有的棧。等價于傳統語言的棧,它持有局部變量和部分結果。并參與部分方法的調用和返回。(由于java框架是可以堆分配的,所以java的棧的存儲空間可以是不連續的)
java棧可以是固定大小或者是動態的。jvm實現可以向程序員提供對java棧的初始大小以及動態情況下的最大和最小值的控制。
如果固定大小而且線程需要的棧大于棧的大小,則出現stackoverflowError
如果動態大小但存儲器沒有足夠空間,則出現outOfMemoryError
Sun的jdk1.0.2版jvm實現中,java棧是不連續、動態的,不收縮,在線程消亡時被回收。java棧的大小的限制可以在jvm啟動時用“-oss”標志設置。
堆:
java有一個所有線程共享的堆。堆是用于分配所有類實例和數組的運行期數據區。
堆在jvm啟動時創建,由garbage collector回收。
堆可以是固定的,也可以動態擴展,并且支持自動收縮,存儲器無需連續。
jvm實現可以向程序員提供堆初始大小以及動態情況下的最大和最小值的控制。
如果要求的堆比系統能夠擁有的堆大,則出現OutOfMemoryError
Sun的jdk1.0.2中,堆是動態的,從不收縮它的堆,它的初始值和最大值在啟動時用“-ms”和“-mx”指定。
方法區:
方法區類似于傳統語言中編譯后代碼的存儲區,存儲每個類結構例如:常數池、域、方法數據。
方法區是虛擬機建立的時候啟動的,邏輯上是垃圾回收實現的一部分,但可以不實現。
方法區可以固定大小,可以動態,可以收縮,無需連續存儲器。
jvm實現可以向程序員提供方法區初始大小以及動態情況下的最大和最小值的控制。
outofmemory異常
sun的jdk1.0.2中,仿佛去是動態的,不收縮的,不提供程序員對其最大最小值的控制。
常數池:
常數池是每個類或接口的constant_pool的運行期表示。功能類似于傳統語言的符號表,但含更寬的數據范圍。(詳細見第五章)
自身方法棧(估計應該是native method stack)
其管理和普通棧類似,每個線程一個,線程創建時創建,只是使用非java的native語言(如C)寫成,以支持native方法。
Sun的jdk1.0.2版jvm實現中,java棧是固定大小。java棧的大小的限制可以在jvm啟動時用“-oss”標志設置。
3.6框架
jvm frame用于存儲數據和部分結果,以及動態鏈接,返回方法的值,和調度異常。
每次java方法調用時創建一個新的框架,當方法結束的時候,框架撤銷。框架從創建它的線程的棧里分配,每個框架有自己的局部變量集和操作數棧(這些可以一次分配,因為都是編譯期可知的)。
對于一個給定線程的任何點,只有一個活躍框架,稱為當前框架,局部變量和操作數棧上的操作總是引用當前框架。
局部變量:
每個jvm frame包含一組局部變量,局部變量總是一個字寬,long型,double型存為兩個局部變量。
操作數棧:
每個jvm frame包含一個操作數棧,絕大多數java操作從當前操作數棧取值。
動態連接:
jvm frame通過包含一個對當前類的常數池的引用來達到動態鏈接的目的,java 的class文件仍然可以使用符號引用訪問變量或方法。
java中的i=i++從這一章來理解應該是和框架(jvm frame)這個概念有關,也就是++操作符被實現成為了一個方法,而不是一個虛擬機指令,這樣就可以解釋了,但是目前還沒有看到有++操作符應該被實現為一個方法的說明,另外java的方法調用是值傳參的,這種情況應該也不會出現值回寫的情況.
看至3。6結束。
3.7對象的表示
jvm不對對象表示要求任何特殊的內部結構。
在sun公司的jdk實現中,對象實例就是指向一個句柄的指針,而這個句柄本身又包括兩個指針:1、一個指向包含該對象方法而代表該對象類型的class對象的指針,2、另一個指向在java堆中為該對象實例分配的存儲區域。
別的jvm實現可以采用諸如:直接插入高速緩存技術,等。
3.8特殊的初始化方法
實例初始化:構造函數作為具有特殊名字《init》的實例初始化方法出現,方法的名字由編譯器提供,這個方法由jvm在內部由invokespecial指令調用,只能使用于未初始化的實例上,不能被java程序員使用。
類和接口的初始化:類和接口的初始化具有特殊的名字《cinit》,方法的名稱由編譯器提供,該方法由jvm顯示調用,從不直接被java代碼和jvm指令調用,只是作為類初始化進程的一部分被間接的調用。
3.9異常
異常一層層向上拋,丟棄當前層的操作數棧和局部變量,知道遇到catch為止,如果到頂層還沒有catch,當前線程將被結束。
3.10class文件格式
class文件是平臺無關格式的二進制文件,class文件格式精確定義了文件的內容。
3.11指令集概述
一個jvm指令由一個字節的操作碼后跟0個或多個操作數構成。操作數的數目由操作碼決定。
當操作數多于一個字節的時候,以高位字節在前的方式存儲。
字節碼指令流只是單字節對齊的(除了tableswitch,和lookupswitch的特殊指令對操作數的特殊要求),放棄了數據對齊,反映了對數據緊湊性的偏好,而排除了可能提高jvm仿真器性能的某些實現技術。
jvm指令中絕大多數是類型相關的,也就是作用于特定類型的操作數的。并在該指令的助記符中顯示的標識出來。
具體的指令集后面細說。
3.12公共設計、私有實現
公共概念:class文件格式和jvm指令集
2004-09-27
學習java虛擬機規范之前,已經有了心理的準備,像我這種從應用中開始真正了解計算機的人,可能會遇到許許多多的問題,很多關于底層的,硬件級別的概念可能會無法理解,但是只要能開始,就是進步,不是嗎。
第一章:前言
************************************************************************************************
java虛擬機假定任何實現技術或主機平臺,它并不非得是解釋型的,它也可以像傳統的程序設計語言一樣,通過把它的指令集編譯成一個實際的CPU指令集來實現。它也可以直接用微代碼或者直接用芯片來實現。
?
第二章:Java概念
(這個部分是對Java語言的介紹,這里羅列出一些比較細節的概念)
1、Java語言使用Unicode1.1.5版編寫。
2、除了注釋、字符、字符串、標識符之外,Java程序的所有輸入元素都是ascii碼形式。
?? 測試證明變量定義可以使用中文。
3、字符串文字以及更一般的常數表達式的值的字符串,被用方法String.inter內部化以共享惟一的實例。
4、整型和引用類型可以轉化為boolean型,非零和非null都為true。(以標準C++的方式x!=0和obj!=null)
5、三種引用類型:類引用,接口引用,數組引用,所有對象包括數組都支持Object類的方法。
6、執行順序:裝載類---鏈接一個類型或者類(檢驗,準備和可選的解析)---初始化(這個初始化可能引起相關父類的初始化動作)
7、類實例退出的時候自動的調用finalize()方法
8、類卸載的時候自動調用classFinalize()方法。
9、虛擬機退出的條件:1、所有非守護線程中止。2、顯式調用了Runtime或者System的exit方法
************************************************************************************************
6、變量是一種存儲位置,有相應的類型,稱為編譯期類型,可以是引用類型,也可以是基本類型。
?? 問題:變量本身是怎樣的一個存在,它的結構如何。
7、java語言中多次提到基本數值類型的特殊值NaN,但是不知道其表現和使用。
2004-6-3凌晨1點,讀至2、16 執行,31頁。
2004-6-3下午五點:讀至34頁
2004-6-6晚上8:30-10:30,讀至第三章:java虛擬機結構:41頁
為了了解i=i++的奧秘,我提前閱讀了第八章:線程和鎖,好像能夠理解,結果又被全盤推翻了。(通查網上的說法:i=i++的特殊之處在于i++,或者說是++操作符的實現,i++操作的方式是1:將i值拷貝一份到另一內存區域,2、對原i值執行++操作,3、將i++的結果放入新分配的區域內,而對于i=i++,就多了第四步:4、將i++值回寫到i的存儲區域中),但java為什么這么實現不是很清楚