#
最近比較忙,但是每天網上還是的堅持學點,不積小流,無以成江河。
今天學jQuery對象訪問:
1.each(callback) 該方法以每一個匹配的元素作為上下文來執行一個函數,
在每次執行函數時,都會給函數傳遞一個表示作為執行環境的元素在匹配的元素集合中所處位置的數字值作為參數(從0開始的int)
返回‘false’將停止循環(相當于普通循環中使用的‘break’)
返回‘true’將跳至下一個循環,(相當于在普通的循環中使用‘continue’)
參數:callback(function)
e.g1
<img/><img/>
jQuery代碼:
$('img').each(function(){
this.src="test"+i+".jpg";
});
e.g2
<button>Change colors</button>
<span></span>
<div></div>
<div></div>
<div></div>
<div></div>
<div id="stop">Stop here</div>
<div></div>
<div></div>
<div></div>
jQuery代碼:
$('button').click(function(){
$('div').each(function(index,domEle){//domEle ==this
$(domEle).css('backgroundColor',"yellow");
if($(this).is("#stop")){
$("span").text("stopped at div index #"+index);
return false;}
});});
2.size() 和length
都可以勇于得到jQuery對象中元素的個數,
返回: Number
e.g1
<img src="test1.jpg"/><img src="test2.jpg"/>
jQuery代碼:
$("img").size();
e.g2
同理:$("img").length;
3.get()取得所有匹配的DOM元素集合
返回:Array<Element>
e.g1
<img src="test1.jpg"/><img src="test2.jpg"/>
jQuery代碼:
$("img").get().reverse();
result:
[<img src="test1.jpg"/><img src="test2.jpg"/>]
4.get(index)
取得其中一個匹配元素,index表示取得第幾個匹配的元素
返回值:Element
HTML代碼:
<img src="test1.jpg"/><img src="test2.jpg"/>
jQuery代碼:
$("img").get(0);
result:
[<img src="test1.jpg"/>]
5.index(subject)
搜索與參數表示的對象匹配的元素,并返回相應元素的索引值,
如果哦找到了匹配的元素,從0開始返回;如果沒有找到匹配的元素,返回-1
返回值;
Number
參數:
subject(Element)
e.g1返回id值為foobar的元素的索引值
<div id="foobar"><div></div><div id="foo"></div></div>
jQuery代碼:
$("div").index($("#foobar")[0]) //0
$("div").index($('#foo')[0]) // 2
$("div").index($('#foo')) // -1
備注:
今天在瀏覽別人博客的時候看到的,收藏。
有時候,我們頁面當中并不需要把要用到的JS全部加載出來,
這會使頁面加載時速度變慢~~~如果能按需加載,那能提高不少性能...也能節約不少流量~~~給用戶帶來好的體驗~~
好比說,當某個JS效果是觸發事件才顯示的...這個效果被封閉在一個JS中,,我想大家經常這樣做吧~~這時候,我們能按需加載那就不必在頁面載入時去加載JS文件~~~這在jquery插件中很多。
用法:
1 , 當在需要的時候再加載所需的javascript和css文件。
$.include('file/test.js')或$.include('file/test.css')
2, 當然若你一次想加載多個文件你也可以這樣寫:
$.include(['file/test.js','file/test.css'])。
3, 因為這兩個文件的路徑相同,所以可以先指定路徑再加載所有文件:
$.ImportBasePath = 'file/';
$.include(['test.css','test.js']);
4, 你還可以加載完文件后執行回調函數
$.include("file/test.css",function(){
alert("加載css后執行");
});
插件下載地址:http://www.94this.com.cn/myCode/jqueryIncludefile/jqueryIncludefile.rar
注:jquery 自帶了有一個異步請求的方法,$.getScript ,可以異步加到JS并執行
jQuery.getScript(url,[callback])
通過 HTTP GET 請求載入并執行一個 JavaScript 文件。
jQuery 1.2 版本之前,getScript 只能調用同域 JS 文件。 1.2中,您可以跨域調用 JavaScript 文件。注意:Safari 2 或更早的版本不能在全局作用域中同步執行腳本。如果通過 getScript 加入腳本,請加入延時函數。
Loads, and executes, a local JavaScript file using an HTTP GET request.
Before jQuery 1.2, getScript was only able to load scripts from the same domain as the original page. As of 1.2, you can now load JavaScript files from any domain. Warning: Safari 2 and older is unable to evaluate scripts in a global context synchronously. If you load functions via getScript, make sure to call them after a delay.
返回值
XMLHttpRequest
參數
url (String) : 待載入 JS 文件地址。
callback (Function) : (可選) 成功載入后回調函數。
示例
載入 jQuery 官方顏色動畫插件 成功后綁定顏色變化動畫。
HTML 代碼:
<button id="go">» Run</button>
<div class="block"></div>
jQuery 代碼:
jQuery.getScript("http://dev.jquery.com/view/trunk/plugins/color/jquery.color.js",
function(){
$("#go").click(function(){
$(".block").animate( { backgroundColor: 'pink' }, 1000)
.animate( { backgroundColor: 'blue' }, 1000);
});
});
加載并執行 test.js。
jQuery 代碼:
$.getScript("test.js");
加載并執行 test.js ,成功后顯示信息。
jQuery 代碼:
$.getScript("test.js", function(){
alert("Script loaded and executed.");
});
jsp文件上傳大多采用采用開源項目來簡化處理,這里列出常用的兩個jar包的實現,并進行比較,說明他們的優缺點和應該注意的問題。
Commons FileUpload,可以在http://jakarta.apache.org/commons/fileupload/下載,這個包需要Commons IO的支持,可以在http://jakarta.apache.org/commons/io/下載
com.oreilly.servlet,可以在http://www.servlets.com/cos/下載
Commons FileUpload提供三種文件上傳處理方式,DiskFileUpload、ServletFileUpload和PortletFileUpload三種方式,其中DiskFileUpload已經在javadoc下已經被標記為過期的方法,建議用ServletFileUpload代替,而PortletFileUpload需要配合portlet-api來使用,所以這里我們只介紹ServletFileUpload,并且這個也是最常用的。
com.oreilly.servlet也提供了三種文件上傳的處理方式,MultipartWrapper、MultipartRequest和MultipartParser三種方式,其中MultipartWrapper和MultipartRequest的用法基本相同,并且沒有MultipartRequest提供的操作多,所以這里介紹MultipartRequest,MultipartParser和前兩者有些不同,可以用來處理某些特殊情況,例如表單中有兩個同名的文件上傳選擇框。
我們暫時稱三面三種文件上傳方式分別為:ServletFileUpload方式(MultipartTestServlet)、MultipartRequest方式(MultipartTestServlet2)、MultipartParser方式(MultipartTestServlet3)
代碼如下:
test.html
<%@ page language="java" import="java.util.*" contentType="text/html;charset=gbk" pageEncoding="gbk"%>
<html>
<body>
<form action="MultipartTestServlet" enctype="multipart/form-data" method="post">
<input type="text" name="username" /><br />
<input type="file" name="myfile" /><br/>
<input type="file" name="myfile" /><br/>
<input type="submit" />
</form>
<br/><br/><br/><br/>
<form action="MultipartTestServlet2" enctype="multipart/form-data" method="post">
<input type="text" name="username" /><br />
<input type="file" name="myfile" /><br/>
<input type="file" name="myfile" /><br/>
<input type="submit" />
</form>
<br/><br/><br/><br/>
<form action="MultipartTestServlet3" enctype="multipart/form-data" method="post">
<input type="text" name="username" /><br />
<input type="file" name="myfile" /><br/>
<input type="file" name="myfile" /><br/>
<input type="submit" />
</form>
</body>
</html>
MultipartTestServlet.java
package com.bug.servlet;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUpload;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.RequestContext;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.fileupload.servlet.ServletRequestContext;
public class MultipartTestServlet extends HttpServlet {
public MultipartTestServlet() {
super();
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
request.setCharacterEncoding("gbk");
RequestContext requestContext = new ServletRequestContext(request);
if(FileUpload.isMultipartContent(requestContext)){
DiskFileItemFactory factory = new DiskFileItemFactory();
factory.setRepository(new File("c:/tmp/"));
ServletFileUpload upload = new ServletFileUpload(factory);
//upload.setHeaderEncoding("gbk");
upload.setSizeMax(2000000);
List items = new ArrayList();
try {
items = upload.parseRequest(request);
} catch (FileUploadException e1) {
System.out.println("文件上傳發生錯誤" + e1.getMessage());
}
Iterator it = items.iterator();
while(it.hasNext()){
FileItem fileItem = (FileItem) it.next();
if(fileItem.isFormField()){
System.out.println(fileItem.getFieldName() + " " + fileItem.getName() + " " + new String(fileItem.getString().getBytes("iso8859-1"), "gbk"));
}else{
System.out.println(fileItem.getFieldName() + " " +
fileItem.getName() + " " +
fileItem.isInMemory() + " " +
fileItem.getContentType() + " " +
fileItem.getSize());
if(fileItem.getName()!=null && fileItem.getSize()!=0){
File fullFile = new File(fileItem.getName());
File newFile = new File("c:/temp/" + fullFile.getName());
try {
fileItem.write(newFile);
} catch (Exception e) {
e.printStackTrace();
}
}else{
System.out.println("文件沒有選擇 或 文件內容為空");
}
}
}
}
}
}
MultipartTestServlet2.java
package com.bug.servlet;
import java.io.IOException;
import java.util.Enumeration;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.oreilly.servlet.MultipartRequest;
import com.oreilly.servlet.multipart.DefaultFileRenamePolicy;
public class MultipartTestServlet2 extends HttpServlet {
public MultipartTestServlet2() {
super();
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//request.setCharacterEncoding("gbk"); 不起作用
System.out.println("start ");
MultipartRequest multi = new MultipartRequest(request, "c:/tmp/", 2*1024*1024, "gbk", new DefaultFileRenamePolicy());
System.out.println("start ");
Enumeration filesName = multi.getFileNames();
Enumeration paramsName = multi.getParameterNames();
while(paramsName.hasMoreElements()){
String paramName = (String) paramsName.nextElement();
System.out.println(multi.getParameter(paramName));
}
while(filesName.hasMoreElements()){
String fileName = (String) filesName.nextElement();
System.out.println(multi.getFilesystemName(fileName) + " " +
multi.getOriginalFileName(fileName) + " " +
multi.getContentType(fileName) + " ");
if(multi.getFilesystemName(fileName)!=null && !multi.getFilesystemName(fileName).equals(""))
System.out.println(multi.getFile(fileName).toURI());
}
}
}
MultipartTestServlet3.java
package com.bug.servlet;
import java.io.File;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.oreilly.servlet.multipart.FilePart;
import com.oreilly.servlet.multipart.MultipartParser;
import com.oreilly.servlet.multipart.ParamPart;
import com.oreilly.servlet.multipart.Part;
public class MultipartTestServlet3 extends HttpServlet {
public MultipartTestServlet3() {
super();
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
MultipartParser mp = new MultipartParser(request, 2*1024*1024, false, false, "gbk");
Part part;
while ((part = mp.readNextPart()) != null) {
String name = part.getName();
if (part.isParam()) {
ParamPart paramPart = (ParamPart) part;
String value = paramPart.getStringValue();
System.out.println("param: name=" + name + "; value=" + value);
}
else if (part.isFile()) {
// it's a file part
FilePart filePart = (FilePart) part;
String fileName = filePart.getFileName();
if (fileName != null) {
long size = filePart.writeTo(new File("c:/tmp/"));
System.out.println("file: name=" + name + "; fileName=" + fileName +
", filePath=" + filePart.getFilePath() +
", contentType=" + filePart.getContentType() +
", size=" + size);
}
else {
System.out.println("file: name=" + name + "; EMPTY");
}
System.out.flush();
}
}
}
}
web.xml中加入
<servlet>
<servlet-name>MultipartTestServlet</servlet-name>
<servlet-class>com.bug.servlet.MultipartTestServlet</servlet-class>
</servlet>
<servlet>
<servlet-name>MultipartTestServlet2</servlet-name>
<servlet-class>com.bug.servlet.MultipartTestServlet2</servlet-class>
</servlet>
<servlet>
<servlet-name>MultipartTestServlet3</servlet-name>
<servlet-class>com.bug.servlet.MultipartTestServlet3</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>MultipartTestServlet</servlet-name>
<url-pattern>/MultipartTestServlet</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>MultipartTestServlet2</servlet-name>
<url-pattern>/MultipartTestServlet2</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>MultipartTestServlet3</servlet-name>
<url-pattern>/MultipartTestServlet3</url-pattern>
</servlet-mapping>
問題1、中文問題:
三種凡是都可以通過自己的方法來設置encoding為gbk開處理和解決中文問題,包括初始化的時候傳入gbk作為參數,或是是初始化后通過setEncoding的方式來實現。
另外ServletFileUpload方式也可以通過request.setCharacterEncoding("gbk");的方式來實現,而其它兩種方式不支持這種方式。
問題2、文件大小限制
ServletFileUpload方式可以設置文件大小限制,也可以不用設置,例子中的upload.setSizeMax(2000000)就可以注釋掉。如果設置upload.setSizeMax(-1),表明不限制上傳的大小。文檔中沒有指明默認的限制的多少,我在不設置的情況下上傳了一個9M的東西,可以上傳,估計默認是不限制大小的。
而MultipartRequest方式和MultipartParser方式是必須設置文件的上傳文件的大小限制的,如果不設置,默認是1M的大小限制。
問題3、文件上傳發生錯誤
如果文件上傳過程中發生任何錯誤,或者是文件的大小超出了范圍,系統都將拋出錯誤。
ServletFileUpload方式在upload.parseRequest(request)時拋出錯誤
MultipartRequest方式在new MultipartRequest(。。。)時拋出錯誤
MultipartParser方式在new MultipartParser(。。。)時拋出錯誤
問題4、上傳同名文件時,他們保存到臨時目錄是的沖突問題
ServletFileUpload方式,不會有沖突,系統會把上傳得文件按照一定的規則重新命名,保證不會沖突
MultipartParser方式,會產生沖突,系統會把文件按照上傳時的文件名,保存到臨時目錄下,如果兩個用會同時上傳文件名相同的文件,那么就可能會產生沖突,一方把另一方的臨時文件給替換了。
MultipartRequest方式,在初始化時如果提供了一個名稱轉換策略,就不會有沖突,如果不提桶,就會有沖突。在上面的例子中我們提供了一個new DefaultFileRenamePolicy()保證了文件名不會有沖突發生。
問題5:表單中有兩個同名的文件上傳選擇框,就像我們例子中的myfile一樣,每個表單中有兩個name=“myfile”的上傳框
ServletFileUpload方式,可以處理,可以分別得到他們各自的文件,
MultipartRequest方式,不可以處理,會發生沖突,會有一個上傳框的文件覆蓋了另外一個。
MultipartParser方式,可以處理,可以分別得到他們各自的文件,
備注:
代碼比較亂,主要是為了說明他們間的區別。他們的詳細地使用說明還是要參考他的javadoc和domo。
參考:
1、http://www.servlets.com/cos/#classes
2、http://jakarta.apache.org/commons/fileupload/apidocs/index.html
3、http://jakarta.apache.org/commons/fileupload/using.html
4、http://www.onjava.com/pub/a/onjava/2003/06/25/commons.html?page=3
//先鎖表,然后再判斷是否已經存在數據,以防止出現重復行
String lockSql = "update YHZHMX set YHZHMX_DJBH=YHZHMX_DJBH where 1=2";
//上面的語法貌似不好用.故采用下面的語法
lockSql = "SELECT * FROM YHZHMX FOR UPDATE";
一、jquery核心函數的學習
1、
jQuery(exp,[context]),這個函數接受一個包含css選擇器的字符串,然后用這個字符串去匹配一組元素,通俗的講,exp參數是要匹配的表達式,context是匹配的范圍,可以是dom元素,文檔或者jquery對象。
jQuery的核心功能都是通過這個函數實現的,
例子:
a.找到所有p元素,并且這些元素都是div元素的子元素
HTML代碼:<p>guoxzh</p><div><p>guoxiaozheng</p></div><p>guoxzh</p.
jQuery代碼:$("div>p")
b.在文檔的第一個表單中,查找所有的當選按鈕
HTML代碼:是帶有type值為radio的input元素
JQuery代碼:$("input:radio",document.forms[0]);
c.在一個有AJAX返回的xml文檔中,查找所有的div元素
$("div",xml.responseXML);
2.
jQuery(html)根據提供的原始的HTMl標記字符串,動態創建有jQuery對象包含的Dom元素,你可以傳遞一個手寫的 HTML 字符串,或者由某些模板引擎或插件創建的字符串,也可以是通過 AJAX 加載過來的字符串。但是在你創建 input 元素的時會有限制,可以參考第二個示例。當然這個字符串可以包含斜杠 (比如一個圖像地址),還有反斜杠。當你創建單個元素時,請使用閉合標簽或 XHTML 格式。例如,創建一個 span ,可以用 $("<span/>") 或 $("<span></span>") ,但不推薦 $("<span>");
返回值:
JQuery
參數:
用于動態創建dom元素的HTML標簽的字符串,
例子:
a.動態創建一個div元素,追加到body里
jQuery代碼:
$("<div><input type="text" name="name" value=""></div>").appendTo("body");
b.創建一個<input>元素必須同時設定type屬性,
jQuery代碼:
IE中無效
$("<input>").attr("type","checkbox");
在IE中有效
$("<input type='checkbox'>");
3.jQuery(element)將一個或多個元素DOM元素轉化為jQuery對象
這個函數也可以接收XML文檔和Window對象(雖然它們不是DOM元素)作為有效的參數。
返回值:jQuery
例子:
a.設置頁面的背景色
jQuery代碼:
$("document.body").css("background","black");
b.隱藏一個表單中所有元素
jQuery代碼:
$("myForm.elements").hide();
Java棧與堆
----對這兩個概念的理解總是忘記,今天從網上搜到一篇比較好的文章收藏
1. 棧(stack)與堆(heap)都是Java用來在Ram中存放數據的地方。與C++不同,Java自動管理棧和堆,程序員不能直接地設置?;蚨?。
2. 棧的優勢是,存取速度比堆要快,僅次于直接位于CPU中的寄存器。但缺點是,存在棧中的數據大小與生存期必須是確定的,缺乏靈活性。另外,棧數據可以共享,詳見第3點。堆的優勢是可以動態地分配內存大小,生存期也不必事先告訴編譯器,Java的垃圾收集器會自動收走這些不再使用的數據。但缺點是,由于要在運行時動態分配內存,存取速度較慢。
3. Java中的數據類型有兩種。
一種是基本類型(primitive types), 共有8種,即int, short, long, byte, float, double, boolean, char(注意,并沒有string的基本類型)。這種類型的定義是通過諸如int a = 3; long b = 255L;的形式來定義的,稱為自動變量。值得注意的是,自動變量存的是字面值,不是類的實例,即不是類的引用,這里并沒有類的存在。如int a = 3; 這里的a是一個指向int類型的引用,指向3這個字面值。這些字面值的數據,由于大小可知,生存期可知(這些字面值固定定義在某個程序塊里面,程序塊退出后,字段值就消失了),出于追求速度的原因,就存在于棧中。
另外,棧有一個很重要的特殊性,就是存在棧中的數據可以共享。假設我們同時定義:
復制內容到剪貼板代碼:
int a = 3;
int b = 3;
編譯器先處理int a = 3;首先它會在棧中創建一個變量為a的引用,然后查找有沒有字面值為3的地址,沒找到,就開辟一個存放3這個字面值的地址,然后將a指向3的地址。接著處理int b = 3;在創建完b的引用變量后,由于在棧中已經有3這個字面值,便將b直接指向3的地址。這樣,就出現了a與b同時均指向3的情況。
特別注意的是,這種字面值的引用與類對象的引用不同。假定兩個類對象的引用同時指向一個對象,如果一個對象引用變量修改了這個對象的內部狀態,那么另一個對象引用變量也即刻反映出這個變化。相反,通過字面值的引用來修改其值,不會導致另一個指向此字面值的引用的值也跟著改變的情況。如上例,我們定義完a與b的值后,再令a=4;那么,b不會等于4,還是等于3。在編譯器內部,遇到a=4;時,它就會重新搜索棧中是否有4的字面值,如果沒有,重新開辟地址存放4的值;如果已經有了,則直接將a指向這個地址。因此a值的改變不會影響到b的值。
另一種是包裝類數據,如Integer, String, Double等將相應的基本數據類型包裝起來的類。這些類數據全部存在于堆中,Java用new()語句來顯示地告訴編譯器,在運行時才根據需要動態創建,因此比較靈活,但缺點是要占用更多的時間。 4. String是一個特殊的包裝類數據。即可以用String str = new String("abc");的形式來創建,也可以用String str = "abc";的形式來創建(作為對比,在JDK 5.0之前,你從未見過Integer i = 3;的表達式,因為類與字面值是不能通用的,除了String。而在JDK 5.0中,這種表達式是可以的!因為編譯器在后臺進行Integer i = new Integer(3)的轉換)。前者是規范的類的創建過程,即在Java中,一切都是對象,而對象是類的實例,全部通過new()的形式來創建。Java中的有些類,如DateFormat類,可以通過該類的getInstance()方法來返回一個新創建的類,似乎違反了此原則。其實不然。該類運用了單例模式來返回類的實例,只不過這個實例是在該類內部通過new()來創建的,而getInstance()向外部隱藏了此細節。那為什么在String str = "abc";中,并沒有通過new()來創建實例,是不是違反了上述原則?其實沒有。
5. 關于String str = "abc"的內部工作。Java內部將此語句轉化為以下幾個步驟:
(1)先定義一個名為str的對String類的對象引用變量:String str;
(2)在棧中查找有沒有存放值為"abc"的地址,如果沒有,則開辟一個存放字面值為"abc"的地址,接著創建一個新的String類的對象o,并將o的字符串值指向這個地址,而且在棧中這個地址旁邊記下這個引用的對象o。如果已經有了值為"abc"的地址,則查找對象o,并返回o的地址。
(3)將str指向對象o的地址。
值得注意的是,一般String類中字符串值都是直接存值的。但像String str = "abc";這種場合下,其字符串值卻是保存了一個指向存在棧中數據的引用!
為了更好地說明這個問題,我們可以通過以下的幾個代碼進行驗證。
復制內容到剪貼板代碼:
String str1 = "abc";
String str2 = "abc";
System.out.println(str1==str2); //true
注意,我們這里并不用str1.equals(str2);的方式,因為這將比較兩個字符串的值是否相等。==號,根據JDK的說明,只有在兩個引用都指向了同一個對象時才返回真值。而我們在這里要看的是,str1與str2是否都指向了同一個對象。
結果說明,JVM創建了兩個引用str1和str2,但只創建了一個對象,而且兩個引用都指向了這個對象。
我們再來更進一步,將以上代碼改成:
復制內容到剪貼板代碼:
String str1 = "abc";
String str2 = "abc";
str1 = "bcd";
System.out.println(str1 + "," + str2); //bcd, abc
System.out.println(str1==str2); //false
這就是說,賦值的變化導致了類對象引用的變化,str1指向了另外一個新對象!而str2仍舊指向原來的對象。上例中,當我們將str1的值改為"bcd"時,JVM發現在棧中沒有存放該值的地址,便開辟了這個地址,并創建了一個新的對象,其字符串的值指向這個地址。
事實上,String類被設計成為不可改變(immutable)的類。如果你要改變其值,可以,但JVM在運行時根據新值悄悄創建了一個新對象,然后將這個對象的地址返回給原來類的引用。這個創建過程雖說是完全自動進行的,但它畢竟占用了更多的時間。在對時間要求比較敏感的環境中,會帶有一定的不良影響。
再修改原來代碼:
復制內容到剪貼板代碼:
String str1 = "abc";
String str2 = "abc";
str1 = "bcd";
String str3 = str1;
System.out.println(str3); //bcd
String str4 = "bcd";
System.out.println(str1 == str4); //true
str3這個對象的引用直接指向str1所指向的對象(注意,str3并沒有創建新對象)。當str1改完其值后,再創建一個String的引用str4,并指向因str1修改值而創建的新的對象??梢园l現,這回str4也沒有創建新的對象,從而再次實現棧中數據的共享。
我們再接著看以下的代碼。
復制內容到剪貼板代碼:
String str1 = new String("abc");
String str2 = "abc";
System.out.println(str1==str2); //false 創建了兩個引用。創建了兩個對象。兩個引用分別指向不同的兩個對象。
String str1 = "abc";
String str2 = new String("abc");
System.out.println(str1==str2); //false
創建了兩個引用。創建了兩個對象。兩個引用分別指向不同的兩個對象。
以上兩段代碼說明,只要是用new()來新建對象的,都會在堆中創建,而且其字符串是單獨存值的,即使與棧中的數據相同,也不會與棧中的數據共享。
6. 數據類型包裝類的值不可修改。不僅僅是String類的值不可修改,所有的數據類型包裝類都不能更改其內部的值。
7. 結論與建議:
(1)我們在使用諸如String str = "abc";的格式定義類時,總是想當然地認為,我們創建了String類的對象str。擔心陷阱!對象可能并沒有被創建!唯一可以肯定的是,指向String類的引用被創建了。至于這個引用到底是否指向了一個新的對象,必須根據上下文來考慮,除非你通過new()方法來顯要地創建一個新的對象。因此,更為準確的說法是,我們創建了一個指向String類的對象的引用變量str,這個對象引用變量指向了某個值為"abc"的String類。清醒地認識到這一點對排除程序中難以發現的bug是很有幫助的。
(2)使用String str = "abc";的方式,可以在一定程度上提高程序的運行速度,因為JVM會自動根據棧中數據的實際情況來決定是否有必要創建新對象。而對于String str = new String("abc");的代碼,則一概在堆中創建新對象,而不管其字符串值是否相等,是否有必要創建新對象,從而加重了程序的負擔。這個思想應該是享元模式的思想,但JDK的內部在這里實現是否應用了這個模式,不得而知。
(3)當比較包裝類里面的數值是否相等時,用equals()方法;當測試兩個包裝類的引用是否指向同一個對象時,用==。
(4)由于String類的immutable性質,當String變量需要經常變換其值時,應該考慮使用StringBuffer類,以提高程序效率。
摘要: 壓縮的
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import...
閱讀全文
現在關鍵是如何讀取XML配置文件?有好幾種XML解析器:主要有DOM和SAX ,這些區別網上文章介紹很多。
在apache的XML項目組中,目前有Xerces Xalan Cocoon幾個開發XML相關技術的project.Tomcat本身使用的是 Sun 的 JAXP,而其XSL Taglib project中使用Xerces解析器。
好了,上面都是比較煩人的理論問題,還是趕快切入XML的配置文件的讀取吧。
在我們的程序中,通常要有一些根據主機環境確定的變量。比如數據庫訪問用戶名和密碼,不同的主機可能設置不一樣。只要更改XML配置文件,就可以正常運行。
localhost
sqlname
username
password
上面這個myenv.xml配置文件一般是放在tomcat的WEB-INF/classes目錄下.
我們編制一個Java程序直接讀取,將dbhost dbuser dbpassword提取出來供其他程序訪問數據庫用.
目前使用SAX比較的多,與DOM主要區別是 SAX是一行一行讀取XML文件進行分析,適合比較大文件,DOM是一次性讀入內存,顯然不能對付大文件.這里我們使用SAX解析,由于SAX解析器不斷在發展,網上有不少文章是針對老版本的.如果你使用JDK1.4 ,可以參考 使用SAX處理XML文檔 一文.這里的程序是根據其改進并且經過實踐調試得來的.
對上面myenv.xml讀取的Java程序:
import org.xml.sax.Attributes;
import org.xml.sax.helpers.DefaultHandler;
import org.xml.sax.SAXException;
import java.util.Properties;
//使用DefaultHandler的好處 是 不必陳列出所有方法,
public class ConfigParser extends DefaultHandler {
////定義一個Properties 用來存放 dbhost dbuser dbpassword的值
private Properties props;
private String currentSet;
private String currentName;
private StringBuffer currentValue = new StringBuffer();
//構建器初始化props
public ConfigParser() {
this.props = new Properties();
}
public Properties getProps() {
return this.props;
}
//定義開始解析元素的方法. 這里是將 中的名稱xxx提取出來.
public void startElement(String uri, String localName, String qName, Attributes attributes)
throws SAXException {
currentValue.delete(0, currentValue.length());
this.currentName =qName;
}
//這里是將 之間的值加入到currentValue
public void characters(char[] ch, int start, int length) throws SAXException {
currentValue.append(ch, start, length);
}
//在遇到 結束后,將之前的名稱和值一一對應保存在props中
public void endElement(String uri, String localName, String qName) throws SAXException {
props.put(qName.toLowerCase(), currentValue.toString().trim());
}
}
上面的這個解析程序比較簡單吧? 其實解析XML就是這么簡單.
現在我們已經將dbhost dbuser dbpassword的值localhost sqlname username password提取了出來.但是這只是在在解析器內部,我們的程序還不能訪問.需要再編制一個程序.
import java.util.Properties;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import java.net.URL;
public class ParseXML{
//定義一個Properties 用來存放 dbhost dbuser dbpassword的值
private Properties props;
//這里的props
public Properties getProps() {
return this.props;
}
public void parse(String filename) throws Exception {
//將我們的解析器對象化
ConfigParser handler = new ConfigParser();
//獲取SAX工廠對象
SAXParserFactory factory = SAXParserFactory.newInstance();
factory.setNamespaceAware(false);
factory.setValidating(false);
//獲取SAX解析
SAXParser parser = factory.newSAXParser();
//得到配置文件myenv.xml所在目錄. tomcat中是在WEB-INF/classes
//下例中BeansConstants是用來存放xml文件中配置信息的類,可以自己代替或定義
URL confURL = BeansConstants.class.getClassLoader().getResource(filename);
try
{
//將解析器和解析對象myenv.xml聯系起來,開始解析
parser.parse(confURL.toString(), handler);
//獲取解析成功后的屬性 以后 我們其他應用程序只要調用本程序的props就可以提取出屬性名稱和值了
props = handler.getProps();
}finally{
factory=null;
parser=null;
handler=null;
}
}
}
由于我們的XML文件是使用最簡單的形式 ,因此解析器相對簡單,但是這已經足夠對付我們的配置文件了.
判斷一個程序系統的先進性,我們先看看他的配置文件,如果還在使用老套的xxx=123 這樣類似.ini的文件,
Web應用程序在瀏覽器中顯示字符串時,由于顯示長度的限制,常常需要將字符串截取后再進行顯示。但目前很多流行的語言,如
C#、
Java內部采用的都是 Unicode 16(UCS2)編碼,在這種編碼中所有的字符都是兩個字符,因此,如果要截取的字符串是中、英文、數字混合的,就會產生問題,如下面的字符串:
String s = "a加b等于c,如果a等1、b等于2,那么c等3";
上面的字符串既有漢字,又有英文字符和數字。如果要截取前6個字節的字符,應該是”a加b等",但如果用substring方法截取前6個字符就成了"a 加b等于c"。產生這個問題的原因是將substring方法將雙字節的漢字當成一個字節的字符(UCS2字符)處理了。要解決這個問題的方法是首先得到該字符串的UCS2編碼的字節數組,如下面的代碼如下:
byte[] bytes = s.getBytes("Unicode");
由于上面生成的字節數組中前兩個字節是標志位,bytes[0] = -2,bytes[1] = -1,因此,要從第三個字節開始掃描,對于一個英文或數字字符,UCS2編碼的第二個字節是相應的ASCII,第一個字節是0,如a的UCS2編碼是0 97,而漢字兩個字節都不為0,因此,可以利于UCS2編碼的這個規則來計算實際的字節數,該方法的實現代碼如下:
public static String bSubstring(String s, int length) throws Exception
{
byte[] bytes = s.getBytes("Unicode");
int n = 0; // 表示當前的字節數
int i = 2; // 要截取的字節數,從第3個字節開始
for (; i < bytes.length && n < length; i++)
{
// 奇數位置,如3、5、7等,為UCS2編碼中兩個字節的第二個字節
if (i % 2 == 1)
{
n++; // 在UCS2第二個字節時n加1
}
else
{
// 當UCS2編碼的第一個字節不等于0時,該UCS2字符為漢字,一個漢字算兩個字節
if (bytes[i] != 0)
{
n++;
}
}
}
// 如果i為奇數時,處理成偶數
if (i % 2 == 1)
{
// 該UCS2字符是漢字時,去掉這個截一半的漢字
if (bytes[i - 1] != 0)
i = i - 1;
// 該UCS2字符是字母或數字,則保留該字符
else
i = i + 1;
}
return new String(bytes, 0, i, "Unicode");
}
下面代碼使用了bSubstring方法:
String s = "a加b等于c,如果a等1、b等于2,那么c等3";
System.out.println(bSubstring(s, 6));
上面的代碼截取的字符串是
"a加b等
"。