如果你覺得你的Eclipse在啟動的時候很慢(比如說超過20秒鐘),也許你要調整一下你的Eclipse啟動參數了,以下是一些``小貼士'':
1. 檢查啟動Eclipse的JVM設置。 在Help\About Eclipse SDK\Configuration Detail里面,你可以看到啟動Eclipse的JVM。 這個JVM和你在Eclipse中設置的Installed JDK是兩回事情。 如果啟動Eclipse的JVM還是JDK 1.4的話,那最好改為JDK 5,因為JDK 5的性能比1.4更好。
C:\eclipse\eclipse.exe -vm "C:\Program Files\Java\jdk1.5.0_08\ bin\javaw.exe"
2. 檢查Eclipse所使用的heap的大小。 在C:\eclipse目錄下有一個配置文件eclipse.ini,其中配置了Eclipse啟動的默認heap大小
-vmargs
-Xms40M
-Xmx256M
所以你可以把默認值改為:
-vmargs
-Xms256M
-Xmx512M
當然,也可以這樣做,把堆的大小改為256 - 512。
C:\eclipse\eclipse.exe -vm "C:\Program Files\Java\jdk1.5.0_08\ bin\javaw.exe" -vmargs -Xms256M -Xmx512M
3. 其他的啟動參數。 如果你有一個雙核的CPU,也許可以嘗試這個參數:
-XX:+UseParallelGC
讓GC可以更快的執行。(只是JDK 5里對GC新增加的參數)
Java對多線程的支持與同步機制深受大家的喜愛,似乎看起來使用了synchronized關鍵字就可以輕松地解決多線程共享數據同步問題。到底如何?――還得對synchronized關鍵字的作用進行深入了解才可定論。
總的說來,synchronized關鍵字可以作為函數的修飾符,也可作為函數內的語句,也就是平時說的同步方法和同步語句塊。如果再細的分類,synchronized可作用于instance變量、object reference(對象引用)、static函數和class literals(類名稱字面常量)身上。
在進一步闡述之前,我們需要明確幾點:
A.無論synchronized關鍵字加在方法上還是對象上,它取得的鎖都是對象,而不是把一段代碼或函數當作鎖――而且同步方法很可能還會被其他線程的對象訪問。
B.每個對象只有一個鎖(lock)與之相關聯。
C.實現同步是要很大的系統開銷作為代價的,甚至可能造成死鎖,所以盡量避免無謂的同步控制。
接著來討論synchronized用到不同地方對代碼產生的影響:
假設P1、P2是同一個類的不同對象,這個類中定義了以下幾種情況的同步塊或同步方法,P1、P2就都可以調用它們。
1. 把synchronized當作函數修飾符時,示例代碼如下:
Public synchronized void methodAAA()
{
//….
}
這也就是同步方法,那這時synchronized鎖定的是哪個對象呢?它鎖定的是調用這個同步方法對象。也就是說,當一個對象P1在不同的線程中執行這個同步方法時,它們之間會形成互斥,達到同步的效果。但是這個對象所屬的Class所產生的另一對象P2卻可以任意調用這個被加了synchronized關鍵字的方法。
上邊的示例代碼等同于如下代碼:
public void methodAAA()
{
synchronized (this) // (1)
{
//…..
}
}
(1)處的this指的是什么呢?它指的就是調用這個方法的對象,如P1。可見同步方法實質是將synchronized作用于object reference。――那個拿到了P1對象鎖的線程,才可以調用P1的同步方法,而對P2而言,P1這個鎖與它毫不相干,程序也可能在這種情形下擺脫同步機制的控制,造成數據混亂:(
2.同步塊,示例代碼如下:
public void method3(SomeObject so)
{
synchronized(so)
{
//…..
}
}
這時,鎖就是so這個對象,誰拿到這個鎖誰就可以運行它所控制的那段代碼。當有一個明確的對象作為鎖時,就可以這樣寫程序,但當沒有明確的對象作為鎖,只是想讓一段代碼同步時,可以創建一個特殊的instance變量(它得是一個對象)來充當鎖:
class Foo implements Runnable
{
private byte[] lock = new byte[0]; // 特殊的instance變量
Public void methodA()
{
synchronized(lock) { //… }
}
//…..
}
注:零長度的byte數組對象創建起來將比任何對象都經濟――查看編譯后的字節碼:生成零長度的byte[]對象只需3條操作碼,而Object lock = new Object()則需要7行操作碼。
3.將synchronized作用于static 函數,示例代碼如下:
Class Foo
{
public synchronized static void methodAAA() // 同步的static 函數
{
//….
}
public void methodBBB()
{
synchronized(Foo.class) // class literal(類名稱字面常量)
}
}
代碼中的methodBBB()方法是把class literal作為鎖的情況,它和同步的static函數產生的效果是一樣的,取得的鎖很特別,是當前調用這個方法的對象所屬的類(Class,而不再是由這個Class產生的某個具體對象了)。
記得在《Effective Java》一書中看到過將 Foo.class和 P1.getClass()用于作同步鎖還不一樣,不能用P1.getClass()來達到鎖這個Class的目的。P1指的是由Foo類產生的對象。
可以推斷:如果一個類中定義了一個synchronized的static函數A,也定義了一個synchronized 的instance函數B,那么這個類的同一對象Obj在多線程中分別訪問A和B兩個方法時,不會構成同步,因為它們的鎖都不一樣。A方法的鎖是Obj這個對象,而B的鎖是Obj所屬的那個Class。
小結如下:
搞清楚synchronized鎖定的是哪個對象,就能幫助我們設計更安全的多線程程序。
還有一些技巧可以讓我們對共享資源的同步訪問更加安全:
1. 定義private 的instance變量+它的 get方法,而不要定義public/protected的instance變量。如果將變量定義為public,對象在外界可以繞過同步方法的控制而直接取得它,并改動它。這也是JavaBean的標準實現方式之一。
2. 如果instance變量是一個對象,如數組或ArrayList什么的,那上述方法仍然不安全,因為當外界對象通過get方法拿到這個instance對象的引用后,又將其指向另一個對象,那么這個private變量也就變了,豈不是很危險。這個時候就需要將get方法也加上synchronized同步,并且,只返回這個private對象的clone()――這樣,調用端得到的就是對象副本的引用了。
這幾個學習材料非常短小精悍,可清晰快捷的掌握以下幾個概念,方便更深入學習
XML tutorial:
http://www.w3schools.com/xml/default.asp
SOAP tutorial:
http://www.w3schools.com/soap/default.asp
WSDL tutorial:
http://www.w3schools.com/wsdl/default.asp
WEB Service tutorial:
http://www.w3schools.com/webservices/default.asp
插入排序: package org.rut.util.algorithm.support; import org.rut.util.algorithm.SortUtil; ??? /* (non-Javadoc) } package org.rut.util.algorithm.support; import org.rut.util.algorithm.SortUtil; /** ??? /* (non-Javadoc) } 選擇排序: package org.rut.util.algorithm.support; import org.rut.util.algorithm.SortUtil; /** ??? /* } Shell排序: package org.rut.util.algorithm.support; import org.rut.util.algorithm.SortUtil; /** ??? /* (non-Javadoc) ??? /** } 快速排序: package org.rut.util.algorithm.support; import org.rut.util.algorithm.SortUtil; /** ??? /* (non-Javadoc) } package org.rut.util.algorithm.support; import org.rut.util.algorithm.SortUtil; /** ??? private static int MAX_STACK_SIZE=4096; } 歸并排序: package org.rut.util.algorithm.support; import org.rut.util.algorithm.SortUtil; /** ??? /* (non-Javadoc) } 改進后的歸并排序: package org.rut.util.algorithm.support; import org.rut.util.algorithm.SortUtil; /** ??? private static final int THRESHOLD = 10; ??? /* ??? private void mergeSort(int[] data, int[] temp, int l, int r) { ??????? for (i = l; i <= mid; i++) { ??? /** } package org.rut.util.algorithm.support; import org.rut.util.algorithm.SortUtil; /** ??? /* (non-Javadoc)
??????? private int[] queue; ??????? public void remove() { ??? } } ? SortUtil: package org.rut.util.algorithm; import org.rut.util.algorithm.support.BubbleSort; /** ??? public final static int BUBBLE = 2; ??? public final static int SELECTION = 3; ??? public final static int SHELL = 4; ??? public final static int QUICK = 5; ??? public final static int IMPROVED_QUICK = 6; ??? public final static int MERGE = 7; ??? public final static int IMPROVED_MERGE = 8; ??? public final static int HEAP = 9; ??? public static void sort(int[] data) { ??? public static String toString(int algorithm){ ??? public static interface Sort { ??? public static void swap(int[] data, int i, int j) { |
Unicode是Apple和Xerox公司于1988年建立的一個技術標準。1991年,成立了一個集團機構負責Unicode的開發和推廣應用。該集團由Apple、Compaq、IBM、Microsoft、Oracle、Silicon ? Graphics, ? Inc.、Sybase、Unisys和Xerox等公司組成。該集團負責維護Unicode標準。
Unicode提供了一種簡單而又一致的表示字符串的方法。Unicode字符串中的所有字符都是16位的(兩個字節)。它沒有專門的字節來指明下一個字節是屬于同一個字符的組成部分,還是一個新字符。這意味著你只需要對指針進行遞增或遞減,就可以遍歷字符串中的各個字符,不再需要調用CharNext之類的函數。由于Unicode用一個16位的值來表示每個字符,因此總共可以得到65000個字符,這樣,它就能夠對世界各國的書面文字中的所有字符進行編碼,遠遠超過了單字節字符集的256個字符的數目。
插件下載地址:
http://www.delphibbs.com/keylife/images/u88173/csdnkantie.rar
下載后解壓到myIE的plugin目錄即可。
例如我的解壓后的目錄:
D:\programs\Maxthon\Plugin\csdnkantie\
效果圖:
http://blog.csdn.net/images/blog_csdn_net/pigo/36738/o_casdnkanite001.gif
http://blog.csdn.net/images/blog_csdn_net/pigo/36738/o_casdnkanite001.gif
pop-ent.21cn.com在Connection上調用close方法會關閉Statement和ResultSet嗎?
級聯的關閉這聽起來好像很有道理,而且在很多地方這樣做也是正確的,通常這樣寫
Connection con = getConnection();//getConnection is your method
PreparedStatement ps = con.prepareStatement(sql);
ResultSet rs = ps.executeQuery();
……
///rs.close();
///ps.close();
con.close();? // NO!
這樣做的問題在于Connection是個接口,它的close實現可能是多種多樣的。在普通情況下,你用 DriverManager.getConnection()得到一個Connection實例,調用它的close方法會關閉Statement和 ResultSet。但是在很多時候,你需要使用數據庫連接池,在連接池中的得到的Connection上調用close方法的時候,Connection可能并沒有被釋放,而是回到了連接池中。它以后可能被其它代碼取出來用。如果沒有釋放Statement和ResultSet,那么在Connection上沒有關閉的Statement和ResultSet可能會越來越多,那么……
相反,我看到過這樣的說法,有人把Connection關閉了,卻繼續使用ResultSet,認為這樣是可以的,引發了激烈的討論,到底是怎么回事就不用我多說了吧。
所以我們必須很小心的釋放數據庫資源,下面的代碼片斷展示了這個過程
Connection con = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
??? con = getConnection();//getConnection is your method
??? ps = con.prepareStatement(sql);
??? rs = ps.executeQuery();
??? ///...........
}
catch (SQLException ex) {
??? ///錯誤處理
}
finally{
??? try {
??????? if(ps!=null)
??????????? ps.close();
??? }
??? catch (SQLException ex) {
??????? ///錯誤處理
??? }
??? try{
??????? if(con!=null)
??????????? con.close();
??? }
??? catch (SQLException ex) {
??????? ///錯誤處理
??? }
}
?
1. Open:? Internet Options --> Content --> AutoComplete
2. Click button: ?'Clear Forms' and 'Clear Passwords'
public class TranCharset {
??? private static final String PRE_FIX_UTF = "&#x";
??? private static final String POS_FIX_UTF = ";";
??? public TranCharset() {
??? }
??? /**
???? * Translate charset encoding to unicode
???? *
???? * @param sTemp charset encoding is gb2312
???? * @return charset encoding is unicode
???? */
??? public static String XmlFormalize(String sTemp) {
??????? StringBuffer sb = new StringBuffer();
??????? if (sTemp == null || sTemp.equals("")) {
??????????? return "";
??????? }
??????? String s = TranCharset.TranEncodeTOGB(sTemp);
??????? for (int i = 0; i < s.length(); i++) {
??????????? char cChar = s.charAt(i);
??????????? if (TranCharset.isGB2312(cChar)) {
??????????????? sb.append(PRE_FIX_UTF);
??????????????? sb.append(Integer.toHexString(cChar));
??????????????? sb.append(POS_FIX_UTF);
??????????? } else {
??????????????? switch ((int) cChar) {
??????????????????? case 32:
??????????????????????? sb.append(" ");
??????????????????????? break;
??????????????????? case 34:
??????????????????????? sb.append(""");
??????????????????????? break;
??????????????????? case 38:
??????????????????????? sb.append("&");
??????????????????????? break;
??????????????????? case 60:
??????????????????????? sb.append("<");
??????????????????????? break;
??????????????????? case 62:
??????????????????????? sb.append(">");
??????????????????????? break;
??????????????????? default:
??????????????????????? sb.append(cChar);
??????????????? }
??????????? }
??????? }
??????? return sb.toString();
??? }
??? /**
???? * 將字符串編碼格式轉成GB2312
???? *
???? * @param str
???? * @return
???? */
??? public static String TranEncodeTOGB(String str) {
??????? try {
??????????? String strEncode = TranCharset.getEncoding(str);
??????????? String temp = new String(str.getBytes(strEncode), "GB2312");
??????????? return temp;
??????? } catch (java.io.IOException ex) {
??????????? return null;
??????? }
??? }
??? /**
???? * 判斷輸入字符是否為gb2312的編碼格式
???? *
???? * @param c 輸入字符
???? * @return 如果是gb2312返回真,否則返回假
???? */
??? public static boolean isGB2312(char c) {
??????? Character ch = new Character(c);
??????? String sCh = ch.toString();
??????? try {
??????????? byte[] bb = sCh.getBytes("gb2312");
??????????? if (bb.length > 1) {
??????????????? return true;
??????????? }
??????? } catch (java.io.UnsupportedEncodingException ex) {
??????????? return false;
??????? }
??????? return false;
??? }
??? /**
???? * 判斷字符串的編碼
???? *
???? * @param str
???? * @return
???? */
??? public static String getEncoding(String str) {
??????? String encode = "GB2312";
??????? try {
??????????? if (str.equals(new String(str.getBytes(encode), encode))) {
??????????????? String s = encode;
??????????????? return s;
??????????? }
??????? } catch (Exception exception) {
??????? }
??????? encode = "ISO-8859-1";
??????? try {
??????????? if (str.equals(new String(str.getBytes(encode), encode))) {
??????????????? String s1 = encode;
??????????????? return s1;
??????????? }
??????? } catch (Exception exception1) {
??????? }
??????? encode = "UTF-8";
??????? try {
??????????? if (str.equals(new String(str.getBytes(encode), encode))) {
??????????????? String s2 = encode;
??????????????? return s2;
??????????? }
??????? } catch (Exception exception2) {
??????? }
??????? encode = "GBK";
??????? try {
??????????? if (str.equals(new String(str.getBytes(encode), encode))) {
??????????????? String s3 = encode;
??????????????? return s3;
??????????? }
??????? } catch (Exception exception3) {
??????? }
??????? encode = "BIG5";
??????? try {
??????????? if (str.equals(new String(str.getBytes(encode), encode))) {
??????????????? String s4 = encode;
??????????????? return s4;
??????????? }
??????? } catch (Exception exception3) {
??????? }
??????? return "";
??? }
??? public static void main(String args[]) {
??????? System.out.println(XmlFormalize("下載"));
??? }
}
問題:
如何在文本框中只允許輸入漢字,字母數字或者其他符號文字都不可以呢?
處理:
//javascript
var?? re=/[^\x00-\xff]/g;
if(re.test(你要測試的值))
{
????? //是漢字
}
注:用ascII碼控制。好像漢字都是負數
System.out.println(Pattern.compile("[\u4e00-\u9fa5]").matcher("a").find());
//[\u4e00-\u9fa5] 中文的正則表達式
//"a" 你想判斷的字符
問題:
在ArrayList 應用中有這樣的代碼:
ArrayList a=new ArrayList();
a.add(...);
Iterator i=a.iterator();
理解:Iterator i=a.iterator();
Iterator 是一個接口,在上面a.iterator()方法的作用是返回一個接口
hasmore(),next()是怎么被實現的?
處理:
迭代模式
ArrayList內部有一個實現了Iterator 接口的類,a.iterator就是返回它內部類的一個實例,即返回一個實現了的iterator接口的類。
接口是一個類型,相當于一個父類型(supertype),可以用一個接口引用一個實現了此接口的類的實例。這樣只能用接口提供的方法來訪問此對象,可以限制訪問,隱藏具體實現。
首先明確一下,樓主的問題應該是比較 JDK 和 JRE (而不是 JVM,因為 JDK 和 JRE 里面都包含 JVM)。
顧名思義,JDK 比 JRE 多出來的東西,就是在開發過程中要用到的一些東西,比如 javac、javadoc、keytool 等工具,還有其它的一些東西(比如 API 文檔)。一般來說,這些東西在軟件開發完成交付運行之后就用不到了。不過也有例外,比如要在 Tomcat 里跑 JSP 的話,就需要 javac。
public:公有的,說明該類成員可被所有的對象使用
protected:保護的,說明該類成員能被同一類中的其他成員,或其子類成員,或同一包中的其他類訪問,不能被其他包的非子類訪問
無:默認的.當修飾符默認時,說明該類成員能被同一類中的其他成員,或同一包中的其他類訪問,不能被其他包的類訪問
private:私有的,說明該類成員只能被同一類中的其他成員訪問,不能被其他類的成員訪問,也不能被子類成員訪問.
1. 有一個ArrayList,里面包含N個Integer,其中的Integer都是由1至N+1的數字構成,并且不重復,但是有一個1至N+1的數字對應的Integerroypayne(java = 星際) ( ![]() | 2006-03-22 09:51:00 | 得分:0 | ||
? | ||||
Top |
treeroot(旗魯特) ( ![]() | 2006-03-22 10:23:00 | 得分:0 | ||
? | ||||
Top |
huyc_fly() ( ![]() | 2006-03-22 11:09:00 | 得分:0 | ||
? | ||||
Top |
larger102(駱駝) ( ![]() | 2006-03-22 11:34:00 | 得分:0 | ||
? | ||||
Top |
huyc_fly() ( ![]() | 2006-03-22 11:55:00 | 得分:0 | ||
? | ||||
Top |
echomyf(ECHO) ( ![]() | 2006-03-22 12:42:00 | 得分:0 | ||
? | ||||
Top |
diy8187(雞狗豬驢) ( ![]() | 2006-03-22 13:00:00 | 得分:0 | ||
? | ||||
Top |
hyper784533() ( ![]() | 2006-03-22 13:05:00 | 得分:0 | ||
? |
Singleton模式主要作用是保證在Java應用程序中,一個類只有一個實例存在。解釋下面的代碼是怎么保證只有一個實例的?
public class Singleton {
private Singleton(){}
private static Singleton instance = new Singleton();
public static Singleton getInstance() {
return instance;
}
}
處理:
因為構造函數是私有的,用戶不能自己實例對象 private Singleton(){}
而且指向這個唯一的對象的引用也是私有,只能通過getInstance方法返回對象的引用
getInstance方法正實現了保證唯一對象的功能
用戶登陸,登陸成功后將用戶名和密碼保存到session中,然后轉到登陸成功后的頁面。
現在有一個問題,如果有人看到了某一個頁面的url,可以直接在地址欄直接輸入url進去,由于session中有用戶名和密碼,所以系統認為他也是合法的用戶,如何解決?
處理:
一、 session是存在服務器上面的?
session有兩種方式一個是cookies一個就是url重寫
但是不管是哪種 都是向服務器傳達的是session的ID
所以解決的方法就是?
???? 為session設置一個存活期:session.setMaxInactiveInterval(10);
二、讓瀏覽器不再緩存
<%
response.setHeader("Pragma","No-cache");
response.setHeader("Cache-Control","no-cache");
response.setDateHeader("Expires", 0);
%>
<%@ taglib uri="<%
try{
session.invalidate();
}catch(Exception e){}
String scope = "application";
if (request.getParameter("scope") != null)
{
?scope = request.getParameter("scope");
}
boolean refresh = false;
if (request.getParameter("refresh") != null)
{
?refresh = true;
}
boolean forceCacheUse = false;
if (request.getParameter("forceCacheUse") != null)
{
?forceCacheUse = true ;
}
%>
<oscache:cache?? duration="40s" refresh="<%= request.getParameter("refresh") == null ? false : true %>" scope="<%= scope %>">
// *****************************頁面部分*********************************//
</oscache:cache>
問題:
<iframe name="I1" src="cs7.jsp" height="300" width="200"></iframe><br>
<iframe name="I2" id="I2" src="cs8.jsp" height="300" width="200">iframe>
如何把I1的值傳到I2里的一個input里?
處理:
document.getElementById("I2").src="cs8.jsp?param=p"
然后再cs8.jsp中接受param值放到input中
問題:
A.JSP如下:
……
<iframe src="B.jsp" id="B" frameborder="0" border="0"></iframe>
……
B.JSP如下,里面有一個C的JS方法
……
<script type="text/javascript">
function C()
{
}
</script>
……
請問如何在A.jsp里調用該C方法?
處理:
用b.document.script.c()
跨域腳本訪問可能造成嚴重的安全問題。一些用戶禁用了跨域腳本訪問。
問題:<html>
<iframe frameborder=0 width=600 height=50 marginheight=0 marginwidth=0 scrolling=no src="applytest.jsp" id="applytest"></iframe>
<FORM? name="form1" METHOD="POST" ACTION="customer.do?command=addapplystudent"? onsubmit="return check_data()">
<table>
? <tr>
??? <TD align="left">姓名 </TD>
??????? <td><input? type="text" name="cname">
????????? <font color="#FF0000">*</font>
??? </td>
? </tr>
</table>
</html>
///////////////////////////////////////////////////////////
現在在Action里取到的學生所在地區的id總是空,我現在請教各位------怎么取到iframe中的某個參數的值?
處理:
可以通過iframe的id="applytest"來訪問其頁面的標簽,如document.all.applytest.all.xxx來訪問其中的名為xxx的標簽.通過再在主頁面設置hidden將其值拷貝一下就行.
問題一、
<table width="99%"? border="0" align="center" cellpadding="0" cellspacing="0">
? <tr>
??? <td colspan="2"><iframe frameborder=no?
???????????? marginheight=0 marginwidth=0 name=schistory scrolling=no
??????????? src="frame2.htm"? width=100%> </iframe></td>
? </tr>
</table>
現在的問題是當frame2.htm顯示的內容很長時,有些內容看不到;如何做到該網頁隨iframe中嵌入的網頁內容長度自動出現滾動條,并且這滾動條不是出現在iframe中
處理:
你這個屬于讓iframe的子頁面決定父頁面的高度。
寫javascript吧。
<script language="Javascript">
function window.onload()
{
parent.document.all("mainFrame").style.height=document.body.scrollHeight+670;
}
</script>
寫在iframe調用的子頁面里面
后面的670是父頁面比子頁面高的高度
問題二、如何動態控制IFrame的長和寬
主頁面要放置一個IFrame用于嵌套顯示子頁面的信息,但是子頁面的數據多少不一,導致子頁面可能會很長或很短,要動態控制IFrame的高低隨子頁面的長短而變化。
主頁面如下:
<HTML>
<HEAD>
<TITLE> New Document </TITLE>
</HEAD>
<BODY >
<TABLE>
??? <TR>
?<TD>
?? <iframe id="frmTest" height="100px" name="frmTest" src="in.html"></iframe>
?</TD>
</TR>
</TABLE>
</BODY>
</HTML>
子頁面只需要做如下處理即可:
在頁面的最下端添加如下JS腳本:
<script language=javascript>
?window.parent.document.all("frmTest").style.height = document.body.scrollHeight + 10;
</script>
其中frmTest即為Main頁面的IFrame的ID。
2.下面代碼的輸出是什么?一共在內存中生成了幾個String對象?為什么?
String s1 = “aaa”;
String s2 = “aaa”;
String s3 = new String(“aaa”);
String s4 = new String(“AAA”);
System.out.println(s1 == s2);
System.out.println(s1 == s3);
System.out.println(s1.equals(s3));
3.下列程序在1處是否會有異常,如果沒有,輸出是什么?是否會運行到2處,如果會,輸出是什么?為什么會有這樣的結果?
public class TestClass {
public void test1() {
List list = new ArrayList();
test2(list);
System.out.println(list.size()); // 1處
test3(list);
System.out.println(list.size()); // 2處
}
public void test2(List list) {
list = null;
}
public void test3(List list) {
list.add(“aaaa”);
}
}
4.請選出下面哪些描述是正確的。
public class ClassA {
public synchronized void a(){
}
public synchronized void b(){
}
}
2 instances of ClassA had been instantiated obj1 and obj2.
Which statements about thread are true?
1)One thread is calling obj1.a(), another thread can call obj1.b().? .
2)One thread is calling obj1.a(), another thread cannot call obj1.b().?
3)One thread is calling obj1.a(), another thread can call obj2.b().? .
4)One thread is calling obj1.a(), another thread cannot call obj2.b().?
5.下面的程序輸出是什么?為什么?
public class Parent {
public void test(ArrayList list) {
System.out.println("invoke parent's test method");
}
public static void main(String[] args) {
Child a = new Child();
ArrayList list = new ArrayList();
a.test(list);
}
}
class Child extends Parent {
public void test(List list) {
System.out.println("invoke child's test method");
}
}
6.下面的程序輸出是什么?為什么?
public class Parent {
public void test(List list) {
System.out.println("invoke parent's test method");
}
public static void main(String[] args) {
Child a = new Child();
ArrayList list = new ArrayList();
a.test(list);
}
}
class Child extends Parent {
public void test(List list) {
System.out.println("invoke child's test method");
}
}
7.仔細分析下面的程序,寫出程序的輸出結果。
public class Parent {
{
System.out.println("parent instance block");
}
public void test() {
System.out.println("parent test method");
}
static {
System.out.println("parent static block");
}
public Parent() {
System.out.println("parent constructor");
test();
}
public static void main(String[] args) {
new Child();
}
}
class Child extends Parent {
private static int staticValue = 20;
private int instanceValue = 20;
{
System.out.println("child instance block");
}
public void test() {
System.out.println("child test method");
System.out.println("static value is: " + staticValue);
System.out.println("instance value is: " + instanceValue);
}
static {
System.out.println("child static block");
}
public Child() {
System.out.println("child constructor");
}
}
8.下面程序的輸出是什么?
public class TestException {
public void test1() {
int result = test2();
System.out.println(result);
}
public int test2() {
try{
String s = null;
s.substring(0, 1);
return 1;
} catch(Exception e) {
return 2;
} finally {
return 3;
}
}
public static void main(String[] args) {
(new TestException()).test1();
}
}
9.請寫出數據庫查詢操作的偽代碼,程序不需要通過編譯,只要思路正確,關鍵步驟不丟失就可以了。注意異常的捕獲,IO流的關閉。可能用到的類或接口有(Connection,DriverManager, Statement, PreparedStatement, ResultSet, SQLException)。
5.1.1·介紹 什么是異常?在Java編程語言中,異常類定義程序中可能遇到的輕微 的錯誤條件。可以寫代碼來處理異常并繼續程序執行,而不是讓程序 中斷。在程序執行中,任何中斷正常程序流程的異常條件就是錯誤或 ]異常。例如,發生下列情況時,會出現異常: - 想打開的文件不存在 - 網絡連接中斷 - 受控操作數超出預定范圍 - 非常感興趣地正在裝載的類文件丟失 在Java編程語言中,錯誤類定義被認為是不能恢復的嚴重錯誤條件。在 大多數情況下,當遇到這樣的錯誤時,建議讓程序中斷。Java編程語言 實現C++異常來幫助建立彈性代碼。在程序中發生錯誤時,發現錯誤的 方法能拋出一個異常到其調用程序,發出已經發生問題的信號。然后, 調用方法捕獲拋出的異常,在可能時,再恢復回來。這個方案給程序員 一個寫處理程序的選擇,來處理異常。通過瀏覽API,可以決定方法拋出 的是什么樣的異常。 5.1.2·實例 考慮一下HelloWorld.java程序版本的簡單擴展,它通過信息來循環: 1. public class HelloWorld { 2. public static void main (String args[]) { 3. int i = 0; 4. 5. String greetings [] = { 6. "Hello world!", 7. "No, I mean it!", 8. "HELLO WORLD!!" 9. }; 10. 11. while (i < 4) { 12. System.out.println (greetings[i]); 13. i++; 14. } 15. } 16. } 正常情況下,當異常被拋出時,在其循環被執行四次之后,程序終止,并帶有 錯誤信息,就象前面所示的程序那樣。 1. c:\student\> java HelloWorld 2. Hello world! 3. No, I mean it! 4. HELLO WORLD!! 5. java.lang.ArrayIndexOutOfBoundsException: 3 6. at HelloWorld.main(HelloWorld.java:12) 異常處理允許程序捕獲異常,處理它們,然后繼續程序執行。它是分層把關, 因此,錯誤情況不會介入到程序的正常流程中。特殊情況發生時,在與正常 執行的代碼分離的代碼塊中被處理。這就產生了更易識別和管理的代碼。 5.2·異常處理 Java編程語言提供了一個來考慮哪個異常被拋出以及如何來恢復它的機制。 ·try和catch語句 要處理特殊的異常,將能夠拋出異常的代碼放入try塊中,然后創建相應的 catch塊的列表,每個可以被拋出異常都有一個。如果生成的異常與catch 中提到的相匹配,那么catch條件的塊語句就被執行。在try塊之后,可能 有許多catch塊,每一個都處理不同的異常。 1. try { 2. // code that might throw a particular exception 3. } catch (MyExceptionType e) { 4. // code to execute if a MyExceptionType exception is thrown 5. } catch (Exception e) { 6. // code to execute if a general Exception exception is thrown 7. } 5.2.1·調用棧機制 如果方法中的一個語句拋出一個沒有在相應的try/catch塊中處理的異常, 那么這個異常就被拋出到調用方法中。如果異常也沒有在調用方法中被處理, 它就被拋出到該方法的調用程序。這個過程要一直延續到異常被處理。 如果異常到這時還沒被處理,它便回到main(),而且,即使main()不處理它, 那么,該異常就異常地中斷程序。考慮這樣一種情況,在該情況中main() 方法調用另一個方法(比如,first()),然后它調用另一個 (比如,second())。如果在second()中發生異常,那么必須做一個檢查 來看看該異常是否有一個catch;如果沒有,那么對調用棧(first())中的 下一個方法進行檢查,然后檢查下一個(main())。如果這個異常在該 調用棧上沒有被最后一個方法處理,那么就會發生一個運行時錯誤, 程序終止執行。 5.2.2·finally語句 finally語句定義一個總是執行的代碼塊,而不考慮異常是否被捕獲。 下述樣板代碼來自Frank Yellin弗蘭克葉林的白皮書《Java中的低級安全》: 1. try { 2. startFaucet(); 3. waterLawn(); 4. } 5. finally { 6. stopFaucet(); 7. } 在前面的例子中,即使異常在打開開關或給草地澆水時發生,開關也能被關掉。 try 后面的括號中的代碼被稱做保護碼。如果終止程序的System.exit() 方法在保護碼內被執行,那么,這是finally語句不被執行的唯一情況。 這就暗示,控制流程能偏離正常執行順序,比如,如果一個return語句 被嵌入try塊內的代碼中,那么,finally塊中的代碼應在return前執行。 5.2.3·重訪前例 下面的例子是第169頁main()方法的重寫。本程序以前的版本中產生的 異常被捕獲,數組索引重新設定,使下述程序繼續運行。 1. public static void main (String args[]) { 2. int i = 0; 3. String greetings [] = { 4. "Hello world!", 5. "No, I mean it!", 6. "HELLO WORLD!!" 7. }; 8. while (i < 4) { 9. try { 10. System.out.println (greetings[i]); 11. } catch (ArrayIndexOutOfBoundsException e){ 12. System.out.println( "Re-setting Index Value"); 13. i = -1; 14. } finally { 15. System.out.println("This is always printed"); 16. } 17. i++; 18. } // end while() 19. } // end main() 當循環被執行時,下述在屏幕上出現的信息將改變。 1. Hello world! 2. This is always printed 3. No, I mean it! 4. This is always printed 5. HELLO WORLD!! 6. This is always printed 7. Re-setting Index Value 8. This is always printed 5.3·異常分類 在Java編程語言中,異常有三種分類。Java.lang.Throwable類充當所有 對象的父類,可以使用異常處理機制將這些對象拋出并捕獲。在Throwable 類中定義方法來檢索與異常相關的錯誤信息,并打印顯示異常發生的棧 跟蹤信息。它有Error和Exception兩個基本子類. Throwable類不能使用,而使用子類異常中的一個來描述任何特殊異常。 每個異常的目的描述如下: - Error表示恢復不是不可能但很困難的情況下的一種嚴重問題。比如說 內存溢出。不可能指望程序能處理這樣的情況。 - RuntimeException表示一種設計或實現問題。也就是說,它表示如果 程序運行正常,從不會發生的情況。比如,如果數組索引擴展不超出 數組界限,那么,ArrayIndexOutOfBoundsException異常從不會拋出。 比如,這也適用于取消引用一個空值對象變量。因為一個正確設計和 實現的程序從不出現這種異常,通常對它不做處理。這會導致一個 運行時信息,應確保能采取措施更正問題,而不是將它藏到誰也不 注意的地方。 - 其它異常表示一種運行時的困難,它通常由環境效果引起,可以進行 處理。例子包括文件未找到或無效URL異常(用戶打了一個錯誤的URL), 如果用戶誤打了什么東西,兩者都容易出現。這兩者都可能因為用戶 錯誤而出現,這就鼓勵程序員去處理它們。 5.4·共同異常 Java編程語言提供幾種預定義的異常。下面是可能遇到的更具共同性的 異常中的幾種: - ArithmeticException—整數被0除,運算得出的結果。 - int I =12 / 0; - NullPointerException—當對象沒被實例化時,訪問對象的屬性或 方法的嘗試: - Date d= null; - System.out.println(d.toString()); - NegativeArraySizeException—創建帶負維數大小的數組的嘗試。 - ArrayIndexoutofBoundsException—訪問超過數組大小范圍的一個元 素的嘗試。 - SecurityException—典型地被拋出到瀏覽器中,SecurityManager類將 拋出applets的一個異常,該異常企圖做下述工作(除非明顯地得到允許): - 訪問一個本地文件 - 打開主機的一個socket,這個主機與服務于applet的主機不是同一個。 - 在運行時環境中執行另一個程序 5.5·處理或聲明規則 為了寫出健壯的代碼,Java編程語言要求,當一個方法在棧(即,它已經被 調用)上發生Exception(它與Error或RuntimeException不同)時,那么, 該方法必須決定如果出現問題該采取什么措施。程序員可以做滿足該要求 的兩件事: 第一,通過將Try{}catch(){}塊納入其代碼中,在這里捕獲給被 命名為屬于某個超類的異常,并調用方法處理它。即使catch塊是空的, 這也算是處理情況。 第二,讓被調用的方法表示它將不處理異常,而且該異常將被拋回到它所 遇到的調用方法中。它是按如下所示通過用throws子句標記的該調用方法 的聲明來實現的: public void troublesome() throws IOException 關鍵字throws之后是所有異常的列表,方法可以拋回到它的調用程序中。 盡管這里只顯示了一個異常,如果有成倍的可能的異常可以通過該方法 被拋出,那么,可以使用逗號分開的列表。 是選擇處理還是選擇聲明一個異常取決于是否給你自己或你的調用程序一個 更合適的候選的辦法來處理異常。注—由于異常類象其它類一樣被組編到 層次中,而且由于無論何時想要使用超類都必須使用子類, 因此,可以 捕獲異常“組”并以相同的捕獲代碼來處理它們。例如,盡管 IOExceptions(EOFException,FileNotFoundException等等) 有幾種不同的類型,通過俘獲IOException,也可以捕獲 IOException任何子類的實例。 5.6·創建自己的異常 5.6.1·介紹 用戶定義異常是通過擴展Exception類來創建的。這種異常類可以包含 一個“普通”類所包含的任何東西。下面就是一個用戶定義異常類例子, 它包含一個構造函數、幾個變量以及方法: 1. public class ServerTimedOutException extends Exception { 2. private String reason; 3. private int port; 4. public ServerTimedOutException (String reason,int port){ 5. this.reason = reason; 6. this.port = port; 7. } 8. public String getReason() { 9. return reason; 10. } 11. public int getPort() { 12. return port; 13. } 14. } 使用語句來拋出已經創建的異常: throw new ServerTimedOutException ("Could not connect", 80); 5.6.2·實例 考慮一個客戶服務器程序。在客戶代碼中,要與服務器連接,并希望 服務器在5秒鐘內響應。如果服務器沒有響應,那么,代碼就如下所述 拋出一個異常(如一個用戶定義的ServerTimedOutException)。 1. public void connectMe(String serverName) throws ServerTimedOutException { 2. int success; 3. int portToConnect = 80; 4. success = open(serverName, portToConnect); 5. if (success == -1) { 6. throw new ServerTimedOutException( 7. "Could not connect", 80); 8. } 9. } 要捕獲異常,使用try語句: 1. public void findServer() { 2. . . . 3. try { 4. connectMe(defaultServer); 5. } catch(ServerTimedOutException e) { 6. System.out.println("Server timed out, trying alternate"); 7. try { 8. connectMe(alternateServer); 9. } catch (ServerTimedOutException e1) { 10. System.out.println("No server currently available"); 11. } 12. } 13. .. . 注—try和catch塊可以如前例所述那樣被嵌套。 也可能部分地處理一個異常然后也將它拋出。如: try { ..... ..... } catch (ServerTimedOutException e) { System.out.println("Error caught "); throw e; } |
abstract class和interface是Java語言中對于抽象類定義進行支持的兩種機制,正是由于這兩種機制的存在,才賦予了Java強大的面向對象能力。
接口:沒有提供任何具體實現,可以說是一個極度抽象的類,他允許你創建一個能夠被向上轉型為不止一種基類型的類,以此來實現多重繼承。
抽象類:包含一種或多種抽象方法的類,且可以提供具體的實現。定義抽象類后,其他類可以對他進行擴充并且通過實現其中的抽象方法,使用抽象類具體話。
Java中的接口和抽象類的區別:接口中沒有屬性,而且所有的方法都是抽象的,而抽象類可以有屬性,而且可以有抽象方法,也可以有實現的方法。但兩者都不能被實例話。
使用的時候,一個類可以繼承多個接口,但只能繼承一個抽象類。
一、理解抽象類
abstract class和interface在Java語言中都是用來進行抽象類(本文中的抽象類并非從abstract class翻譯而來,它表示的是一個抽象體,而abstract class為Java語言中用于定義抽象類的一種方法,請讀者注意區分)定義的,那么什么是抽象類,使用抽象類能為我們帶來什么好處呢?
在面向對象的概念中,我們知道所有的對象都是通過類來描繪的,但是反過來卻不是這樣。并不是所有的類都是用來描繪對象的,如果一個類中沒有包含足夠的信息來描繪一個具體的對象,這樣的類就是抽象類。抽象類往往用來表征我們在對問題領域進行分析、設計中得出的抽象概念,是對一系列看上去不同,但是本質上相同的具體概念的抽象。
比如:如果我們進行一個圖形編輯軟件的開發,就會發現問題領域存在著圓、三角形這樣一些具體概念,它們是不同的,但是它們又都屬于形狀這樣一個概念,形狀這個概念在問題領域是不存在的,它就是一個抽象概念。正是因為抽象的概念在問題領域沒有對應的具體概念,所以用以表征抽象概念的抽象類是不能夠實例化的。
在面向對象領域,抽象類主要用來進行類型隱藏。我們可以構造出一個固定的一組行為的抽象描述,但是這組行為卻能夠有任意個可能的具體實現方式。這個抽象描述就是抽象類,而這一組任意個可能的具體實現則表現為所有可能的派生類。模塊可以操作一個抽象體。由于模塊依賴于一個固定的抽象體,因此它可以是不允許修改的;同時,通過從這個抽象體派生,也可擴展此模塊的行為功能。熟悉OCP的讀者一定知道,為了能夠實現面向對象設計的一個最核心的原則OCP(Open-Closed Principle),抽象類是其中的關鍵所在。
二、從語法定義層面看abstract class和interface
在語法層面,Java語言對于abstract class和interface給出了不同的定義方式,下面以定義一個名為Demo的抽象類為例來說明這種不同。使用abstract class的方式定義Demo抽象類的方式如下:
abstract class Demo {
abstract void method1();
abstract void method2();
…
}
使用interface的方式定義Demo抽象類的方式如下:
interface Demo {
void method1();
void method2();
…
}
在abstract class方式中,Demo可以有自己的數據成員,也可以有非abstarct的成員方法,而在interface方式的實現中,Demo只能夠有靜態的不能被修改的數據成員(也就是必須是static final的,不過在interface中一般不定義數據成員),所有的成員方法都是abstract的。從某種意義上說,interface是一種特殊形式的abstract class。
從編程的角度來看,abstract class和interface都可以用來實現"design by contract"的思想。但是在具體的使用上面還是有一些區別的。
首先,abstract class在Java語言中表示的是一種繼承關系,一個類只能使用一次繼承關系。但是,一個類卻可以實現多個interface。也許,這是Java語言的設計者在考慮Java對于多重繼承的支持方面的一種折中考慮吧。
其次,在abstract class的定義中,我們可以賦予方法的默認行為。但是在interface的定義中,方法卻不能擁有默認行為,為了繞過這個限制,必須使用委托,但是這會 增加一些復雜性,有時會造成很大的麻煩。
在抽象類中不能定義默認行為還存在另一個比較嚴重的問題,那就是可能會造成維護上的麻煩。因為如果后來想修改類的界面(一般通過abstract class或者interface來表示)以適應新的情況(比如,添加新的方法或者給已用的方法中添加新的參數)時,就會非常的麻煩,可能要花費很多的時間(對于派生類很多的情況,尤為如此)。但是如果界面是通過abstract class來實現的,那么可能就只需要修改定義在abstract class中的默認行為就可以了。
同樣,如果不能在抽象類中定義默認行為,就會導致同樣的方法實現出現在該抽象類的每一個派生類中,違反了"one rule,one place"原則,造成代碼重復,同樣不利于以后的維護。因此,在abstract class和interface間進行選擇時要非常的小心。
三、從設計理念層面看abstract class和interface
上面主要從語法定義和編程的角度論述了abstract class和interface的區別,這些層面的區別是比較低層次的、非本質的。本文將從另一個層面:abstract class和interface所反映出的設計理念,來分析一下二者的區別。作者認為,從這個層面進行分析才能理解二者概念的本質所在。
前面已經提到過,abstarct class在Java語言中體現了一種繼承關系,要想使得繼承關系合理,父類和派生類之間必須存在"is a"關系,即父類和派生類在概念本質上應該是相同的。對于interface 來說則不然,并不要求interface的實現者和interface定義在概念本質上是一致的,僅僅是實現了interface定義的契約而已。為了使論述便于理解,下面將通過一個簡單的實例進行說明。
考慮這樣一個例子,假設在我們的問題領域中有一個關于Door的抽象概念,該Door具有執行兩個動作open和close,此時我們可以通過abstract class或者interface來定義一個表示該抽象概念的類型,定義方式分別如下所示:
使用abstract class方式定義Door:
abstract class Door {
abstract void open();
abstract void close();
}
使用interface方式定義Door:
interface Door {
void open();
void close();
}
其他具體的Door類型可以extends使用abstract class方式定義的Door或者implements使用interface方式定義的Door。看起來好像使用abstract class和interface沒有大的區別。
如果現在要求Door還要具有報警的功能。我們該如何設計針對該例子的類結構呢(在本例中,主要是為了展示abstract class和interface反映在設計理念上的區別,其他方面無關的問題都做了簡化或者忽略)下面將羅列出可能的解決方案,并從設計理念層面對這些不同的方案進行分析。
解決方案一:
簡單的在Door的定義中增加一個alarm方法,如下:
abstract class Door {
abstract void open();
abstract void close();
abstract void alarm();
}
或者
interface Door {
void open();
void close();
void alarm();
}
那么具有報警功能的AlarmDoor的定義方式如下:
class AlarmDoor extends Door {
void open() { … }
void close() { … }
void alarm() { … }
}
或者
class AlarmDoor implements Door {
void open() { … }
void close() { … }
void alarm() { … }
}
這種方法違反了面向對象設計中的一個核心原則ISP(Interface Segregation Priciple),在Door的定義中把Door概念本身固有的行為方法和另外一個概念"報警器"的行為方法混在了一起。這樣引起的一個問題是那些僅僅依賴于Door這個概念的模塊會因為"報警器"這個概念的改變(比如:修改alarm方法的參數)而改變,反之依然。
解決方案二:
既然open、close和alarm屬于兩個不同的概念,根據ISP原則應該把它們分別定義在代表這兩個概念的抽象類中。定義方式有:這兩個概念都使用abstract class方式定義;兩個概念都使用interface方式定義;一個概念使用abstract class方式定義,另一個概念使用interface方式定義。
顯然,由于Java語言不支持多重繼承,所以兩個概念都使用abstract class方式定義是不可行的。后面兩種方式都是可行的,但是對于它們的選擇卻反映出對于問題領域中的概念本質的理解、對于設計意圖的反映是否正確、合理。我們一一來分析、說明。
如果兩個概念都使用interface方式來定義,那么就反映出兩個問題:
1、我們可能沒有理解清楚問題領域,AlarmDoor在概念本質上到底是Door還是報警器?
2、如果我們對于問題領域的理解沒有問題,比如:我們通過對于問題領域的分析發現AlarmDoor在概念本質上和Door是一致的,那么我們在實現時就沒有能夠正確的揭示我們的設計意圖,因為在這兩個概念的定義上(均使用interface方式定義)反映不出上述含義。
如果我們對于問題領域的理解是:AlarmDoor在概念本質上是Door,同時它有具有報警的功能。我們該如何來設計、實現來明確的反映出我們的意思呢?前面已經說過,abstract class在Java語言中表示一種繼承關系,而繼承關系在本質上是"is a"關系。所以對于Door這個概念,我們應該使用abstarct class方式來定義。另外,AlarmDoor又具有報警功能,說明它又能夠完成報警概念中定義的行為,所以報警概念可以通過interface方式定義。如下所示:
abstract class Door {
abstract void open();
abstract void close();
}
interface Alarm {
void alarm();
}
class AlarmDoor extends Door implements Alarm {
void open() { … }
void close() { … }
void alarm() { … }
}
這種實現方式基本上能夠明確的反映出我們對于問題領域的理解,正確的揭示我們的設計意圖。其實abstract class表示的是"is a"關系,interface表示的是"like a"關系,大家在選擇時可以作為一個依據,當然這是建立在對問題領域的理解上的,比如:如果我們認為AlarmDoor在概念本質上是報警器,同時又具有Door的功能,那么上述的定義方式就要反過來了。
abstract class和interface是Java語言中的兩種定義抽象類的方式,它們之間有很大的相似性。但是對于它們的選擇卻又往往反映出對于問題領域中的概念本質的理解、對于設計意圖的反映是否正確、合理,因為它們表現了概念間的不同的關系(雖然都能夠實現需求的功能)。這其實也是語言的一種的慣用法,希望讀者朋友能夠細細體會