new & valueof & 直接賦值的區別
首先來看下面這段代碼
public static void main(String[] args) {
??String s1 = "s1";
??String s2 = new String("s2");
??String s3 = String.valueOf(12345);
}
?
編譯成class文件之后,使用eclipse class file viewer查看
?
? // Method descriptor #15 ([Ljava/lang/String;)V
? // Stack: 3, Locals: 4
? public static void main(java.lang.String[] args);
???? 0? ldc <String "s1"> [16]
???? 2? astore_1 [s1]
???? 3? new java.lang.String [18]
???? 6? dup
???? 7? ldc <String "s2"> [20]
???? 9? invokespecial java.lang.String(java.lang.String) [22]
??? 12? astore_2 [s2]
??? 13? sipush 12345
??? 16? invokestatic java.lang.String.valueOf(int) : java.lang.String [25]
??? 19? astore_3 [s3]
??? 20? return
????? Line numbers:
??????? [pc: 0, line: 12]
??????? [pc: 3, line: 13]
??????? [pc: 13, line: 14]
??????? [pc: 20, line: 20]
????? Local variable table:
??????? [pc: 0, pc: 21] local: args index: 0 type: java.lang.String[]
??????? [pc: 3, pc: 21] local: s1 index: 1 type: java.lang.String
??????? [pc: 13, pc: 21] local: s2 index: 2 type: java.lang.String
??????? [pc: 20, pc: 21] local: s3 index: 3 type: java.lang.String
}
?
對于第一行代碼 String s1 = "s1"; 編譯成字節碼之后,對應兩條指令,
-
ldc指令從運行時常量池push一個值到Frame的操作數棧上面,這個值在這里就是"s1"字符串的引用,
-
astore指令將objectref存儲到局部變量,這里也就是存儲到局部變量s1。
?
對于第二行代碼???String s2 = new String("s2");編譯成字節碼之后,對于的指令也用高亮標注出來了,這里把操作數棧的情況畫了出來,希望能幫助理解。橙色標注的為棧頂元素。
-
new指令會在堆上創建對象,操作數棧里壓入創建的objectref,
-
-
ldc指令依然是從常量池push一個值到Frame的操作數棧上,這個值是"s2"字符串的引用。?
|
"s2"_ref |
objectref |
objectref |
... |
-
invokespecial 指令調用一個方法,這里就是調用String的構造函數,調用完成之后棧上還有一個objectref?
-
astore指令將objectref存儲到局部變量,這里也就是存儲到局部變量s2。?
?
對于第三行代碼??String s3 = String.valueOf(12345); 編譯成字節碼之后對應的指令,
-
sipush 將 12345 壓棧
-
invokestatic 調用 String.valueof(int) 方法
-
astore 將棧頂的對象引用存儲到本地變量s3 (這里不再深究這個棧頂元素是怎么來的了)
?
PMD檢查代碼的時候,有這樣的warning: Avoid instantiating?String objects.Call String.valueOf() instead. PMD給出的原因是In JDK 1.5, calling new String() causes memory allocation. String.valueOf() is more memory friendly.
?
經過上面的分解,我們應該知道原因了,以后寫代碼的時候,初始化一個字符串,??String s1 = "s1"; 這樣的代碼肯定比??String s2 = new String("s2");代碼強,將其他類型的值轉換成String的時候,valueof方法比new方法效率也高。
?
備注:
A frame is used to store data and partial results(局部變量,操作數棧), as well as to perform dynamic linking , return values for methods, and dispatch exceptions.
?
ldc指令的操作數棧: ...->...,value (value是int,float 或者 string 類型的引用)
astore的操作數棧: ...,objectref->...
new指令的操作數棧: ...->...,objectref
dup指令的操作數棧: ...,value->...,value,value
invokespecial的操作數棧: ...,objectref, [agr1,[arg2...]]->...
invloestatic的操作數棧:..., [arg1, [arg2...]]?-> ...
?
如果要理解的更透徹建議閱讀以下參考資料:
posted @
2008-07-28 14:27 jht 閱讀(1704) |
評論 (1) |
編輯 收藏
java.awt.Component.requestFocusInWindow
posted @
2008-07-22 14:34 jht 閱讀(386) |
評論 (1) |
編輯 收藏
http://www.tkk7.com/Files/jht/MyScreenSnap_2.0.zip
截圖程序,設計目標:簡單易用
支持全屏截圖和選擇截圖,運行需要JRE1.5以上版本
在1.0版
http://www.tkk7.com/Files/jht/MyScreenSnap.zip的基礎上,
?? * 修改了一下主界面,增加圖片保存為BMP,GIF,JPG,PNG格式的功能
?? * 參考了
千里冰封的代碼,加上了調整選擇區域的功能
Source Code已經包含在壓縮包里面了,有興趣的可以down下來改改。
下面是1.0版本和2.0版本的兩個界面。
posted @
2008-07-02 09:17 jht 閱讀(331) |
評論 (1) |
編輯 收藏
其實是個簡單的小問題,僅在此做個記錄。
遇到這個問題的不妨讀一下這篇文章先:Access查詢和過濾條件
http://www.fontstuff.com/access/acctut06.htm我遇到的報錯語句如下:
update?monitor_table?set?logoffTime?='2008-04-06?16:58:54',?keyClickCount?='17'?where?userName?='abcd'?and?logonTime?='2008-04-06?16:56:36'?讀了上面的文章,知道
MS Access的時間分隔符號為 # ,而 MS SQL Server的時間分隔符為 '
所以正確的語句應該是:
update?monitor_table?set?logoffTime?='2008-04-06?16:58:54',?keyClickCount?='17'?where?userName?='abcd'?and?logonTime?=#2008-04-06?16:56:36#?
posted @
2008-05-19 15:39 jht 閱讀(1912) |
評論 (1) |
編輯 收藏
http://download-west.oracle.com/docs/cd/B10501_01/appdev.920/a96616/arxml24.htm
posted @
2008-05-19 15:38 jht 閱讀(192) |
評論 (0) |
編輯 收藏
如題,有人真的遇到過這個問題,開始被問到的時候還真覺得奇怪,心想不會啊,從JDK5開始就支持這個枚舉類型了啊,為什么呢?
開始還懷疑他的JDK版本太低導致的,但是一看是JDK1.6的,迷惑了幾秒。。。
然后我打開了Eclipse的Java編譯選項,
發現原來遇到這個問題的人的Java編譯級別設置的是1.4,如下圖,當然就會出問題了。

呵呵,雖然,這是個小問題,但是如果遇到了還真夠新手郁悶一陣的。
posted @
2008-04-02 20:56 jht 閱讀(899) |
評論 (2) |
編輯 收藏
作者簡介
徐皓,北京航空航天大學計算機系本科生,你可以通過ertri@163.com與他聯系。
正文
不靈敏的圖形用戶界面會降低應用程序的可用性。當以下現象出現的時候,我們通常說這個用戶界面反應不靈敏。
- 不響應事件的現象;
- 沒有更新的現象
[@more@]
這些現象在很大程度上與事件的處理方法相關,而在編寫Swing應用程序的時候,我們幾乎必然要編寫方法去響應鼠標點擊按鈕,鍵盤回車等事件。在這些方法中我們要編寫一些代碼,在運行時去觸發一些動作。常見動作包括查找,更新數據庫等。在這篇文章中通過對一個實例的分析,介紹了一些基本概念,常見的錯誤以及提出了一個解決方案。
event-dispatching thread
我們一定要記住,事件響應方法的代碼都是在event-dispatching thread中執行的,除非你啟用另一個線程。
那么,什么是event-dispatching thread呢?在《Java Tutorial》[1]中,作者給出了一條單一線程規則:一旦一個Swing組件被實現(realized),所有的有可能影響或依賴于這個組件的狀態的代碼都應該在event-dispatching thread中被執行。而實現一個組件有兩種方式:
- 對頂層組件調用show(), pack(), 或者setVisible(true);
- 將一個組件加到一個已經被實現的容器中。
單一線程規則的根源是由于Swing組件庫的大部分方法是對多線程不安全的,盡管存在一些例外。這些例外的情況可以在《Java Tutorial》[1]的相關章節找到,這里不再展開。
為了支持單一線程模型,Swing組件庫提供了一個專門來完成這些與Swing組件相關的操作的線程,而這一線程就是event-dispatching thread。我們的事件響應方法通常都是由這一線程調用的,除非你自己編寫代碼來調用這些事件響應方法。在這里初學者經常犯的一個錯誤就是在事件響應方法中完成過多的與修改組件沒有直接聯系的代碼。其最有可能的效果就是導致組件反應緩慢。比如以下響應按鈕事件的代碼:
String str = null;
this.textArea.setText("Please wait...");
try {
//do something that is really time consuming
str = "Hello, world!";
Thread.sleep(1000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
this.textArea.setText(str); ? ?
執行之后的效果就是按鈕似乎定住了一段時間,直到Done.出現之后才彈起來。原因就是Swing組件的更新和事件的響應都是在event-dispatching thread中完成的,而事件響應的時候,event-dispatching thread被事件響應方法占據,所以組件不會被更新。而直到事件響應方法退出時才有可能去更新Swing組件。
為了解決這個問題,有人也許會試圖通過調用repaint()方法來更新組件:
final String[] str = new String[1];
this.jTextArea1.setText("Please wait...");
this.repaint();
try {
Thread.sleep(1000L);
}catch(InterruptedException e) {
e.printStackTrace();
}
str[0] = "Done.";
jTextArea1.setText(str[0]);
但是這一個方法沒有起到預期的作用,按鈕仍然定住一段時間,在察看了repaint()方法的源代碼之后就知道原因了。
PaintEvent e = new PaintEvent(this, PaintEvent.UPDATE,
new Rectangle(x, y, width, height));
Toolkit.getEventQueue().postEvent(e); ? ? ? ?
repaint()方法實際上是在事件隊列里加了一個UPDATE的事件,而沒有直接去重畫組件,而且這一個事件只能等待當前的事件響應方法結束之后才能被分配。因此只有繞過分配機制直接調用paint方法才能達到目的。
final String[] str = new String[1];
this.jTextArea1.setText("Please wait...");
this.paint(this.getGraphics());
try {
Thread.sleep(1000L);
}catch(InterruptedException e) {
e.printStackTrace();
}
str[0] = "Done.";
jTextArea1.setText(str[0]);
這樣卻是實現了更新,但是還存在著以下的問題。雖然從感覺上,按鈕已經彈起來了,但是在Done.出現之前,我們卻無法按下這個按鈕??梢哉f按鈕還是定住了,只不過定在了彈起的狀態。調用重繪方法無法從根本上解決問題,因此我們需要尋求其他的方法。
使用多線程
有效的解決方法是使用多線程。首先看一看一個更好的解決方案,這一方案是在參考《Rethinking Swing Threading》[3]的一個程序片段完成的:
final String[] str = new String[1];
this.jTextArea1.setText("Please wait...");
this.repaint();
new Thread() {
public void run() {
try {
Thread.sleep(1000L);
}catch(InterruptedException e) {
e.printStackTrace();
}
str[0] = "Done.";
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
jTextArea1.setText(str[0]);
}
});
}
}.start();
在這個程序中,要花費大量時間的操作被放到另一個線程當中,從而使事件響應方法能快速返回,event-dispatching thread就可以更新UI和響應其它事件了。注意到這個程序使用了invokeLater()方法。invokeLater()方法的作用是讓event-dispatching thread去運行制定的代碼。當然也可以不使用invokeLater()方法,但是這樣就違背了單一線程原則,同時帶來了一定程度的相對多線程的不安全性。到現在,解決方案似乎是完美的了,但是我們看一看在原來的程序添加下面的代碼,盡管我們通常不這樣做。
public void paint(java.awt.Graphics g) {
super.paint(g);
g.drawRect(1, 1, 100, 100);
}
我們會發現以前畫的矩形被覆蓋了一部分,原因是由于我們沒用重畫這一個矩形,因此在結尾加上對repaint()方法的調用。
final String[] str = new String[1];
this.jTextArea1.setText("Please wait...");
this.repaint();
new Thread() {
public void run() {
try {
Thread.sleep(1000L);
}catch(InterruptedException e) {
e.printStackTrace();
}
str[0] = "Done.";
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
jTextArea1.setText(str[0]);
repaint();
}
});
}
}.start();
如果你認為這段代碼過于缺乏可讀性,通過在《Java Tutorial》[1]里面介紹的SwingWorker來簡化編程的方法。可以通過實現一個construct()方法來實現花費大量時間的操作和重寫finished()方法來完成組件更新的工作。
this.jTextArea1.setText("Please wait...");
final SwingWorker worker = new SwingWorker() {
public Object construct() {
try {
Thread.sleep(1000L);
}catch(InterruptedException e) {
e.printStackTrace();
}
return "Done.";
}
public void finished() {
jTextArea1.setText(getValue().toString());
repaint();
}
};
worker.start();
在《Rethinking Swing Threading》[3],作者將以上的編程方式稱為同步方式。另外作者提出了一個通過消息機制來實現相同功能的更清晰,但是需要編寫更多代碼的"異步"的方法。
結論
總之,我們在編寫使用Swing組件的程序是要記住以下幾點:
1、不要過多地占用event-dispatching thread;
2、與更新組件相關的代碼要使用event-dispatching thread去執行;
3、要更新組件。
編寫反應靈敏的圖形用戶界面還需要考慮很多問題,以上只是最基本的一部分。歡迎有興趣的讀者來信進行討論。
posted @
2008-03-13 17:53 jht 閱讀(574) |
評論 (0) |
編輯 收藏
打開注冊表編輯器,進入主鍵[HKEY_CURRENT_USER\Software\Microsoft\Command Processor],將“CompletionChar”鍵值設置為9。
posted @
2008-01-30 16:40 jht 閱讀(708) |
評論 (0) |
編輯 收藏
在Struts中我們用html:errors標簽在JSP頁面上輸出驗證過程中產生的錯誤信息,錯誤信息一般來自于消息資源文件(xxx.properties文件,一般位于classes目錄下,文本文件),當然錯誤信息也可以是不是資源文件中的文本消息,而是自定義的文本。接下來將詳細講述。
先來看一個簡單例子
1、資源文件錯誤信息來源(其格式為 key = value )
???
?? error.test = this is a test error.
2、JSP頁面中用于顯示錯誤信息標簽
??
?? <html:errors property="testerror"/>
3、ActionFormBean的validate()方法中產生錯誤信息
?? ActionErrors error = new ActionErrors();
?? error.add("testerror",new ActionMessage("error.test"))
??
?? return error;
?
這個例子的功能就是在ActionForm Bean的validate()方法中產生一條名為:testerror的錯誤信息,錯誤信息息是資源文件中key為error.test的值。然后在頁面上用html:errors標簽輸出testerror這條錯誤信息。
這是最常用的一種功能,所有的錯誤信息都在資源文件里面。
有人會問,錯誤信息只能存放在資源文件中嗎,其實不是這樣。不需要資源文件也可以產生錯誤信息。
我們再來看一下ActionMessage的另一種構造方法:
ActionMessage(String key,boolean isresource)
如果isresource值為true,則表示key是資源文件中的key,產生的消息就是與key相對應的消息
如果isresource值為false,則表示key為一條普通的消息。
如果上面的error.add改為error.add("testerror",new ActonMessage("這是一條自定義消息",false",));那么頁面上顯示的將是:這是一條自定義消息.
另外還可以用ActionMessage產生復合消息,比如我們要輸出:xxx不能用作用戶名,其中xxx是一個變量。
首先我們在資源文件中加一個條復合消息
testmsg = {0}不能用作用戶名。這里{0}是要被替換的參數。
我們再來看一下ActionMessage的另一中構造方法
ActionMessage(String key,Object value0);
也就是說用value0的值來替換{0}
我們修改error.add為error.add("testerror",new ActonMessage("testmsg","毛澤東"))
那么JSP頁面上將顯示:毛澤東不能用作用戶名。
當然在一條復合消息中也可帶多個參數,參數依次為{0},{1},{2}或更多
例如:loginUser = 用戶名:{0} 姓名:{1} 登錄次數:{2}.....
那么在產生錯誤消息時就用new ActionMessage(String key,Object value0,Object value1,Object? value2.....)或者使用對象數組new ActionMessage(String key,Object[] values)
String[] detail = {"Admin","王晶","12"};
error.add("testerror",new ActionMessage("loginUser",detail))
Note:
Cannot find message resources under key org.apache.struts.action.MESSAGE? 錯誤的原因是沒有配置資源文件
解決辦法: 在struts-config.xml 中加入如下的一段
<message-resources parameter="application" null="false"></message-resources>
posted @
2008-01-14 22:20 jht 閱讀(1150) |
評論 (1) |
編輯 收藏
備忘:
>?sqlplus?(
<
username
>
[/
<
password
>
][@
<
connect_identifier
>
]?|?/)?[AS?SYSDBA?|?AS?SYSOPER]?|?/NOLOG
?SQL?
>
???
desc
??user_source;
?Name???????????????????????????????????????
Null
??????Type
??
--
?---------------------------------------?--------?----------------------------?
??NAME????????????????????????????????????????????????
VARCHAR2
?(?
30
?)
?TYPE????????????????????????????????????????????????
VARCHAR2
?(?
12
?)
?LINE????????????????????????????????????????????????
NUMBER
?
??
TEXT
?????????????????????????????????????????????????
VARCHAR2
?(?
4000
?)

SQL?
>
???
select
???
TEXT
???
from
??user_source??
where
??TYPE?
=
?
'
?PROCEDURE?
'
???
and
??NAME?
=
?
'
?Your_Procedure_name?
'
?;

no?rows?selected

SQL?
>
??
var
?out_var?
number
exec
?Your_Procedure_name?(
''
,
''
,
''
,:out_var)
print
?out_var
posted @
2007-11-28 14:00 jht 閱讀(2739) |
評論 (0) |
編輯 收藏