2008年11月30日
#
public class QuenDemo {
public static void main(String[] args){
//public class Queue extends Collection
Queue<Integer> queue=new LinkedList<Integer>();
Random rand = new Random(47);
for(int i=0;i<10;i++){
queue.offer(rand.nextInt(i+10));
}
System.out.println("1111"+queue.toString());
printQ(queue);
//public class LinkedList extends AbstractSequentialList implements List,Queue,Cloneable,Serializable
Queue<Character> qc=new LinkedList<Character>();
for(char c:"guoxzh".toCharArray()){
qc.offer(c);
System.out.println("qc=="+qc.toString());
}
printQ(qc);
}
public static void printQ(Queue queue){
while(queue.peek()!=null){
//peek和element都是在不移除的情況下返回對(duì)頭,但是peek在隊(duì)列為空的情況下返回null,element方法會(huì)拋出NoSuchElementException異常
System.out.println(queue.remove());
//remove和poll方法都是在移除并返回對(duì)頭,但是poll在為空時(shí)返回null,而remove會(huì)拋出NoSucheElementException異常
System.out.println("2222"+queue.toString());
}
}
}
package src;
import java.io.UnsupportedEncodingException;
public class ChangeCharset {
/** 7位ASCII字符,也叫作ISO646-US、Unicode字符集的基本拉丁塊 */
public static final String US_ASCII = "US-ASCII";
/** ISO 拉丁字母表 No.1,也叫作 ISO-LATIN-1 */
public static final String ISO_8859_1 = "ISO-8859-1";
/** 8 位 UCS 轉(zhuǎn)換格式 */
public static final String UTF_8 = "UTF-8";
/** 16 位 UCS 轉(zhuǎn)換格式,Big Endian(最低地址存放高位字節(jié))字節(jié)順序 */
public static final String UTF_16BE = "UTF-16BE";
/** 16 位 UCS 轉(zhuǎn)換格式,Little-endian(最高地址存放低位字節(jié))字節(jié)順序 */
public static final String UTF_16LE = "UTF-16LE";
/** 16 位 UCS 轉(zhuǎn)換格式,字節(jié)順序由可選的字節(jié)順序標(biāo)記來標(biāo)識(shí) */
public static final String UTF_16 = "UTF-16";
/** 中文超大字符集 */
public static final String GBK = "GBK";
/**
* 將字符編碼轉(zhuǎn)換成US-ASCII碼
*/
public String toASCII(String str) throws UnsupportedEncodingException{
return this.changeCharset(str, US_ASCII);
}
/**
* 將字符編碼轉(zhuǎn)換成ISO-8859-1碼
*/
public String toISO_8859_1(String str) throws UnsupportedEncodingException{
return this.changeCharset(str, ISO_8859_1);
}
/**
* 將字符編碼轉(zhuǎn)換成UTF-8碼
*/
public String toUTF_8(String str) throws UnsupportedEncodingException{
return this.changeCharset(str, UTF_8);
}
/**
* 將字符編碼轉(zhuǎn)換成UTF-16BE碼
*/
public String toUTF_16BE(String str) throws UnsupportedEncodingException{
return this.changeCharset(str, UTF_16BE);
}
/**
* 將字符編碼轉(zhuǎn)換成UTF-16LE碼
*/
public String toUTF_16LE(String str) throws UnsupportedEncodingException{
return this.changeCharset(str, UTF_16LE);
}
/**
* 將字符編碼轉(zhuǎn)換成UTF-16碼
*/
public String toUTF_16(String str) throws UnsupportedEncodingException{
return this.changeCharset(str, UTF_16);
}
/**
* 將字符編碼轉(zhuǎn)換成GBK碼
*/
public String toGBK(String str) throws UnsupportedEncodingException{
return this.changeCharset(str, GBK);
}
/**
* 字符串編碼轉(zhuǎn)換的實(shí)現(xiàn)方法
* @param str 待轉(zhuǎn)換編碼的字符串
* @param newCharset 目標(biāo)編碼
* @return
* @throws UnsupportedEncodingException
*/
public String changeCharset(String str, String newCharset)
throws UnsupportedEncodingException {
if (str != null) {
//用默認(rèn)字符編碼解碼字符串。
byte[] bs = str.getBytes();
//用新的字符編碼生成字符串
return new String(bs, newCharset);
}
return null;
}
/**
* 字符串編碼轉(zhuǎn)換的實(shí)現(xiàn)方法
* @param str 待轉(zhuǎn)換編碼的字符串
* @param oldCharset 原編碼
* @param newCharset 目標(biāo)編碼
* @return
* @throws UnsupportedEncodingException
*/
public String changeCharset(String str, String oldCharset, String newCharset)
throws UnsupportedEncodingException {
if (str != null) {
//用舊的字符編碼解碼字符串。解碼可能會(huì)出現(xiàn)異常。
byte[] bs = str.getBytes(oldCharset);
//用新的字符編碼生成字符串
return new String(bs, newCharset);
}
return null;
}
public static void main(String[] args) throws UnsupportedEncodingException {
ChangeCharset test = new ChangeCharset();
String str = "This is a 中文的 String!";
System.out.println("str: " + str);
String gbk = test.toGBK(str);
System.out.println("轉(zhuǎn)換成GBK碼: " + gbk);
System.out.println();
String ascii = test.toASCII(str);
System.out.println("轉(zhuǎn)換成US-ASCII碼: " + ascii);
gbk = test.changeCharset(ascii,ChangeCharset.US_ASCII, ChangeCharset.GBK);
System.out.println("再把ASCII碼的字符串轉(zhuǎn)換成GBK碼: " + gbk);
System.out.println();
String iso88591 = test.toISO_8859_1(str);
System.out.println("轉(zhuǎn)換成ISO-8859-1碼: " + iso88591);
gbk = test.changeCharset(iso88591,ChangeCharset.ISO_8859_1, ChangeCharset.GBK);
System.out.println("再把ISO-8859-1碼的字符串轉(zhuǎn)換成GBK碼: " + gbk);
System.out.println();
String utf8 = test.toUTF_8(str);
System.out.println("轉(zhuǎn)換成UTF-8碼: " + utf8);
gbk = test.changeCharset(utf8,ChangeCharset.UTF_8, ChangeCharset.GBK);
System.out.println("再把UTF-8碼的字符串轉(zhuǎn)換成GBK碼: " + gbk);
System.out.println();
String utf16be = test.toUTF_16BE(str);
System.out.println("轉(zhuǎn)換成UTF-16BE碼:" + utf16be);
gbk = test.changeCharset(utf16be,ChangeCharset.UTF_16BE, ChangeCharset.GBK);
System.out.println("再把UTF-16BE碼的字符串轉(zhuǎn)換成GBK碼: " + gbk);
}
}
JAVA里面關(guān)于byte數(shù)組和String之間的轉(zhuǎn)換問題
把byte轉(zhuǎn)化成string,必須經(jīng)過編碼。
例如下面一個(gè)例子:
import java.io.UnsupportedEncodingException;
public class test{
public static void main(String g[]) {
String s = "12345abcd";
byte b[] = s.getBytes();
String t = b.toString();
System.out.println(t);
}
}
輸出字符串的結(jié)果和字符串s不一樣了.
經(jīng)過以下方式轉(zhuǎn)碼就可以正確轉(zhuǎn)換了:
public class test{
public static void main(String g[]) {
String s = "12345abcd";
byte b[] = s.getBytes();
try {
String t = new String(b);
System.out.print(t);
} catch (Exception e) {
e.printStackTrace();
}
}
}
引用:
String str = "String";
byte[] byte1 = str.getBytes();
String str1 = new String(byte1);
byte[] byte2 = str1.getBytes();
String str2 = new String(byte2);
System.out.println("str<<<" + str);
System.out.println("byte1<<<" + byte1);
System.out.println("str1<<<" + str1);
System.out.println("byte2<<<" + byte2);
System.out.println("str2<<<" + str2);
-------------------------------------
輸出結(jié)果
str<<<String
byte1<<<[B@192d342
str1<<<String
byte2<<<[B@6b97fd
str2<<<String
想請(qǐng)教為什么兩個(gè)byte輸出的不一樣呢?
String str = "String";
byte[] byte1 = str.getBytes();
String str1 = new String(byte1);
byte[] byte2 = str1.getBytes();
----------
注意byte1是str得到的byte數(shù)組,而byte2是另一個(gè)字符串str1得到的數(shù)組
他們本身也是兩個(gè)對(duì)象
直接打印實(shí)際上調(diào)用的是toString()方法,而toString()的默認(rèn)實(shí)現(xiàn)是打印對(duì)象類型+hashCode()
[B表示byte數(shù)組 @表示之后的是地址 后面跟著的是hashCode,其實(shí)就是其虛擬機(jī)地址
從大的方面來講,JVM的內(nèi)存模型分為兩大塊:
永久區(qū)內(nèi)存( Permanent space)和堆內(nèi)存(heap space)。
棧內(nèi)存(stack space)一般都不歸在JVM內(nèi)存模型中,因?yàn)闂?nèi)存屬于線程級(jí)別。
每個(gè)線程都有個(gè)獨(dú)立的棧內(nèi)存空間。
Permanent space里存放加載的Class類級(jí)對(duì)象如class本身,method,field等等。
heap space主要存放對(duì)象實(shí)例和數(shù)組。
heap space由Old Generation和NewGeneration組成,OldGeneration存放生命周期長(zhǎng)久的實(shí)例對(duì)象,而新的對(duì)象實(shí)例一般放在NewGeneration。
New Generation還可以再分為Eden區(qū)(圣經(jīng)中的伊甸園)、和Survivor區(qū),新的對(duì)象實(shí)例總是首先放在Eden區(qū),Survivor區(qū)作為Eden區(qū)和Old區(qū)的緩沖,可以向Old區(qū)轉(zhuǎn)移活動(dòng)的對(duì)象實(shí)例。
一般,我們常見的OOM(out of memory)內(nèi)存溢出異常,就是堆內(nèi)存空間不足以存放新對(duì)象實(shí)例時(shí)導(dǎo)致。
永久區(qū)內(nèi)存溢出相對(duì)少見,一般是由于需要加載海量的Class數(shù)據(jù),超過了非堆內(nèi)存的容量導(dǎo)致。通常出現(xiàn)在Web應(yīng)用剛剛啟動(dòng)時(shí),因此Web應(yīng)用推薦使用預(yù)加載機(jī)制,方便在部署時(shí)就發(fā)現(xiàn)并解決該問題。
棧內(nèi)存也會(huì)溢出,但是更加少見。
堆內(nèi)存優(yōu)化:
調(diào)整JVM啟動(dòng)參數(shù)-Xms -Xmx -XX:newSize -XX:MaxNewSize,如調(diào)整初始堆內(nèi)存和最大對(duì)內(nèi)存 -Xms256M -Xmx512M。 或者調(diào)整初始New Generation的初始內(nèi)存和最大內(nèi)存-XX:newSize=128M -XX:MaxNewSize=128M。
永久區(qū)內(nèi)存優(yōu)化:
調(diào)整PermSize參數(shù) 如 -XX:PermSize=256M-XX:MaxPermSize=512M。
棧內(nèi)存優(yōu)化:
調(diào)整每個(gè)線程的棧內(nèi)存容量 如 -Xss2048K
最終,一個(gè)運(yùn)行中的JVM所占的內(nèi)存= 堆內(nèi)存 + 永久區(qū)內(nèi)存 + 所有線程所占的棧內(nèi)存總和 。
財(cái)務(wù)公司的背景:
財(cái)務(wù)公司有兩種模式:
1.美國(guó)模式財(cái)務(wù)公司是以搞活商品流通、促進(jìn)商品銷售為特色的非銀行金融機(jī)構(gòu),它依附于制造商,是一些大型耐用品而設(shè)立的受控子公司,這類財(cái)務(wù)公司主要是為零售商提供融資服務(wù)的,主要分布在美國(guó)、加拿大和德國(guó)。
2.英國(guó)模式財(cái)務(wù)公司基本上依附于商業(yè)銀行,其組建的目的在于規(guī)避政府對(duì)商業(yè)銀行的監(jiān)管,因?yàn)檎?guī)定,商業(yè)銀行不得從事證券投資業(yè)務(wù),而財(cái)務(wù)公司不屬于銀行,所以不受此限制,這種模式主要分布在英國(guó)、日本和中國(guó)香港。
中國(guó)財(cái)務(wù)公司概況
財(cái)務(wù)公司又稱金融公司,是為了企業(yè)技術(shù)改造,新產(chǎn)品開發(fā)及產(chǎn)品銷售提供金融服務(wù)的,以中長(zhǎng)期金融業(yè)務(wù)為主的非銀行機(jī)構(gòu),各國(guó)的名稱不同,業(yè)務(wù)內(nèi)容也不一樣。
財(cái)務(wù)公司是中國(guó)企業(yè)體制改革和融資體制改革的產(chǎn)物,國(guó)家為了增強(qiáng)國(guó)有大中型企業(yè)的活力,盤活企業(yè)內(nèi)部資金,增強(qiáng)企業(yè)集團(tuán)的融資能力,支持企業(yè)集團(tuán)的發(fā)展,促進(jìn)產(chǎn)業(yè)結(jié)構(gòu)和產(chǎn)品結(jié)果的調(diào)整,以及探索具有中國(guó)特色的產(chǎn)品資本與金融資本相結(jié)合的道路,于1987年成立了中國(guó)第一家企業(yè)集團(tuán)財(cái)務(wù)公司,即東風(fēng)汽車工業(yè)集團(tuán)財(cái)務(wù)公司。
財(cái)務(wù)公司---公司主體
財(cái)務(wù)公司是根據(jù)《公司法》和《企業(yè)集團(tuán)財(cái)務(wù)公司管理辦法》設(shè)立的,為企業(yè)集團(tuán)成員單位技術(shù)改造、新產(chǎn)品開發(fā)及產(chǎn)品銷售提供金融服務(wù),以中長(zhǎng)期金融業(yè)務(wù)為主的非銀行機(jī)構(gòu)。
財(cái)務(wù)公司一般分企業(yè)附屬財(cái)務(wù)公司和非企業(yè)附屬財(cái)務(wù)公司,企業(yè)附屬財(cái)務(wù)公司由企業(yè)設(shè)立,為本企業(yè)服務(wù),但是服務(wù)范圍不僅局限于本企業(yè);非企業(yè)附屬財(cái)務(wù)公司包括銀行附屬財(cái)務(wù)公司、引起合資財(cái)務(wù)公司和獨(dú)立財(cái)務(wù)公司。
1.銀行附屬財(cái)務(wù)公司是由銀行控股,因規(guī)避監(jiān)管、實(shí)現(xiàn)金融創(chuàng)新和彌補(bǔ)銀行的不足而設(shè)立的,同時(shí)也為企業(yè)和個(gè)人提供金融服務(wù)。
2.銀行合資財(cái)務(wù)公司是銀行和企業(yè)出于金融創(chuàng)新規(guī)避監(jiān)管或促進(jìn)產(chǎn)融合作的考慮而設(shè)立,為企業(yè)和個(gè)人提供金融服務(wù),
3.獨(dú)立財(cái)務(wù)公司一般是沒有母公司的財(cái)務(wù)公司,規(guī)模較小,比較靈活,在某一方面提供融資服務(wù)。
財(cái)務(wù)公司的業(yè)務(wù)范圍
1.經(jīng)中國(guó)人民銀行批準(zhǔn),中國(guó)財(cái)務(wù)公司可從事下列部分或全部業(yè)務(wù):
2.吸收成員單位3個(gè)月以上定期存款。
3.發(fā)行財(cái)務(wù)公司債券。
4.同業(yè)拆借。
5.對(duì)成員單位辦理貸款及融資租賃。
6.辦理集團(tuán)成員單位產(chǎn)品的消費(fèi)信貸、買方信貸及融資租賃。
7.辦理成員單位商業(yè)匯票的承兌及貼現(xiàn)。
8.辦理成員單位的委托貸款及委托投資。
9.有價(jià)證券、金融機(jī)構(gòu)股權(quán)及成員單位股權(quán)投資。
10.承銷成員單位的企業(yè)債券。
11.對(duì)成員單位辦理財(cái)務(wù)顧問、信用鑒證及其他咨詢代理業(yè)務(wù)。
12.對(duì)成員單位提供擔(dān)保。
13.境外外匯借款。
14.經(jīng)中國(guó)人民銀行批準(zhǔn)的其他業(yè)務(wù)。
財(cái)務(wù)公司的主要作用
1.業(yè)務(wù)范圍比較廣,但是以企業(yè)集團(tuán)為限。
主要業(yè)務(wù)有存款、貸款、結(jié)算、擔(dān)保和代理等一般銀行業(yè)務(wù),還可以經(jīng)人民銀行批準(zhǔn),開展證券、信托投資等業(yè)務(wù)。
2.資金來源于集團(tuán)公司,用于集團(tuán)公司,對(duì)集團(tuán)公司的依附性強(qiáng),
財(cái)務(wù)公司的資金主要來源于兩個(gè)方面:a、集團(tuán)公司和集團(tuán)成員公司投入的資本金;b、集團(tuán)公司成員企業(yè)在財(cái)務(wù)公司的存款。
3.接受企業(yè)集團(tuán)和人民銀行的雙重監(jiān)管。
財(cái)務(wù)公司是企業(yè)內(nèi)部的金融機(jī)構(gòu),期股東大都是集團(tuán)公司成員企業(yè),因而其景榮活動(dòng)必然受到集團(tuán)公司的監(jiān)督,同時(shí),財(cái)務(wù)公司所從事的是金融業(yè)務(wù),其金融活動(dòng)必須接受人民銀行監(jiān)管
4.堅(jiān)持服務(wù)與效益相結(jié)合、服務(wù)優(yōu)先的經(jīng)營(yíng)原則。雖然財(cái)務(wù)公司作為獨(dú)立的法人,但是是企業(yè)集團(tuán)內(nèi)部的機(jī)構(gòu),且集團(tuán)公司成員企業(yè)大都是財(cái)務(wù)公司的股東,所以財(cái)務(wù)公司在經(jīng)營(yíng)中一般都應(yīng)較好地處理服務(wù)與效益的關(guān)系,在堅(jiān)持為集團(tuán)公司成員企業(yè)提供良好金融服務(wù)的前提下,努力實(shí)現(xiàn)利潤(rùn)的最大化,
財(cái)務(wù)公司的作用
1.在資金管理方面和使用上,促使企業(yè)從粗放型向集約型轉(zhuǎn)變,
沒有財(cái)務(wù)公司之前,集團(tuán)公司成員企業(yè)不能直接發(fā)生信貸關(guān)系,有些單位資金閑置,有些單位資金緊張,財(cái)務(wù)公司成立以后,成員單位成為財(cái)務(wù)公司的股東,在一定程度上集中了各成員單位的資本來進(jìn)行一體化經(jīng)營(yíng),財(cái)務(wù)公司應(yīng)用金融手段將集團(tuán)公司內(nèi)企業(yè)的閑散資金集中起來,統(tǒng)籌安排使用,這樣不僅可以加快集團(tuán)成員企業(yè)間資金結(jié)算的速度,而且總整體上降低了集團(tuán)財(cái)務(wù)費(fèi)用,提高就然公司資金的使用效率,加速集團(tuán)公司資產(chǎn)一體化經(jīng)營(yíng)的進(jìn)程,
2.財(cái)務(wù)公司以資金為紐帶,以服務(wù)為手段,增強(qiáng)了集團(tuán)公司的凝聚力。
股本金將成員單位聯(lián)接在一起,另一方面財(cái)務(wù)公司吸納的資金又成為集團(tuán)公司企業(yè)信貸資金的一個(gè)來源,從而集團(tuán)公司成員企業(yè)進(jìn)一步緊密的聯(lián)結(jié)在一起,形成了一種相互支持,相互促進(jìn),共同發(fā)展的局面。
3.及時(shí)解決了企業(yè)集團(tuán)急需的資金,保證企業(yè)生產(chǎn)經(jīng)營(yíng)的正常進(jìn)行。
4.增強(qiáng)了企業(yè)集團(tuán)的融資功能,促進(jìn)了集團(tuán)公司的發(fā)展壯大,
5.有利于打破現(xiàn)有銀行體制資金規(guī)模按行政區(qū)域分割的局面,促進(jìn)大集團(tuán)公司跨地域、跨行業(yè)發(fā)展,
6.促進(jìn)了金融業(yè)的競(jìng)爭(zhēng),有利于金融機(jī)構(gòu)提高服務(wù)質(zhì)量和效益,有利于金融體制改革的深化。
1、“我請(qǐng)客”:覺得我們常用pay這個(gè)詞,如Let me pay it for you。這里列舉三種說法:I am buying;This is on me;This is all my bill。
2、“收買某人”:有個(gè)比較正式的詞叫bribe,名詞時(shí)為“賄賂”的意思,動(dòng)詞時(shí)就有“收買”之意。既然提到了“買”,那么我們能不能用上buy呢?當(dāng)然,那就是buy sb off。
3、“向前看!”:我們會(huì)說Look forward!而美語里有個(gè)更貼切的說法是Eyes front!“眼睛朝前”,是不是很生動(dòng)?
4、“頭等大事”:你會(huì)怎么翻譯呢?The most important thing嗎?看這個(gè)吧“It's on the top of my list”。
5、“看在主的份上,你就……”:兩種說法,其一是For the love of God,另外For God's sake(sake的意思是緣故、關(guān)系)二者之中,后者更常用
6、“我不是傻子!”:I am not a fool?對(duì),語法完全正確。但再看這個(gè)I am no fool。比上面的只少兩個(gè)字母,但是不是感覺不一樣?同樣的道理,我們常說I have no idea,而不常說I dont have any idea。
7、short hairs:是說“短頭發(fā)”嗎?呵呵,它就是我們說的“小辮子”!
8、one-time thing:帥哥跟一美女過了一夜,回來后室友問帥哥:Do you really love her?帥哥回答:Oh, it was just a one-time thing!那么one-time thing是什么呢?我就不羅嗦嘍!
9、She knew red was her color。“她知道紅色是她的顏色”?恰當(dāng)?shù)姆g是:她知道自己和紅色很相配。Then, what's your color?
10、“停電”:No electricity?恩,夠直白!其實(shí)提到“電”,老外更多是用power,停電就可以是Ther is a power failure或Power goes out
有一次編網(wǎng)頁的時(shí)候,把base 標(biāo)簽給刪掉了,超鏈接怎么也行不通,老是路徑不對(duì),原來是base 標(biāo)簽在做怪:
<base>標(biāo)記定義了文檔的基礎(chǔ)URL地址,在文檔中所有的相對(duì)地址形式的URL都是相對(duì)于這里定義的URL而言的。一篇文檔中的<base>標(biāo)記不能多于一個(gè),必須放于頭部,并且應(yīng)該在任何包含URL地址的語句之前。
(1)href 屬性
href屬性指定了文檔的基礎(chǔ)URL地址,該屬性在<base>標(biāo)記中是必須存在的。
例如:如果希望將文檔的基礎(chǔ)URL定義為“www.abc.com”,則可以使用如下語句:
<base href = "www.abc.com"> 當(dāng)定義了基礎(chǔ)URL地址之后,文檔中所有引用的URL地址都從該基礎(chǔ)URL地址開始,例如,對(duì)于上面的語句,如果文檔中一個(gè)超級(jí)鏈接指向gsl/welcome.htm,則它實(shí)際上指向的是如下URL地址:www.abc.com/gsl/welcome.htm
(2)target
target屬性同框架一起使用,它定義了當(dāng)文檔中的鏈接被點(diǎn)擊后,在哪一個(gè)框架中展開頁面。如果文檔中超級(jí)鏈接沒有明確指定展開頁面的目標(biāo)框架集,則就使用這里定義的地址代替。常用的target的屬性值有:
_blank,表明在新窗口中打開鏈接指向的頁面。
_self,在當(dāng)前文檔的框架中打開頁面。
_parent,在當(dāng)前文檔的父窗口中打開頁面。
_top,在鏈接所在的完整窗口中展開頁面。
1、增加一個(gè)虛似硬盤
如果是在vmware里面安裝的windows系統(tǒng),添加個(gè)硬盤很容易,
(1)先打開要添加硬盤的虛擬系統(tǒng)(不要啟動(dòng)該系統(tǒng)),選擇虛擬機(jī)菜單---設(shè)置-----選添加,
(2)然后在彈出添加硬件向?qū)Т翱谥?-----選擇硬盤-------一路next就好了,后面的操作和新建一個(gè)虛擬機(jī)的時(shí)候配置硬盤是一樣的。
(3)添加了新的硬盤后,啟動(dòng)windows進(jìn)到系統(tǒng)中,在控制面板中找“管理工具”->“計(jì)算機(jī)管理”,然后選“磁盤管理”,添加新磁盤就好了。
其實(shí)很簡(jiǎn)單的..如果想繼續(xù)給VMware增加硬盤的話,重復(fù)上述動(dòng)作。
2、改變?cè)摂M硬盤的大小
界面中并沒有提供增加硬盤容量的方法。
只能在命令行形式下執(zhí)行。
安裝所在盤的c:\Program Files\VMware\VMware Workstation下有一個(gè)vmware-vdiskmanager.exe,就是它。
命令參數(shù)如下:
------------------------------------------------------------------
Usage: vmware-vdiskmanager.exe OPTIONS <disk-name> | <mount-point>
Offline disk manipulation utility
Options:
-c : create disk; need to specify other create options
-d : defragment the specified virtual disk
-k : shrink the specified virtual disk
-n <source-disk> : rename the specified virtual disk; need to
specify destination disk-name
-p : prepare the mounted virtual disk specified by
the drive-letter for shrinking
-q : do not log messages
-r <source-disk> : convert the specified disk; need to specify
destination disk-type
-x <new-capacity> : expand the disk to the specified capacity
Additional options for create and convert:
-a <adapter> : (for use with -c only) adapter type (ide, buslogic o
r lsilogic)
-s <size> : capacity of the virtual disk
-t <disk-type> : disk type id
Disk types:
0 : single growable virtual disk
1 : growable virtual disk split in 2Gb files
2 : preallocated virtual disk
3 : preallocated virtual disk split in 2Gb files
The capacity can be specified in sectors, Kb, Mb or Gb.
The acceptable ranges:
ide adapter : [100.0Mb, 950.0Gb]
scsi adapter: [100.0Mb, 950.0Gb]
ex 1: vmware-vdiskmanager.exe -c -s 850Mb -a ide -t 0 myIdeDisk.vmdk
ex 2: vmware-vdiskmanager.exe -d myDisk.vmdk
ex 3: vmware-vdiskmanager.exe -r sourceDisk.vmdk -t 0 destinationDisk.vm
dk
ex 4: vmware-vdiskmanager.exe -x 36Gb myDisk.vmdk
ex 5: vmware-vdiskmanager.exe -n sourceName.vmdk destinationName.vmdk
ex 6: vmware-vdiskmanager.exe -k myDisk.vmdk
ex 7: vmware-vdiskmanager.exe -p <mount-point>
(A virtual disk first needs to be mounted at <mount-point>)
-----------------------------------------------------------------
其中的-x參數(shù)就是用來擴(kuò)容的……
如這個(gè):vmware-vdiskmanager.exe -x 36Gb myDisk.vmdk
解析: vmware-vdiskmanager.exe -x 大小 虛擬硬盤文件
-------------------------------------------------------
我的執(zhí)行過程:
D:\Program files\VMware\VMware Workstation>vmware-vdiskmanager.exe -x 12GB "F:\Windows Server 2003 Enterprise Edition\Windows Server 2003 Enterprise Edition.vmdk"
==================================================================
總結(jié)一下:
1。文件名應(yīng)該用雙引號(hào)括起來。
2。vmdk文件名要連同路徑。
3。GB,MB,別忘了B。
什么是金融債券?金融債券有哪些種類?
金融債券是由銀行和非銀行金融機(jī)構(gòu)發(fā)行的
債券。在英、美等歐美國(guó)家,金融機(jī)構(gòu)發(fā)行的債券歸類于
公司債券。在我國(guó)及日本等國(guó)家,金融機(jī)構(gòu)發(fā)行的債券稱為金融債券。 金融債券能夠較有效地解決銀行等金融機(jī)構(gòu)的資金來源不足和期限不匹配的矛盾。
一般來說,銀行等金融機(jī)構(gòu)的資金有三個(gè)來源,即吸收存款、向其他機(jī)構(gòu)借款和發(fā)行債券。
存款資金的特點(diǎn)之一,是在經(jīng)濟(jì)發(fā)生動(dòng)蕩的時(shí)候,易發(fā)生儲(chǔ)戶爭(zhēng)相提款的現(xiàn)象,從而造成資金來源不穩(wěn)定;
向其他商業(yè)銀行或中央銀行借款所得的資金主要是短期資金,而金融機(jī)構(gòu)往往需要進(jìn)行一些期限較長(zhǎng)的投融資,這樣就出現(xiàn)了資金來源和資金運(yùn)用在期限上的矛盾,發(fā)行金融債券比較有效地解決了這個(gè)矛盾。債券在到期之前一般不能提前兌換,只能在市場(chǎng)上轉(zhuǎn)讓,從而保證了所籌集資金的穩(wěn)定性。同時(shí),金融機(jī)構(gòu)發(fā)行債券時(shí)可以靈活規(guī)定期限,比如為了一些長(zhǎng)期項(xiàng)目投資,可以發(fā)行期限較長(zhǎng)的債券。因此,發(fā)行金融債券可以使金融機(jī)構(gòu)籌措到穩(wěn)定且期限靈活的資金,從而有利于優(yōu)化資產(chǎn)結(jié)構(gòu),擴(kuò)大長(zhǎng)期投資業(yè)務(wù)。由于銀行等金融機(jī)構(gòu)在一國(guó)經(jīng)濟(jì)中占有較特殊的地位,政府對(duì)它們的運(yùn)營(yíng)又有嚴(yán)格的監(jiān)管,因此,金融債券的資信通常高于其他非金融機(jī)構(gòu)債券,違約風(fēng)險(xiǎn)相對(duì)較小,具有較高的安全性。所以,金融債券的利率通常低于。般的企業(yè)債券,但高于風(fēng)險(xiǎn)更小的國(guó)債和銀行儲(chǔ)蓄存款利率。
按不同標(biāo)準(zhǔn),金融債券可以劃分為很多種類。最常見的分類有以下兩種:
(1) 根據(jù)利息的支付方式 金融債券可分為附息金融債券和貼現(xiàn)全融債券。如果金融債券上附有多期息票,發(fā)行人定期支付利息,則稱為附息金融債券;如果金融債券是以低于面值的價(jià)格貼現(xiàn)發(fā)行,到期按面值還本付息,利息為發(fā)行價(jià)與面佰的差額,則稱為貼現(xiàn)債券。比如票面金額為1000元,期限為1年的貼現(xiàn)金融債券,發(fā)行價(jià)格為900元,1年到期時(shí)支付給投資者1000元,那么利息收入就是100元,而實(shí)際年利率就是11.11%(即<1 000-900>/900* 100%〕。按照國(guó)外通常的做法,貼現(xiàn)金融債券的利息收入要征稅,并且不能在證券交易所上市交易。
(2) 根據(jù)發(fā)行條件 金融債券可分為普通金融債券和累進(jìn)利息金融債券。普通金融債券按面值發(fā)行,到期一次還本付息,期限一般是1年、2年和3年。普通金融債券類似于銀行的定期存款,只是利率高些。累進(jìn)利息金融債券的利率不固定,在不同的時(shí)間段有不同的利率,并且一年比一年高,也就是說,債券的利率隨著債券期限的增加累進(jìn),比如面值1000無、期限為5年的金融債券,第回年利率為9%,第二年利率為10%,第三年為11%,第四年為12%,第五年為13%。投資者可在第一年至第五年之間隨時(shí)去銀行兌付,并獲得規(guī)定的利息。
此外,金融債券也可以像
企業(yè)債券一樣,根據(jù)期限的長(zhǎng)短劃分為短期債券、中期債券和長(zhǎng)期債券;根據(jù)是否記名劃分為記名債券和不記名債券;根據(jù)擔(dān)保情況劃分為信用債券和擔(dān)保債券;根據(jù)可否提前贖回劃分為可提前贖回債券和不可提前贖回債券;根據(jù)債券票面利率是否變動(dòng)劃分為
固定利率債券、
浮動(dòng)利率債券和
累進(jìn)利率債券;根據(jù)發(fā)行人是否給予投資者選擇權(quán)劃分為附有選擇權(quán)的債券和不附有選擇權(quán)的偵券等。
學(xué)習(xí)資源:
http://www.cnblogs.com/jimmyzhang/archive/2007/10/24/936151.html (花上1-2個(gè)小時(shí)仔細(xì)學(xué)習(xí),然后反復(fù)實(shí)踐,能夠很快上手)
正則表達(dá)式工具:
我首推RegexBuddy了。下面這個(gè)地址里有RegexBuddy3.2.1完整版的下載地址(如果你仔細(xì)瀏覽這個(gè)網(wǎng)站,會(huì)發(fā)現(xiàn)此人是一個(gè)正則表達(dá)式狂熱分子):
http://iregex.org/blog/regexbuddy321.html
1、<script language="javascript">
window.onbeforeunload = function()
{
if(((event.clientX > document.body.clientWidth - 43) && (event.clientY < 23)) || event.altKey) {
window.event.returnValue = '關(guān)閉。';
}
}
</script>
2、<script language="javascript">
window.onbeforeunload = function()
{
var n = window.event.screenX - window.screenLeft;
var b = n > document.documentElement.scrollWidth-20;
if(b && window.event.clientY < 0 || window.event.altKey)
{
alert("是關(guān)閉而非刷新");
window.open(this.location);
//return false;
//window.event.returnValue = ""; }
}
</script>
本文來自CSDN博客,轉(zhuǎn)載請(qǐng)標(biāo)明出處:http://blog.csdn.net/ajaxchen_615/archive/2009/07/06/4325917.aspx
如果你的頁面對(duì)IE7兼容沒有問題,又不想大量修改現(xiàn)有代碼,同時(shí)又能在IE8中正常使用,微軟聲稱,開發(fā)商僅需要在目前兼容IE7的網(wǎng)站上添加一行代碼即可解決問題,此代碼如下:
CODE:
<meta http-equiv="x-ua-compatible" content="ie=7" />
從今天開始學(xué)習(xí).net開發(fā),java開發(fā)工作暫放一放,不過在學(xué)習(xí).net的過程中,會(huì)結(jié)合java對(duì)比,在學(xué)習(xí)新知識(shí)的同時(shí)也鞏固和復(fù)習(xí)一下java的知識(shí),在學(xué)習(xí)中提升,在學(xué)習(xí)中成長(zhǎng),加油!
1.對(duì)象和屬性
對(duì)象是一種復(fù)核數(shù)據(jù)類型,它們將多個(gè)數(shù)據(jù)值幾種在一個(gè)單元中,而且允許使用名字來存取這些值,即對(duì)象是一個(gè)無序的屬性集合,這個(gè)屬性都有自己的名字和值,存儲(chǔ)在對(duì)象中的以命名的值可以是數(shù)字和字符串這樣的原始值,也可以是對(duì)象。
2.對(duì)象的創(chuàng)建
對(duì)象是由運(yùn)算符new來創(chuàng)建的,在這個(gè)運(yùn)算符之后必須有用于初始化對(duì)象的構(gòu)造函數(shù)名。
創(chuàng)建一個(gè)空對(duì)象(即沒有屬性的對(duì)象)
var o = new Object();
js還支持內(nèi)部構(gòu)造函數(shù),它們以另一種簡(jiǎn)潔的方式初始化新創(chuàng)建的對(duì)象
var now = new Date();
var new_year = new Date(2009,09,19);
3.屬性的設(shè)置和查詢
4.屬性的枚舉
for/in循環(huán)列出的屬性并沒有特定順序,而且它只能枚舉出所有用戶定義的屬性,但是卻不能枚舉出那些預(yù)定義的屬性或方法,并且它可以
枚舉出被設(shè)為undefined的屬性,但是它不能列出被delete刪除的屬性。
5.未定義的屬性
如果要讀取一個(gè)不存在屬性的值,那么得到的結(jié)果是一個(gè)特殊的js值,undefined
可以使用delete來刪除一個(gè)對(duì)象的屬性,注意:刪除一個(gè)屬性并不僅僅是把該屬性設(shè)置為undefined,而是真正從對(duì)象中移除了該屬性。
6.構(gòu)造函數(shù)
它由new運(yùn)算符調(diào)用,傳遞給它的是一個(gè)新創(chuàng)建的空對(duì)象引用,將該引用作為關(guān)鍵字this的值,而且它還要對(duì)新創(chuàng)建的對(duì)象進(jìn)行適當(dāng)?shù)某跏蓟?/p>
注意:構(gòu)造函數(shù)如何使用它的參數(shù)來初始化this關(guān)鍵字所引用的對(duì)象的屬性,記住,構(gòu)造函數(shù)只是初始化了特定的對(duì)象,但并不返回這個(gè)對(duì)象。
構(gòu)造函數(shù)通常沒有返回值,他們只是初始化由this值傳遞進(jìn)來的對(duì)象,并且什么也不返回..但是,構(gòu)造函數(shù)可以返回一個(gè)對(duì)象值,如果這樣做,被返回的對(duì)象就成了new表達(dá)式的值了,在這種情況下,
this值所引用的對(duì)象就被丟棄了。
7.方法
方法有一個(gè)非常重要的屬性,即在方法主體內(nèi)部,關(guān)鍵字this的值變成了調(diào)用該方法的對(duì)象。
方法和函數(shù)的區(qū)別,其實(shí)他們沒有什么技術(shù)上的差別,真正的區(qū)別存在于設(shè)計(jì)和目的上,方法是用來對(duì)this對(duì)象進(jìn)行操作的,而函數(shù)通常是獨(dú)立的,并不需要使用this對(duì)象。
8.原型對(duì)象和繼承
js對(duì)象都“繼承”原型對(duì)象的屬性,每個(gè)對(duì)象都有原型對(duì)象,原型對(duì)象的所有屬性是以它為原型的對(duì)象的屬性,也就是說,每個(gè)對(duì)象都繼承原型對(duì)象的所有屬性,
一個(gè)對(duì)象的原型是有創(chuàng)建并初始化該對(duì)象的構(gòu)造函數(shù)定義的,js中的所有函數(shù)都有prototype屬性,它引用一個(gè)對(duì)象,雖然原型對(duì)象初始化時(shí)是空的,但是你在其中定義的任何屬性都會(huì)被構(gòu)造函數(shù)創(chuàng)建
的所有對(duì)象繼承。
構(gòu)造函數(shù)定義了對(duì)象的類,并初始化了類中狀態(tài)變量的屬性,因?yàn)樵蛯?duì)象和構(gòu)造函數(shù)關(guān)聯(lián)在一起,所以類的每個(gè)成員都從原型對(duì)象繼承了相同的屬性,這說明原型對(duì)象是存放方法和其他常量屬性的理
想場(chǎng)所。
繼承是在查詢一個(gè)屬性值時(shí)自動(dòng)發(fā)生的,屬性并非從原型對(duì)象賦值到新的對(duì)象的,他們只不過看起來像是那些對(duì)象的屬性,有兩點(diǎn)重要的含義,一是:使用原型對(duì)象可以大量減少每個(gè)對(duì)象對(duì)內(nèi)存的需求
量,因?yàn)閷?duì)象可以繼承許多屬性;而且即使屬性在對(duì)象被創(chuàng)建之后才添加屬性到它的原型對(duì)象中,對(duì)象也能夠繼承這些屬性。
屬性的繼承只發(fā)生在讀屬性值時(shí),而在寫屬性值時(shí)不會(huì)發(fā)生。
因?yàn)樵蛯?duì)象的屬性被一個(gè)類的所有對(duì)象共享,所以通常只用他們來定義類中所有對(duì)象的相同的屬性,這使得原型對(duì)象適合于方法定義,另外原型對(duì)象還適合于具有常量的屬性的定義,
a.原型和內(nèi)部類
不只是用戶定義的類有原型對(duì)象,像內(nèi)部類同樣具有原型對(duì)象,也可以給他們賦值,
e.g String.prototype.endsWith = function(o){
return (e == this,charAt(this.length-1));
}
9.面向?qū)ο蟮膉s
在面向?qū)ο蟮某绦蛟O(shè)計(jì)中,共有的概念是強(qiáng)類型和支持以類為基礎(chǔ)的繼承機(jī)制,根據(jù)這個(gè)評(píng)判標(biāo)準(zhǔn),就可以證明js不是面向?qū)ο笳Z言。
js對(duì)象可以具有大量的屬性,而且還可以動(dòng)態(tài)的將這些屬性添加到對(duì)象中,這是對(duì)面對(duì)象c++和java做不到的,
雖然js沒有類的概念,但是它用構(gòu)造函數(shù)和原型對(duì)象模擬了類。
js和以類為基礎(chǔ)的面向?qū)ο笳Z言中,同一個(gè)類可以具有多個(gè)對(duì)象,對(duì)象是它所屬的那個(gè)類的實(shí)力,所以任何類都可以有多個(gè)實(shí)例,js中的命名延勇了java中的命名約定,即命名類時(shí)以大寫字母開頭,命名對(duì)象時(shí)以小寫字母開頭,類幫助我們區(qū)分代碼中的類和對(duì)象。
實(shí)例屬性
每個(gè)對(duì)象都有它自己?jiǎn)螕?jù)的實(shí)力屬性的副本,為了模擬面向?qū)ο蟮某绦蛟O(shè)計(jì)語言,js中的實(shí)例屬性是那些在對(duì)象中用構(gòu)造函數(shù)創(chuàng)建的或初始化的屬性。
實(shí)例方法
實(shí)例方法和實(shí)例數(shù)據(jù)非常的相似,實(shí)例方法是由特定對(duì)象或?qū)嵗{(diào)用的,實(shí)例方法使用了關(guān)鍵字this來引用他們要操作的對(duì)象或?qū)嵗呛蛯?shí)例屬性不同額一點(diǎn)是每個(gè)實(shí)例方法都是由類的所有實(shí)例共享的,在js中,給類定義一個(gè)實(shí)例方法,是通過把構(gòu)造函數(shù)的原型對(duì)象中的一個(gè)屬性設(shè)置為函數(shù)值類實(shí)現(xiàn)的,這樣,由那個(gè)構(gòu)造函數(shù)創(chuàng)建的所有對(duì)象都會(huì)共享一個(gè)以繼承的對(duì)函數(shù)的引用,而且使用上面素?cái)?shù)的方法調(diào)用語法就能夠調(diào)用這個(gè)函數(shù)。
類屬性
類屬性是一個(gè)與類相關(guān)聯(lián)的變量,而不是和類的每個(gè)實(shí)例相關(guān)聯(lián)的變量,每個(gè)類屬性只有一個(gè)副本,它是通過類存取的,可以簡(jiǎn)單的定義了構(gòu)造函數(shù)自身的一個(gè)屬性來定義類屬性
類方法
類方法是一個(gè)與類關(guān)聯(lián)在一起的方法,而不是和類的實(shí)例關(guān)聯(lián)在一起的方法,要調(diào)用類方法,就必須使用類本身,而不是使用類的特定實(shí)例。由于類方法不能通過一個(gè)特定對(duì)象調(diào)用,所以使用關(guān)鍵字this對(duì)它來說沒有意義,和類屬性一樣,類方法是全局性的,
超類和子類
面向?qū)ο笳Z言中有類層次的概念,每個(gè)類都有一個(gè)超類,他們從超類中繼承屬性和方法,類還可以被擴(kuò)展,或者說子類化,這樣其他子類就能繼承它的行為,js中繼承是以原型為基礎(chǔ)的,而不是以類基礎(chǔ)的繼承機(jī)制,但是我們?nèi)耘f能夠總結(jié)出累世的類層次圖,在js中,類Object是最通用的類,其他所有類都是專用化了的版本,或者說的是Object的子類,另一種解釋方法是Object是所有內(nèi)部類的超類,所有類都繼承了Object的基本方法。
舉例說明:
類Complex的對(duì)象就繼承了Complex.prototype對(duì)象的屬性,而后者又繼承了Object.prototype的屬性,由此可以推出,對(duì)象Complex繼承了兩個(gè)對(duì)象的屬性,在Complex對(duì)象中查詢某個(gè)屬性時(shí),首先查詢的是這個(gè)對(duì)象本身,如果在這個(gè)對(duì)喜愛那個(gè)中沒有發(fā)現(xiàn)要查詢的屬性,就查詢Complex.prototype對(duì)象,最后,如果在那個(gè)對(duì)象中還沒有最后按到要查詢的屬性,就查詢Object.prototype對(duì)象,注意類層次關(guān)系中的屬性隱藏。參考P153
10.作為關(guān)聯(lián)數(shù)組的對(duì)象
運(yùn)算符“.”類存取一個(gè)對(duì)象屬性,而數(shù)組更常用的存取書香運(yùn)算賦是[],下面的兩行代碼是等價(jià)的:
obj.property ====== obj["property"],他們的語法區(qū)別是,前者的屬性名是標(biāo)識(shí)符,后者的屬性名卻是一個(gè)字符串,
在c、c++、java和其他類似的強(qiáng)類型語言中,一個(gè)對(duì)象的屬性數(shù)是固定,而且必須預(yù)定義這些屬性的名字,由于js是一種弱類型語言,它并沒有采用這一規(guī)則,所以在用js編寫的程序,可以為對(duì)象創(chuàng)建任意數(shù)目的屬性,但是當(dāng)你采用“.”運(yùn)算符來存取一個(gè)對(duì)象的屬性時(shí),屬性名時(shí)是用標(biāo)識(shí)符表示的,而js程序性中,標(biāo)識(shí)符必須被逐字的輸入,他們不是一種數(shù)據(jù)類型,因此程序不能對(duì)他們進(jìn)行操作。
constructor屬性
每個(gè)對(duì)象都有constructor屬性,它引用的是用來初始化該對(duì)象的構(gòu)造函數(shù)。但是并不是所有的對(duì)象都具有自己唯一的constructor屬性,相反,如果這個(gè)屬性是從原型對(duì)象繼承來的。
js會(huì)為我們定義的每一個(gè)構(gòu)造函數(shù)都創(chuàng)建一個(gè)原型對(duì)象,并且將那個(gè)對(duì)象賦給構(gòu)造函數(shù)的prototype屬性。但是之前沒有說明原型對(duì)象初始時(shí)是非空的,在原型對(duì)象創(chuàng)建之初,它包括一個(gè)constructor屬性, 用來引用構(gòu)造函數(shù),也就是說,如果有一個(gè)函數(shù)f,那么屬性f.prototype.constructor就總是等于f的。
由于構(gòu)造函數(shù)定義了一個(gè)對(duì)象的類,所以屬性construtor在確定給定對(duì)象的類型時(shí)是一個(gè)功能強(qiáng)大的工具。
并不能保證constructor屬性總是存在的,例如,一個(gè)類的創(chuàng)建者可以用一個(gè)全新的對(duì)象來替換構(gòu)造函數(shù)的原型對(duì)象,而新對(duì)象可能不具有有效的constructor屬性。
toString()方法
toLocaleString()方法
valueOf()方法
js需要將一個(gè)對(duì)象轉(zhuǎn)化成字符創(chuàng)之外的原型類型時(shí),就調(diào)用它,這個(gè)函數(shù)返回的是能代表關(guān)鍵字this所引用的對(duì)象的值的數(shù)據(jù)。
hasOwnProperty()
如果兌現(xiàn)局部定義了一個(gè)非繼承的屬性,屬性名是由一個(gè)字符串實(shí)際參數(shù)指定的,那么該方法就返回true,否則,它將返回false。
propertyIsEnumerable()
如果對(duì)象定義了一個(gè)屬性,屬性名是由一個(gè)字符串實(shí)際參數(shù)指定的,而且該屬性可以用for/in循環(huán)枚舉出來,那么該方法返回true,否則返回false。
注意:該方法只考慮對(duì)象直接定義的屬性,而不考慮繼承的屬性,因?yàn)榉祷豧alse可能是因?yàn)槟莻€(gè)屬性是不可枚舉的,也可能是因?yàn)樗m然是可以枚舉的,但卻是個(gè)繼承的屬性。
怎么判斷一個(gè)屬性是可枚舉的?
isPrototypeOf()
如果調(diào)用對(duì)象是實(shí)際參數(shù)指定的對(duì)象的原型對(duì)象,該方法返回true,否則返回false,該方法的用途和對(duì)象的constructoe屬性相似。
1.函數(shù)
注意:定義函數(shù)時(shí)可以使用個(gè)數(shù)可變的參數(shù),而且函數(shù)既可以有return語句,也可以沒有return語句;如果函數(shù)不包含return語句,它就只執(zhí)行函數(shù)體中的每條語句,然后返回給調(diào)用者undefined。
使用運(yùn)算符typeof來檢測(cè)參數(shù)的數(shù)據(jù)類型,使用if(!param)return;來判斷是否存在該參數(shù),因?yàn)閖s是一種無類型語言,所以你不能給函數(shù)的參數(shù)制定一個(gè)數(shù)據(jù)類型,而且js也不會(huì)檢測(cè)傳遞的數(shù)據(jù)是不是那個(gè)函數(shù)所需要的類型,如果參數(shù)很重要時(shí),就使用前面介紹的運(yùn)算符進(jìn)行檢測(cè)。
不可變參數(shù)js的處理:如果傳遞的參數(shù)比函數(shù)需要的個(gè)數(shù)多,那么多余的幾個(gè)參數(shù)被忽略掉,如果傳遞的參數(shù)比函數(shù)需要的個(gè)數(shù)少,那么多余的幾個(gè)參數(shù)就會(huì)被賦予undefined,在大多數(shù)情況下,這回使得函數(shù)產(chǎn)生錯(cuò)誤。
2.嵌套函數(shù)
a,函數(shù)定義中可以嵌套其他函數(shù)的定義,但是只能在在頂層全局代碼和頂層函數(shù)代碼中,不能出現(xiàn)在循環(huán)或條件語句中,并且這些限制只應(yīng)用于由function語句聲明的函數(shù),函數(shù)直接量可以出現(xiàn)在任何js表達(dá)式中。
3.Function()構(gòu)造函數(shù)
可以使用Function()構(gòu)造函數(shù)和new運(yùn)算符動(dòng)態(tài)地定義函數(shù), var f = new Function("x","y","return x*y;");它等價(jià)于:function f(x,y){return x*y;}
Function構(gòu)造函數(shù)可以接受任意多個(gè)字符串參數(shù),它的最后一個(gè)參數(shù)是函數(shù)的主體,其中可以包含任何js語句,語句之間用分號(hào)分隔。由于傳遞給構(gòu)造函數(shù)Function()的參數(shù)中沒有一個(gè)用于說明它要?jiǎng)?chuàng)建的函數(shù)名,用Function()構(gòu)造函數(shù)創(chuàng)建的未命名函數(shù)有時(shí)被稱作為“匿名函數(shù)”。
Function()函數(shù)存在的意義:因?yàn)镕unction()構(gòu)造函數(shù)允許我們動(dòng)態(tài)地建立和編譯一個(gè)函數(shù),它不會(huì)將我們限制在function語句預(yù)編譯的函數(shù)體中;另一個(gè)原因是它能將函數(shù)定義為js表達(dá)式的一部分,而不是將其定義為一個(gè)語句;缺點(diǎn)是:這樣做每次調(diào)用一個(gè)函數(shù)時(shí),F(xiàn)unction()構(gòu)造函數(shù)都要對(duì)它進(jìn)行編譯,
4.函數(shù)直接量
函數(shù)直接量是一個(gè)表達(dá)式,它可以定義匿名函數(shù)。
function f(x){return x*x;} //function語句
var f = new Function("x","return x*x;"); //Function()構(gòu)造函數(shù)
var f = function(X){return x*x;}; //函數(shù)直接量
雖然函數(shù)直接量創(chuàng)建的是未命名函數(shù),但是它的語法也規(guī)定它可以指定函數(shù)名,這在編寫調(diào)用自身的遞歸函數(shù)時(shí)特別的有用,e.g
var f= function fact(x){if(x<=1)return 1; else return x*fact(x-1);}
總結(jié):function()函數(shù)可以任意的使用,具有通用性,F(xiàn)unction()函數(shù)和函數(shù)直接量具有很多的相似性,他們都是未命名函數(shù)(函數(shù)直接量可以有函數(shù)名,尤其是在子調(diào)用函數(shù)中),函數(shù)直接量有個(gè)重要的有點(diǎn),函數(shù)直接量只被解析和編譯一次,而作為字符串傳遞給Function()構(gòu)造函數(shù)的js代碼則在每次調(diào)用構(gòu)造函數(shù)時(shí)只需要被解析和編譯一次。
函數(shù)最重要的特性就是他們能夠被定義和調(diào)用,但是在js中函數(shù)并不只是一種語法,還可以是數(shù)據(jù),可以把函數(shù)賦給變量、存儲(chǔ)在對(duì)象的屬性中或存儲(chǔ)在數(shù)組的元素中,傳遞給函數(shù)。其實(shí)函數(shù)名并沒有什么實(shí)際意義,它只是保存函數(shù)的變量的名字,可以將這個(gè)函數(shù)賦給其他的變量,它仍然以相同的方式起作用,
e.g function square(x){x*x;}
var a = square(4);
var b = square;//這種情況下b引用的函數(shù)和square的作用相同
var c = b(5);
除了賦給全局變量之外,還可以將函數(shù)賦給對(duì)象的屬性,這是稱函數(shù)為方法;也可以賦給數(shù)組元素。
e.g
var a = new Object; var a = new Object();
a.square = new Function("x","return x*x";);
y = o.square(16);
e.g
var a = new Array(3);
a[0] = function(x){return x*x;};
a[1] = 20;
a[2] = a[0](a[1]);
除這些之外,如何將函數(shù)作為參數(shù)傳遞給其他函數(shù),
e.g
function add(x,y){return x+y;}
function subtract(x,y){return x-y;}
function multiply(x,y){return x*y;}
function dibide(x,y){return x/y;}
function operate(operator,operand1,operand2){
return operator(operand1,operand2);
}
var i = operate(add,operate(add,2,3),operate(multiply,4,5));
var operators = new Object();
operators["add"] = function(x,y){return x+y;}
operators["multiply"] = function(x,y){return x*y;}
operators["divide"] = function(x,y){return x/y;}
operators["pow"] = Math.pow;
function operate2(op_name,operand1,operand2){
if(operators[op_name] == null)return "unknow operator";
else return operators[op_name](operand1,operand2);
}
var j = operate2('add',"hello",operate2("add","","world"));
var k = operate2('pow',10,2);
5.函數(shù)的作用域,調(diào)用對(duì)象
函數(shù)的作用域中除了全局變量、函數(shù)內(nèi)部的局部變量和形式參數(shù)外,函數(shù)還定義了一個(gè)特殊屬性,
arguments,這個(gè)屬性應(yīng)用了另外一個(gè)特殊的對(duì)象-----Arguments對(duì)象,因?yàn)閍rguments屬性是調(diào)用對(duì)象的一個(gè)屬性,所以它的狀態(tài)和局部變量以及函數(shù)的形式參數(shù)是相同的。
所以arguments標(biāo)識(shí)符被看做是保留字,不能將它作為變量名或形式參數(shù)名。
6.Arguments對(duì)象
arguments它具有特殊的意義,是調(diào)用對(duì)象的一個(gè)特殊屬性,用來引用Arguments對(duì)象,Arguments對(duì)象就像數(shù)組,可以按照數(shù)字獲取傳遞給函數(shù)的參數(shù)值,但是它并非真正的Array對(duì)象。
arguments具有l(wèi)ength屬性,
可以使用arguments來檢測(cè)調(diào)用函數(shù)使用了正確數(shù)目的實(shí)際參數(shù),
注意:arguments并非真正的數(shù)組,它是一個(gè)Arguments對(duì)象,Arguments對(duì)象有一個(gè)非同尋常的特征,當(dāng)函數(shù)具有命名了的參數(shù)時(shí),Arguments對(duì)象的數(shù)組元素是存放函數(shù)參數(shù)的局部變量的同義詞。
e.g
function(x){
alert(x); //顯示參數(shù)的初始值
arguments[0] = null;//改變數(shù)組預(yù)算也會(huì)改變x
alert(x); //現(xiàn)在顯示為“null”
除了數(shù)組元素,Arguments對(duì)象還定義了callee屬性,用來引用當(dāng)前正在執(zhí)行的函數(shù),這對(duì)未命名的函數(shù)調(diào)用自身非常有用。
e.g
function(x){
if(x<-1)return 1;
return x*arguments.callee(x-1);
}
7.函數(shù)的屬性和方法
由于函數(shù)是對(duì)象,所以它具有數(shù)據(jù)和方法。
函數(shù)的length屬性
函數(shù)的屬性length和arguments屬性的length不同,arguments數(shù)組的length屬性指定了傳遞給該函數(shù)的實(shí)際參數(shù)數(shù)目,并且arguments屬性的length只在函數(shù)內(nèi)部起作用,而函數(shù)自身的length屬性它是只讀的,返回的是函數(shù)需要的實(shí)際參數(shù)的數(shù)目,并且函數(shù)的屬性length函數(shù)體的內(nèi)部和外部都在是有效的。
函數(shù)的prototype屬性
每個(gè)函數(shù)都有一個(gè)prototype屬性,它引用的是預(yù)定義的原型對(duì)象,原型對(duì)象在使用new運(yùn)算符把函數(shù)作為構(gòu)造函數(shù)時(shí)起作用。
函數(shù)自定義屬性
有時(shí)候定義全局變量比較亂,可以通過自定義函數(shù)屬性來解決
函數(shù)的apply()和call()方法
他們的第一個(gè)參數(shù)都是要調(diào)用的函數(shù)的對(duì)象,在函數(shù)體內(nèi)這一參數(shù)是關(guān)鍵字this的值,call()的剩余參數(shù)是傳遞給要調(diào)用的函數(shù)的值,apply()的剩余參數(shù)是由數(shù)組指定的參數(shù)。
寫出漂亮代碼的七種方法
首先我想說明我本文闡述的是純粹從美學(xué)的角度來寫出代碼,而非技術(shù)、邏輯等。以下為寫出漂亮代碼的七種方法:
1, 盡快結(jié)束 if語句
例如下面這個(gè)JavaScript語句,看起來就很恐怖:
- 1 function findShape(flags, point, attribute, list) {
-
- 2 if(!findShapePoints(flags, point, attribute)) {
-
- 3 if(!doFindShapePoints(flags, point, attribute)) {
-
- 4 if(!findInShape(flags, point, attribute)) {
-
- 5 if(!findFromGuide(flags,point) {
-
- 6 if(list.count() > 0 && flags == 1) {
-
- 7 doSomething();
-
- 8 }
-
- 9 }
-
- 10 }
-
- 11 }
-
- 12 }
-
- 13 }
1 function findShape(flags, point, attribute, list) {
2 if(!findShapePoints(flags, point, attribute)) {
3 if(!doFindShapePoints(flags, point, attribute)) {
4 if(!findInShape(flags, point, attribute)) {
5 if(!findFromGuide(flags,point) {
6 if(list.count() > 0 && flags == 1) {
7 doSomething();
8 }
9 }
10 }
11 }
12 }
13 }
但如果這么寫就好看得多:
- 1 function findShape(flags, point, attribute, list) {
-
- 2 if(findShapePoints(flags, point, attribute)) {
-
- 3 return;
-
- 4 }
-
- 5
-
- 6 if(doFindShapePoints(flags, point, attribute)) {
-
- 7 return;
-
- 8 }
-
- 9
-
- 10 if(findInShape(flags, point, attribute)) {
-
- 11 return;
-
- 12 }
-
- 13
-
- 14 if(findFromGuide(flags,point) {
-
- 15 return;
-
- 16 }
-
- 17
-
- 18 if (!(list.count() > 0 && flags == 1)) {
-
- 19 return;
-
- 20 }
-
- 21
-
- 22 doSomething();
-
- 23
-
- 24 }
1 function findShape(flags, point, attribute, list) {
2 if(findShapePoints(flags, point, attribute)) {
3 return;
4 }
5
6 if(doFindShapePoints(flags, point, attribute)) {
7 return;
8 }
9
10 if(findInShape(flags, point, attribute)) {
11 return;
12 }
13
14 if(findFromGuide(flags,point) {
15 return;
16 }
17
18 if (!(list.count() > 0 && flags == 1)) {
19 return;
20 }
21
22 doSomething();
23
24 }
你可能會(huì)很不喜歡第二種的表述方式,但反映出了迅速返回if值的思想,也可以理解為:避免不必要的else陳述。
2, 如果只是簡(jiǎn)單的布爾運(yùn)算(邏輯運(yùn)算),不要使用if語句
例如:
- 1 function isStringEmpty(str){
-
- 2 if(str === "") {
-
- 3 return true;
-
- 4 }
-
- 5 else {
-
- 6 return false;
-
- 7 }
-
- 8 }
1 function isStringEmpty(str){
2 if(str === "") {
3 return true;
4 }
5 else {
6 return false;
7 }
8 }
可以寫為:
- 1 function isStringEmpty(str){
-
- 2 return (str === "");
-
- 3 }
1 function isStringEmpty(str){
2 return (str === "");
3 }
3, 使用空白,這是免費(fèi)的
例如:
1
- function getSomeAngle() {
-
- 2
-
- 3 radAngle1 = Math.atan(slope(center, point1));
-
- 4 radAngle2 = Math.atan(slope(center, point2));
-
- 5 firstAngle = getStartAngle(radAngle1, point1, center);
-
- 6 secondAngle = getStartAngle(radAngle2, point2, center);
-
- 7 radAngle1 = degreesToRadians(firstAngle);
-
- 8 radAngle2 = degreesToRadians(secondAngle);
-
- 9 baseRadius = distance(point, center);
-
- 10 radius = baseRadius + (lines * y);
-
- 11 p1["x"] = roundValue(radius * Math.cos(radAngle1) + center["x"]);
-
- 12 p1["y"] = roundValue(radius * Math.sin(radAngle1) + center["y"]);
-
- 13 pt2["x"] = roundValue(radius * Math.cos(radAngle2) + center["y"]);
-
- 14 pt2["y"] = roundValue(radius * Math.sin(radAngle2) + center["y");
-
- 15
-
- 16 }
function getSomeAngle() {
2 // Some code here then
3 radAngle1 = Math.atan(slope(center, point1));
4 radAngle2 = Math.atan(slope(center, point2));
5 firstAngle = getStartAngle(radAngle1, point1, center);
6 secondAngle = getStartAngle(radAngle2, point2, center);
7 radAngle1 = degreesToRadians(firstAngle);
8 radAngle2 = degreesToRadians(secondAngle);
9 baseRadius = distance(point, center);
10 radius = baseRadius + (lines * y);
11 p1["x"] = roundValue(radius * Math.cos(radAngle1) + center["x"]);
12 p1["y"] = roundValue(radius * Math.sin(radAngle1) + center["y"]);
13 pt2["x"] = roundValue(radius * Math.cos(radAngle2) + center["y"]);
14 pt2["y"] = roundValue(radius * Math.sin(radAngle2) + center["y");
15 // Now some more code
16 }
很多開發(fā)者不愿意使用空白,就好像這要收費(fèi)一樣。我在此并非刻意地添加空白,粗魯?shù)卮驍啻a的連貫性。在實(shí)際編寫代碼的過程中,會(huì)很容易地發(fā)現(xiàn)在什么地方加入空白,這不但美觀而且讓讀者易懂,如下:
- 1 function getSomeAngle() {
-
- 2
-
- 3 radAngle1 = Math.atan(slope(center, point1));
-
- 4 radAngle2 = Math.atan(slope(center, point2));
-
- 5
-
- 6 firstAngle = getStartAngle(radAngle1, point1, center);
-
- 7 secondAngle = getStartAngle(radAngle2, point2, center);
-
- 8
-
- 9 radAngle1 = degreesToRadians(firstAngle);
-
- 10 radAngle2 = degreesToRadians(secondAngle);
-
- 11
-
- 12 baseRadius = distance(point, center);
-
- 13 radius = baseRadius + (lines * y);
-
- 14
-
- 15 p1["x"] = roundValue(radius * Math.cos(radAngle1) + center["x"]);
-
- 16 p1["y"] = roundValue(radius * Math.sin(radAngle1) + center["y"]);
-
- 17
-
- 18 pt2["x"] = roundValue(radius * Math.cos(radAngle2) + center["y"]);
-
- 19 pt2["y"] = roundValue(radius * Math.sin(radAngle2) + center["y");
-
- 20
-
- 21 }
-
-
-
- 4, 不要使用無謂的注釋
-
- 無謂的注釋讓人費(fèi)神,這實(shí)在很討厭。不要標(biāo)出很明顯的注釋。在以下的例子中,每個(gè)人都知道代碼表達(dá)的是“students id”,因而沒必要標(biāo)出。
-
- 1 function existsStudent(id, list) {
-
- 2 for(i = 0; i < list.length; i++) {
-
- 3 student = list[i];
-
- 4
-
- 5
-
- 6 thisId = student.getId();
-
- 7
-
- 8 if(thisId === id) {
-
- 9 return true;
-
- 10 }
-
- 11 }
-
- 12 return false;
-
- 13 }
1 function getSomeAngle() {
2 // Some code here then
3 radAngle1 = Math.atan(slope(center, point1));
4 radAngle2 = Math.atan(slope(center, point2));
5
6 firstAngle = getStartAngle(radAngle1, point1, center);
7 secondAngle = getStartAngle(radAngle2, point2, center);
8
9 radAngle1 = degreesToRadians(firstAngle);
10 radAngle2 = degreesToRadians(secondAngle);
11
12 baseRadius = distance(point, center);
13 radius = baseRadius + (lines * y);
14
15 p1["x"] = roundValue(radius * Math.cos(radAngle1) + center["x"]);
16 p1["y"] = roundValue(radius * Math.sin(radAngle1) + center["y"]);
17
18 pt2["x"] = roundValue(radius * Math.cos(radAngle2) + center["y"]);
19 pt2["y"] = roundValue(radius * Math.sin(radAngle2) + center["y");
20 // Now some more code
21 }
4, 不要使用無謂的注釋
無謂的注釋讓人費(fèi)神,這實(shí)在很討厭。不要標(biāo)出很明顯的注釋。在以下的例子中,每個(gè)人都知道代碼表達(dá)的是“students id”,因而沒必要標(biāo)出。
1 function existsStudent(id, list) {
2 for(i = 0; i < list.length; i++) {
3 student = list[i];
4
5 // Get the student's id
6 thisId = student.getId();
7
8 if(thisId === id) {
9 return true;
10 }
11 }
12 return false;
13 }
5, 不要在源文件中留下已經(jīng)刪除的代碼,哪怕你標(biāo)注了
如果你使用了版本控制,那么你就可以輕松地找回前一個(gè)版本的代碼。如果別人大費(fèi)周折地讀了你的代碼,卻發(fā)現(xiàn)是要?jiǎng)h除的代碼,這實(shí)在太恨人了。
//function thisReallyHandyFunction() {
// someMagic();
// someMoreMagic();
// magicNumber = evenMoreMagic();
// return magicNumber;
//}
6,不要有太長(zhǎng)的代碼
看太長(zhǎng)的代碼實(shí)在太費(fèi)勁,尤其是代碼本身的功能又很小。如下:
- 1 public static EnumMap<Category, IntPair> getGroupCategoryDistribution(EnumMap<Category, Integer> sizes, int groups) {
-
- 2 EnumMap<Category, IntPair> categoryGroupCounts = new EnumMap<Category,IntPair>(Category.class);
-
- 3
-
- 4 for(Category cat : Category.values()) {
-
- 5 categoryGroupCounts.put(cat, getCategoryDistribution(sizes.get(cat), groups));
-
- 6 }
1 public static EnumMap<Category, IntPair> getGroupCategoryDistribution(EnumMap<Category, Integer> sizes, int groups) {
2 EnumMap<Category, IntPair> categoryGroupCounts = new EnumMap<Category,IntPair>(Category.class);
3
4 for(Category cat : Category.values()) {
5 categoryGroupCounts.put(cat, getCategoryDistribution(sizes.get(cat), groups));
6 }
#
我并不是說非要堅(jiān)持70個(gè)字符以內(nèi),但是一個(gè)比較理想的長(zhǎng)度是控制在120個(gè)字符內(nèi)。如果你把代碼發(fā)布在互聯(lián)網(wǎng)上,用戶讀起來就很困難。
7,不要在一個(gè)功能(或者函數(shù)內(nèi))有太多代碼行
我的一個(gè)老同事曾經(jīng)說Visual C++很臭,因?yàn)樗辉试S你在一個(gè)函數(shù)內(nèi)擁有超過10,000行代碼。我記不清代碼行數(shù)的上限,不知道他說的是否正確,但我很不贊成他的觀點(diǎn)。如果一個(gè)函數(shù)超過了50行,看起來有多費(fèi)勁你知道么,還有沒完沒了的if循環(huán),而且你還的滾動(dòng)鼠標(biāo)前后對(duì)照這段代碼。對(duì)我而言,超過35行的代碼理解起來就很困難了。我的建議是超過這個(gè)數(shù)字就把一個(gè)函數(shù)代碼分割成兩個(gè)。
本篇文章為在工作中使用JAVA反射的經(jīng)驗(yàn)總結(jié),也可以說是一些小技巧,以后學(xué)會(huì)新的小技巧,會(huì)不斷更新。
在開始之前,我先定義一個(gè)測(cè)試類Student,代碼如下:
- package chb.test.reflect;
-
- public class Student {
- private int age;
- private String name;
- public int getAge() {
- return age;
- }
- public void setAge(int age) {
- this.age = age;
- }
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
-
- public static void hi(int age,String name){
- System.out.println("大家好,我叫"+name+",今年"+age+"歲");
- }
- }<PRE></PRE>
package chb.test.reflect;
public class Student {
private int age;
private String name;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public static void hi(int age,String name){
System.out.println("大家好,我叫"+name+",今年"+age+"歲");
}
}
一、JAVA反射的常規(guī)使用步驟
反射調(diào)用一般分為3個(gè)步驟:
代碼示例:
- Class cls = Class.forName("chb.test.reflect.Student");
- Method m = cls.getDeclaredMethod("hi",new Class[]{int.class,String.class});
- m.invoke(cls.newInstance(),20,"chb");<PRE></PRE>
Class cls = Class.forName("chb.test.reflect.Student");
Method m = cls.getDeclaredMethod("hi",new Class[]{int.class,String.class});
m.invoke(cls.newInstance(),20,"chb");
二、方法調(diào)用中的參數(shù)類型
在方法調(diào)用中,參數(shù)類型必須正確,這里需要注意的是不能使用包裝類替換基本類型,比如不能使用Integer.class代替int.class。
如我要調(diào)用Student的setAge方法,下面的調(diào)用是正確的:
- Class cls = Class.forName("chb.test.reflect.Student");
- Method setMethod = cls.getDeclaredMethod("setAge",int.class);
- setMethod.invoke(cls.newInstance(), 15);<PRE></PRE>
Class cls = Class.forName("chb.test.reflect.Student");
Method setMethod = cls.getDeclaredMethod("setAge",int.class);
setMethod.invoke(cls.newInstance(), 15);
而如果我們用Integer.class替代int.class就會(huì)出錯(cuò),如:
- Class cls = Class.forName("chb.test.reflect.Student");
- Method setMethod = cls.getDeclaredMethod("setAge",Integer.class);
- setMethod.invoke(cls.newInstance(), 15);<PRE></PRE>
Class cls = Class.forName("chb.test.reflect.Student");
Method setMethod = cls.getDeclaredMethod("setAge",Integer.class);
setMethod.invoke(cls.newInstance(), 15);
jvm會(huì)報(bào)出如下異常:
- java.lang.NoSuchMethodException: chb.test.reflect.Student.setAge(java.lang.Integer)
- at java.lang.Class.getDeclaredMethod(Unknown Source)
- at chb.test.reflect.TestClass.testReflect(TestClass.java:23)<PRE></PRE>
java.lang.NoSuchMethodException: chb.test.reflect.Student.setAge(java.lang.Integer)
at java.lang.Class.getDeclaredMethod(Unknown Source)
at chb.test.reflect.TestClass.testReflect(TestClass.java:23)
三、static方法的反射調(diào)用
static方法調(diào)用時(shí),不必得到對(duì)象示例,如下:
- Class cls = Class.forName("chb.test.reflect.Student");
- Method staticMethod = cls.getDeclaredMethod("hi",int.class,String.class);
- staticMethod.invoke(cls,20,"chb");
-
Class cls = Class.forName("chb.test.reflect.Student");
Method staticMethod = cls.getDeclaredMethod("hi",int.class,String.class);
staticMethod.invoke(cls,20,"chb");//這里不需要newInstance
//staticMethod.invoke(cls.newInstance(),20,"chb");
四、private的成員變量賦值
如果直接通過反射給類的private成員變量賦值,是不允許的,這時(shí)我們可以通過setAccessible方法解決。代碼示例:
- Class cls = Class.forName("chb.test.reflect.Student");
- Object student = cls.newInstance();
- Field field = cls.getDeclaredField("age");
- field.set(student, 10);
- System.out.println(field.get(student));<PRE></PRE>
Class cls = Class.forName("chb.test.reflect.Student");
Object student = cls.newInstance();//得到一個(gè)實(shí)例
Field field = cls.getDeclaredField("age");
field.set(student, 10);
System.out.println(field.get(student));
運(yùn)行如上代碼,系統(tǒng)會(huì)報(bào)出如下異常:
- java.lang.IllegalAccessException: Class chb.test.reflect.TestClass can not access a member of class chb.test.reflect.Student with modifiers "private"
- at sun.reflect.Reflection.ensureMemberAccess(Unknown Source)
- at java.lang.reflect.Field.doSecurityCheck(Unknown Source)
- at java.lang.reflect.Field.getFieldAccessor(Unknown Source)
- at java.lang.reflect.Field.set(Unknown Source)
- at chb.test.reflect.TestClass.testReflect(TestClass.java:20)<PRE></PRE>
java.lang.IllegalAccessException: Class chb.test.reflect.TestClass can not access a member of class chb.test.reflect.Student with modifiers "private"
at sun.reflect.Reflection.ensureMemberAccess(Unknown Source)
at java.lang.reflect.Field.doSecurityCheck(Unknown Source)
at java.lang.reflect.Field.getFieldAccessor(Unknown Source)
at java.lang.reflect.Field.set(Unknown Source)
at chb.test.reflect.TestClass.testReflect(TestClass.java:20)
解決方法:
- Class cls = Class.forName("chb.test.reflect.Student");
- Object student = cls.newInstance();
- Field field = cls.getDeclaredField("age");
- field.setAccessible(true);
- field.set(student, 10);
- System.out.println(field.get(student));<PRE></PRE>
Class cls = Class.forName("chb.test.reflect.Student");
Object student = cls.newInstance();
Field field = cls.getDeclaredField("age");
field.setAccessible(true);//設(shè)置允許訪問
field.set(student, 10);
System.out.println(field.get(student));
其實(shí),在某些場(chǎng)合下(類中有g(shù)et,set方法),可以先反射調(diào)用set方法,再反射調(diào)用get方法達(dá)到如上效果,代碼示例:
- Class cls = Class.forName("chb.test.reflect.Student");
- Object student = cls.newInstance();
-
- Method setMethod = cls.getDeclaredMethod("setAge",Integer.class);
- setMethod.invoke(student, 15);
-
- Method getMethod = cls.getDeclaredMethod("getAge");
- System.out.println(getMethod.invoke(student));
|
Reflection 是 Java 程序開發(fā)語言的特征之一,它允許運(yùn)行中的 Java 程序?qū)ψ陨磉M(jìn)行檢查,或者說“自審”,并能直接操作程序的內(nèi)部屬性。例如,使用它能獲得 Java 類中各成員的名稱并顯示出來。JavaBean 是 reflection 的實(shí)際應(yīng)用之一,它能讓一些工具可視化的操作軟件組件。這些工具通過 reflection 動(dòng)態(tài)的載入并取得 Java 組件(類) 的屬性。
1. 一個(gè)簡(jiǎn)單的例子
考慮下面這個(gè)簡(jiǎn)單的例子,讓我們看看 reflection 是如何工作的。
import java.lang.reflect.*;
public class DumpMethods {
public static void main(String args[]) {
try {
Class c = Class.forName(args[0]);
Method m[] = c.getDeclaredMethods();
for (int i = 0; i < m.length; i++)
System.out.println(m[i].toString());
} catch (Throwable e) {
System.err.println(e);
}
}
}
按如下語句執(zhí)行:
java DumpMethods java.util.Stack
它的結(jié)果輸出為:
public java.lang.Object java.util.Stack.push(java.lang.Object)
public synchronized java.lang.Object java.util.Stack.pop()
public synchronized java.lang.Object java.util.Stack.peek()
public boolean java.util.Stack.empty()
public synchronized int java.util.Stack.search(java.lang.Object)
這樣就列出了java.util.Stack 類的各方法名以及它們的限制符和返回類型。
這個(gè)程序使用 Class.forName 載入指定的類,然后調(diào)用 getDeclaredMethods 來獲取這個(gè)類中定義了的方法列表。java.lang.reflect.Methods 是用來描述某個(gè)類中單個(gè)方法的一個(gè)類。還有就是getDeclaredMethod(para1,para2)來獲取這個(gè)類中的具體某一個(gè)方法,其中para1是一個(gè)String類型,具體代表的是方法名,para2是個(gè)一個(gè)Class類型的數(shù)組,其中定義個(gè)方法的具體參數(shù)類型。
例如:
- Class cls = Class.forName("chb.test.reflect.Student");
- Method m = cls.getDeclaredMethod("方法名",new Class[]{int.class,String.class});
- m.invoke(cls.newInstance(),20,"chb");
總結(jié):
//使用反射類調(diào)用某個(gè)類中的方法
Class c = Class.forName("com.inspur.reflect.MethodTest");
Method n = c.getDeclaredMethod("show", new Class[]{String.class,int.class});
n.invoke(c.newInstance(), "guoxzh",20);
a.使用Class.forName("類名")來獲取類
b.其次使用getDeclaredMethods()方法獲取該類所有的方法,也可以使用getDeclaredMethod("方法名",new Class[]{int.class,String.class})方法類獲取具體的某一個(gè)方法
c.接著可以使用invoke(c.newInstance,param....)來調(diào)用具體的方法。
2.詳細(xì)介紹開始使用 Reflection
用于 reflection 的類,如 Method,可以在 java.lang.relfect 包中找到。使用這些類的時(shí)候必須要遵循三個(gè)步驟:第一步是獲得你想操作的類的 java.lang.Class 對(duì)象。在運(yùn)行中的 Java 程序中,用 java.lang.Class 類來描述類和接口等。
下面就是獲得一個(gè) Class 對(duì)象的方法之一:
Class c = Class.forName("java.lang.String");
這條語句得到一個(gè) String 類的類對(duì)象。還有另一種方法,如下面的語句:
Class c = int.class;
或者
Class c = Integer.TYPE;
它們可獲得基本類型的類信息。其中后一種方法中訪問的是基本類型的封裝類 (如 Integer) 中預(yù)先定義好的 TYPE 字段。
第二步是調(diào)用諸如 getDeclaredMethods 的方法,以取得該類中定義的所有方法的列表。
一旦取得這個(gè)信息,就可以進(jìn)行第三步了——使用 reflection API 來操作這些信息,如下面這段代碼:
Class c = Class.forName("java.lang.String");
Method m[] = c.getDeclaredMethods();
System.out.println(m[0].toString());
它將以文本方式打印出 String 中定義的第一個(gè)方法的原型。
在下面的例子中,這三個(gè)步驟將為使用 reflection 處理特殊應(yīng)用程序提供例證。
模擬 instanceof 操作符
得到類信息之后,通常下一個(gè)步驟就是解決關(guān)于 Class 對(duì)象的一些基本的問題。例如,Class.isInstance 方法可以用于模擬 instanceof 操作符:
class A {
}
public class instance1 {
public static void main(String args[]) {
try {
Class cls = Class.forName("A");
boolean b1 = cls.isInstance(new Integer(37)); //判斷Integer(37)該對(duì)象是否是A類的對(duì)象
System.out.println(b1);
boolean b2 = cls.isInstance(new A());
System.out.println(b2);
} catch (Throwable e) {
System.err.println(e);
}
}
}
在這個(gè)例子中創(chuàng)建了一個(gè) A 類的 Class 對(duì)象,然后檢查一些對(duì)象是否是 A 的實(shí)例。Integer(37) 不是,但 new A() 是。
3.找出類的方法
找出一個(gè)類中定義了些什么方法,這是一個(gè)非常有價(jià)值也非常基礎(chǔ)的 reflection 用法。下面的代碼就實(shí)現(xiàn)了這一用法:
package com.inspur.reflect;
import java.lang.reflect.Method;
public class Methodtest1 {
private int abc(Object p,int x) throws NullPointerException{
if(p==null)throw new NullPointerException();
return x;
}
public static void main(String[] args) {
try{
Class cls = Class.forName("com.inspur.reflect.Methodtest1");
Method methodlist[]= cls.getDeclaredMethods();
for(int i = 0;i<methodlist.length;i++){
Method m = methodlist[i];
System.out.println("name=="+m.getName());//得到方法的名稱
System.out.println("decl class=="+m.getDeclaringClass());//得到定義的類名
Class prev[] = m.getParameterTypes(); //取m方法中的所有參數(shù)
//遍歷所有的參數(shù)
for(int j = 0; j<prev.length;j++){
System.out.println("param["+j+"]=="+prev[j]);
}
Class exec[] = m.getExceptionTypes(); //得到所有的異常
//遍歷所有的異常
for(int k=0;k<exec.length;k++){
System.out.println("execption["+k+"]=="+exec[k]);
}
Class ret = m.getReturnType(); //得到每個(gè)方法的返回值
System.out.println("return leixing=="+ret.toString());
}
}catch(Throwable e){
System.err.println(e.getMessage());
}
}
}
這個(gè)程序首先取得 method1 類的描述,然后調(diào)用 getDeclaredMethods 來獲取一系列的 Method 對(duì)象,它們分別描述了定義在類中的每一個(gè)方法,包括 public 方法、protected 方法、package 方法和 private 方法等。
如果你在程序中使用 getMethods 來代替 getDeclaredMethods,你還能獲得繼承來的各個(gè)方法的信息。同時(shí)你也可以使用Modifier.toString(m.getModifiers())來獲取方法的限制屬性。
取得了 Method 對(duì)象列表之后,要顯示這些方法的參數(shù)類型、異常類型和返回值類型等就不難了。這些類型是基本類型還是類類型,都可以由描述類的對(duì)象按順序給出。
輸出的結(jié)果如下:
name==main
decl class==class com.inspur.reflect.Methodtest1
param[0]==class [Ljava.lang.String;
return leixing==void
name==abc
decl class==class com.inspur.reflect.Methodtest1
param[0]==class java.lang.Object
param[1]==int
execption[0]==class java.lang.NullPointerException
return leixing==int 4.獲取構(gòu)造器信息
獲取類構(gòu)造器的用法與上述獲取方法的用法類似,如:
import java.lang.reflect.*;
public class constructor1 {
public constructor1() {
}
protected constructor1(int i, double d) {
}
public static void main(String args[]) {
try {
Class cls = Class.forName("constructor1");
Constructor ctorlist[] = cls.getDeclaredConstructors();
for (int i = 0; i < ctorlist.length; i++) {
Constructor ct = ctorlist[i];
System.out.println("name = " + ct.getName());
System.out.println("decl class = " + ct.getDeclaringClass());
Class pvec[] = ct.getParameterTypes();
for (int j = 0; j < pvec.length; j++)
System.out.println("param #" + j + " " + pvec[j]);
Class evec[] = ct.getExceptionTypes();
for (int j = 0; j < evec.length; j++)
System.out.println("exc #" + j + " " + evec[j]);
System.out.println("-----");
}
} catch (Throwable e) {
System.err.println(e);
}
}
}
這個(gè)例子中沒能獲得返回類型的相關(guān)信息,那是因?yàn)闃?gòu)造器沒有返回類型。
這個(gè)程序運(yùn)行的結(jié)果是:
name = constructor1
decl class = class constructor1
-----
name = constructor1
decl class = class constructor1
param #0 int
param #1 double
-----
5.獲取類的字段(域)
找出一個(gè)類中定義了哪些數(shù)據(jù)字段也是可能的,下面的代碼就在干這個(gè)事情:
import java.lang.reflect.*;
public class field1 {
private double d;
public static final int i = 37;
String s = "testing";
public static void main(String args[]) {
try {
Class cls = Class.forName("field1");
Field fieldlist[] = cls.getDeclaredFields();
for (int i = 0; i < fieldlist.length; i++) {
Field fld = fieldlist[i];
System.out.println("name = " + fld.getName());
System.out.println("decl class = " + fld.getDeclaringClass());
System.out.println("type = " + fld.getType());
int mod = fld.getModifiers();
System.out.println("modifiers = " + Modifier.toString(mod));
System.out.println("-----");
}
} catch (Throwable e) {
System.err.println(e);
}
}
}
這個(gè)例子和前面那個(gè)例子非常相似。例中使用了一個(gè)新東西 Modifier,它也是一個(gè) reflection 類,用來描述字段成員的修飾語,如“private int”。這些修飾語自身由整數(shù)描述,而且使用 Modifier.toString 來返回以“官方”順序排列的字符串描述 (如“static”在“final”之前)。這個(gè)程序的輸出是:
name = d
decl class = class field1
type = double
modifiers = private
-----
name = i
decl class = class field1
type = int
modifiers = public static final
-----
name = s
decl class = class field1
type = class java.lang.String
modifiers =
-----
和獲取方法的情況一下,獲取字段的時(shí)候也可以只取得在當(dāng)前類中申明了的字段信息 (getDeclaredFields),或者也可以取得父類中定義的字段 (getFields) 。
6.根據(jù)方法的名稱來執(zhí)行方法
文本到這里,所舉的例子無一例外都與如何獲取類的信息有關(guān)。我們也可以用 reflection 來做一些其它的事情,比如執(zhí)行一個(gè)指定了名稱的方法。下面的示例演示了這一操作:
import java.lang.reflect.*;
public class method2 {
public int add(int a, int b) {
return a + b;
}
public static void main(String args[]) {
try {
Class cls = Class.forName("method2");
Class partypes[] = new Class[2];
partypes[0] = Integer.TYPE;
partypes[1] = Integer.TYPE;
Method meth = cls.getMethod("add", partypes);
method2 methobj = new method2();
Object arglist[] = new Object[2];
arglist[0] = new Integer(37);
arglist[1] = new Integer(47);
Object retobj = meth.invoke(methobj, arglist);
Integer retval = (Integer) retobj;
System.out.println(retval.intValue());
} catch (Throwable e) {
System.err.println(e);
}
}
}
假如一個(gè)程序在執(zhí)行的某處的時(shí)候才知道需要執(zhí)行某個(gè)方法,這個(gè)方法的名稱是在程序的運(yùn)行過程中指定的 (例如,JavaBean 開發(fā)環(huán)境中就會(huì)做這樣的事),那么上面的程序演示了如何做到。
上例中,getMethod 用于查找一個(gè)具有兩個(gè)整型參數(shù)且名為 add 的方法。找到該方法并創(chuàng)建了相應(yīng)的 Method 對(duì)象之后,在正確的對(duì)象實(shí)例中執(zhí)行它。執(zhí)行該方法的時(shí)候,需要提供一個(gè)參數(shù)列表,這在上例中是分別包裝了整數(shù) 37 和 47 的兩個(gè) Integer 對(duì)象。執(zhí)行方法的返回的同樣是一個(gè) Integer 對(duì)象,它封裝了返回值 84。
7.創(chuàng)建新的對(duì)象
對(duì)于構(gòu)造器,則不能像執(zhí)行方法那樣進(jìn)行,因?yàn)閳?zhí)行一個(gè)構(gòu)造器就意味著創(chuàng)建了一個(gè)新的對(duì)象 (準(zhǔn)確的說,創(chuàng)建一個(gè)對(duì)象的過程包括分配內(nèi)存和構(gòu)造對(duì)象)。所以,與上例最相似的例子如下:
import java.lang.reflect.*;
public class constructor2 {
public constructor2() {
}
public constructor2(int a, int b) {
System.out.println("a = " + a + " b = " + b);
}
public static void main(String args[]) {
try {
Class cls = Class.forName("constructor2");
Class partypes[] = new Class[2];
partypes[0] = Integer.TYPE;
partypes[1] = Integer.TYPE;
Constructor ct = cls.getConstructor(partypes);
Object arglist[] = new Object[2];
arglist[0] = new Integer(37);
arglist[1] = new Integer(47);
Object retobj = ct.newInstance(arglist);
} catch (Throwable e) {
System.err.println(e);
}
}
}
根據(jù)指定的參數(shù)類型找到相應(yīng)的構(gòu)造函數(shù)并執(zhí)行它,以創(chuàng)建一個(gè)新的對(duì)象實(shí)例。使用這種方法可以在程序運(yùn)行時(shí)動(dòng)態(tài)地創(chuàng)建對(duì)象,而不是在編譯的時(shí)候創(chuàng)建對(duì)象,這一點(diǎn)非常有價(jià)值。
(這里如果使用無參構(gòu)造器創(chuàng)建對(duì)象的話,這可以直接使用Class.forName("...").newInstance();來創(chuàng)建對(duì)象)
8.改變字段(域)的值
reflection 的還有一個(gè)用處就是改變對(duì)象數(shù)據(jù)字段的值。reflection 可以從正在運(yùn)行的程序中根據(jù)名稱找到對(duì)象的字段并改變它,下面的例子可以說明這一點(diǎn):
import java.lang.reflect.*;
public class field2 {
public double d;
public static void main(String args[]) {
try {
Class cls = Class.forName("field2");
Field fld = cls.getField("d");
field2 f2obj = new field2();
System.out.println("d = " + f2obj.d);
fld.setDouble(f2obj, 12.34);
System.out.println("d = " + f2obj.d);
} catch (Throwable e) {
System.err.println(e);
}
}
}
這個(gè)例子中,字段 d 的值被變?yōu)榱?12.34。
9.使用數(shù)組
本文介紹的 reflection 的最后一種用法是創(chuàng)建的操作數(shù)組。數(shù)組在 Java 語言中是一種特殊的類類型,一個(gè)數(shù)組的引用可以賦給 Object 引用。觀察下面的例子看看數(shù)組是怎么工作的:
import java.lang.reflect.*;
public class array1 {
public static void main(String args[]) {
try {
Class cls = Class.forName("java.lang.String");
Object arr = Array.newInstance(cls, 10);
Array.set(arr, 5, "this is a test");
String s = (String) Array.get(arr, 5);
System.out.println(s);
} catch (Throwable e) {
System.err.println(e);
}
}
}
例中創(chuàng)建了 10 個(gè)單位長(zhǎng)度的 String 數(shù)組,為第 5 個(gè)位置的字符串賦了值,最后將這個(gè)字符串從數(shù)組中取得并打印了出來。
下面這段代碼提供了一個(gè)更復(fù)雜的例子:
import java.lang.reflect.*;
public class array2 {
public static void main(String args[]) {
int dims[] = new int[]{5, 10, 15};
Object arr = Array.newInstance(Integer.TYPE, dims);
Object arrobj = Array.get(arr, 3);
Class cls = arrobj.getClass().getComponentType();
System.out.println(cls);
arrobj = Array.get(arrobj, 5);
Array.setInt(arrobj, 10, 37);
int arrcast[][][] = (int[][][]) arr;
System.out.println(arrcast[3][5][10]);
}
}
例中創(chuàng)建了一個(gè) 5 x 10 x 15 的整型數(shù)組,并為處于 [3][5][10] 的元素賦了值為 37。注意,多維數(shù)組實(shí)際上就是數(shù)組的數(shù)組,例如,第一個(gè) Array.get 之后,arrobj 是一個(gè) 10 x 15 的數(shù)組。進(jìn)而取得其中的一個(gè)元素,即長(zhǎng)度為 15 的數(shù)組,并使用 Array.setInt 為它的第 10 個(gè)元素賦值。
注意創(chuàng)建數(shù)組時(shí)的類型是動(dòng)態(tài)的,在編譯時(shí)并不知道其類型。
摘要: 轉(zhuǎn)自其他博客《收藏》
(1) 選擇最有效率的表名順序(只在基于規(guī)則的優(yōu)化器中有效):
ORACLE的解析器按照從右到左的順序處理FROM子句中的表名,F(xiàn)ROM子句中寫在最后的表(基礎(chǔ)表 driving table)將被最先處理,在FROM子句中包含多個(gè)表的情況下,你必須選擇記錄條數(shù)最少的表作為基礎(chǔ)表。如果有3個(gè)以上的表連接查詢,...
閱讀全文
1,使用Spring 的 ActionSupport
2,使用Spring 的 DelegatingRequestProcessor 類。
3,全權(quán)委托。
無論用那種方法來整合第一步就是要為struts來裝載spring的應(yīng)用環(huán)境。 就是在 struts 中加入一個(gè)插件。
struts-config.xml中
<plug-in className="org.springframework.web.struts.ContextLoaderPlugIn">
<set-property property="contextConfigLocation" value="/WEB-INF/applicationContext.xml"/>
</plug-in>
|
spring 的配置文件被作為參數(shù)配置進(jìn)來。這樣可以省略對(duì)web.xml 文件中的配置。確保你的applicationContext.xml 在WEB-INF目錄下面
1、使用Spring的ActionSupport .
Spring 的ActionSupport 繼承至org.apache.struts.action.Action
ActionSupport的子類可以或得 WebApplicationContext類型的全局變量。通過getWebApplicationContext()可以獲得這個(gè)變量。
這是一個(gè) servlet 的代碼:
public class LoginAction extends org.springframework.web.struts.ActionSupport {
public ActionForward execute(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response) {
LoginForm loginForm = (LoginForm) form;// TODO Auto-generated method stub
//獲得 WebApplicationContext 對(duì)象
WebApplicationContext ctx = this.getWebApplicationContext();
LoginDao dao = (LoginDao) ctx.getBean("loginDao");
User u = new User();
u.setName(loginForm.getName());
u.setPwd(loginForm.getPwd());
if(dao.checkLogin(u)){
return mapping.findForward("success");
}else{
return mapping.findForward("error");
}
}
}
applicationContext.xml 中的配置
<beans>
<bean id="loginDao" class="com.cao.dao.LoginDao"/>
</beans>
|
這中配置方式同直接在web.xml文件配置差別不大。
注意:Action繼承自 org.springframework.web.struts.ActionSupport 使得struts和spring耦合在一起。
但實(shí)現(xiàn)了表示層和業(yè)務(wù)邏輯層的解耦(LoginDao dao = (LoginDao) ctx.getBean("loginDao"))。
2、使用Spring 的 DelegatingRequestProcessor 類
DelegatingRequestProcessor 繼承自 org.apache.struts.action.RequestProcessor 并覆蓋了里面的方法。
sturts-config.xml 中
processorClass="org.springframework.web.struts.DelegatingRequestProcessor"/> 通過 來替代
org.apache.struts.action.RequestProcessor 的請(qǐng)求處理。
public class LoginAction extends Action {
//利用spring來注入這個(gè)對(duì)象。
private LoginDao dao ;
public void setDao(LoginDao dao) {
System.out.println("執(zhí)行注入");
this.dao = dao;
}
public LoginDao getDao() {
return dao;
}
public ActionForward execute(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response) {
LoginForm loginForm = (LoginForm) form;// TODO Auto-generated method stub
//這樣一改這行代碼似乎沒有必要了。
//WebApplicationContext ctx = this.getWebApplicationContext();
//LoginDao dao = (LoginDao) ctx.getBean("loginDao");
User u = new User();
u.setName(loginForm.getName());
u.setPwd(loginForm.getPwd());
//直接用dao來調(diào)用spring會(huì)將這個(gè)對(duì)象實(shí)例化。
if(dao.checkLogin(u)){
return mapping.findForward("success");
}else{
return mapping.findForward("error");
}
}
}
這里的。
LoginAction extends Action 說明 struts沒有和spring 耦合。
看一下
applicationContext.xml 中的配置。
<beans>
<bean id="loginDao" class="com.cao.dao.LoginDao"/>
<bean name="/login" class="com.cao.struts.action.LoginAction">
<property name="dao">
<ref local="loginDao"/>
</property>
</bean>
</beans>
|
這里 name="/login" 與struts 中的path匹配
class="com.cao.struts.action.LoginAction" 與struts 中的type匹配
還要為 LoginAction 提供必要的setXXX方法。 獲得ApplicationCotext和依賴注入的工作都在DelegatingRequestProcessor中完成。
3,全權(quán)委托:
Action 的創(chuàng)建和對(duì)象的依賴注入全部由IOC容器來完成。使用Spring的DelegatingAcionProxy來幫助實(shí)現(xiàn)代理的工作
org.springframework.web.struts.DelegatingActiongProxy繼承于org.apache.struts.action.Action .
全權(quán)委托的配置方式同 方式 2 類似 (applcationContext.xml文件的配置和 Action類的實(shí)現(xiàn)方式相同)。
<struts-config>
<data-sources />
<form-beans >
<form-bean name="loginForm"
type="com.cao.struts.form.LoginForm" />
</form-beans>
<global-exceptions />
<global-forwards />
<action-mappings >
<!-- type指向的是spring 的代理類 -->
<action
attribute="loginForm"
input="login.jsp"
name="loginForm"
path="/login"
scope="request"
type="org.springframework.web.struts.DelegatingActionProxy" >
<forward name="success" path="/ok.jsp" />
<forward name="error" path="/error.jsp" />
</action>
</action-mappings>
<message-resources parameter="com.cao.struts.ApplicationResources" />
<plug-in className=
"org.springframework.web.struts.ContextLoaderPlugIn">
<set-property property="contextConfigLocation"
value="/WEB-INF/applicationContext.xml"/>
</plug-in>
</struts-config>
不同之處
1, <action>中 type指向的是spring 的代理類
2, 去掉struts-config.xml中 <controller >
|
三種整和方式中我們優(yōu)先選用 全權(quán)委托的方式。
理由:
1,第一種使得過多的耦合了Spring和Action .
2,RequestProcessor類已經(jīng)被代理 如果要再實(shí)現(xiàn)自己的實(shí)現(xiàn)方式(如:編碼處理)怕有點(diǎn)麻煩。
總結(jié)一下:
整合工作中的步驟:
1,修改struts-config.xml
2, 配置applicationContext.xml
3, 為Action添加get/set方法 來獲得依賴注入的功能。
最近比較忙,但是每天網(wǎng)上還是的堅(jiān)持學(xué)點(diǎn),不積小流,無以成江河。
今天學(xué)jQuery對(duì)象訪問:
1.each(callback) 該方法以每一個(gè)匹配的元素作為上下文來執(zhí)行一個(gè)函數(shù),
在每次執(zhí)行函數(shù)時(shí),都會(huì)給函數(shù)傳遞一個(gè)表示作為執(zhí)行環(huán)境的元素在匹配的元素集合中所處位置的數(shù)字值作為參數(shù)(從0開始的int)
返回‘false’將停止循環(huán)(相當(dāng)于普通循環(huán)中使用的‘break’)
返回‘true’將跳至下一個(gè)循環(huán),(相當(dāng)于在普通的循環(huán)中使用‘continue’)
參數(shù):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
都可以勇于得到j(luò)Query對(duì)象中元素的個(gè)數(shù),
返回: 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)
取得其中一個(gè)匹配元素,index表示取得第幾個(gè)匹配的元素
返回值:Element
HTML代碼:
<img src="test1.jpg"/><img src="test2.jpg"/>
jQuery代碼:
$("img").get(0);
result:
[<img src="test1.jpg"/>]
5.index(subject)
搜索與參數(shù)表示的對(duì)象匹配的元素,并返回相應(yīng)元素的索引值,
如果哦找到了匹配的元素,從0開始返回;如果沒有找到匹配的元素,返回-1
返回值;
Number
參數(shù):
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
備注:
今天在瀏覽別人博客的時(shí)候看到的,收藏。
有時(shí)候,我們頁面當(dāng)中并不需要把要用到的JS全部加載出來,
這會(huì)使頁面加載時(shí)速度變慢~~~如果能按需加載,那能提高不少性能...也能節(jié)約不少流量~~~給用戶帶來好的體驗(yàn)~~
好比說,當(dāng)某個(gè)JS效果是觸發(fā)事件才顯示的...這個(gè)效果被封閉在一個(gè)JS中,,我想大家經(jīng)常這樣做吧~~這時(shí)候,我們能按需加載那就不必在頁面載入時(shí)去加載JS文件~~~這在jquery插件中很多。
用法:
1 , 當(dāng)在需要的時(shí)候再加載所需的javascript和css文件。
$.include('file/test.js')或$.include('file/test.css')
2, 當(dāng)然若你一次想加載多個(gè)文件你也可以這樣寫:
$.include(['file/test.js','file/test.css'])。
3, 因?yàn)檫@兩個(gè)文件的路徑相同,所以可以先指定路徑再加載所有文件:
$.ImportBasePath = 'file/';
$.include(['test.css','test.js']);
4, 你還可以加載完文件后執(zhí)行回調(diào)函數(shù)
$.include("file/test.css",function(){
alert("加載css后執(zhí)行");
});
插件下載地址:http://www.94this.com.cn/myCode/jqueryIncludefile/jqueryIncludefile.rar
注:jquery 自帶了有一個(gè)異步請(qǐng)求的方法,$.getScript ,可以異步加到JS并執(zhí)行
jQuery.getScript(url,[callback])
通過 HTTP GET 請(qǐng)求載入并執(zhí)行一個(gè) JavaScript 文件。
jQuery 1.2 版本之前,getScript 只能調(diào)用同域 JS 文件。 1.2中,您可以跨域調(diào)用 JavaScript 文件。注意:Safari 2 或更早的版本不能在全局作用域中同步執(zhí)行腳本。如果通過 getScript 加入腳本,請(qǐng)加入延時(shí)函數(shù)。
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
參數(shù)
url (String) : 待載入 JS 文件地址。
callback (Function) : (可選) 成功載入后回調(diào)函數(shù)。
示例
載入 jQuery 官方顏色動(dòng)畫插件 成功后綁定顏色變化動(dòng)畫。
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);
});
});
加載并執(zhí)行 test.js。
jQuery 代碼:
$.getScript("test.js");
加載并執(zhí)行 test.js ,成功后顯示信息。
jQuery 代碼:
$.getScript("test.js", function(){
alert("Script loaded and executed.");
});
jsp文件上傳大多采用采用開源項(xiàng)目來簡(jiǎn)化處理,這里列出常用的兩個(gè)jar包的實(shí)現(xiàn),并進(jìn)行比較,說明他們的優(yōu)缺點(diǎn)和應(yīng)該注意的問題。
Commons FileUpload,可以在http://jakarta.apache.org/commons/fileupload/下載,這個(gè)包需要Commons IO的支持,可以在http://jakarta.apache.org/commons/io/下載
com.oreilly.servlet,可以在http://www.servlets.com/cos/下載
Commons FileUpload提供三種文件上傳處理方式,DiskFileUpload、ServletFileUpload和PortletFileUpload三種方式,其中DiskFileUpload已經(jīng)在javadoc下已經(jīng)被標(biāo)記為過期的方法,建議用ServletFileUpload代替,而PortletFileUpload需要配合portlet-api來使用,所以這里我們只介紹ServletFileUpload,并且這個(gè)也是最常用的。
com.oreilly.servlet也提供了三種文件上傳的處理方式,MultipartWrapper、MultipartRequest和MultipartParser三種方式,其中MultipartWrapper和MultipartRequest的用法基本相同,并且沒有MultipartRequest提供的操作多,所以這里介紹MultipartRequest,MultipartParser和前兩者有些不同,可以用來處理某些特殊情況,例如表單中有兩個(gè)同名的文件上傳選擇框。
我們暫時(shí)稱三面三種文件上傳方式分別為: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("文件上傳發(fā)生錯(cuò)誤" + 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("文件沒有選擇 或 文件內(nèi)容為空");
}
}
}
}
}
}
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、中文問題:
三種凡是都可以通過自己的方法來設(shè)置encoding為gbk開處理和解決中文問題,包括初始化的時(shí)候傳入gbk作為參數(shù),或是是初始化后通過setEncoding的方式來實(shí)現(xiàn)。
另外ServletFileUpload方式也可以通過request.setCharacterEncoding("gbk");的方式來實(shí)現(xiàn),而其它兩種方式不支持這種方式。
問題2、文件大小限制
ServletFileUpload方式可以設(shè)置文件大小限制,也可以不用設(shè)置,例子中的upload.setSizeMax(2000000)就可以注釋掉。如果設(shè)置upload.setSizeMax(-1),表明不限制上傳的大小。文檔中沒有指明默認(rèn)的限制的多少,我在不設(shè)置的情況下上傳了一個(gè)9M的東西,可以上傳,估計(jì)默認(rèn)是不限制大小的。
而MultipartRequest方式和MultipartParser方式是必須設(shè)置文件的上傳文件的大小限制的,如果不設(shè)置,默認(rèn)是1M的大小限制。
問題3、文件上傳發(fā)生錯(cuò)誤
如果文件上傳過程中發(fā)生任何錯(cuò)誤,或者是文件的大小超出了范圍,系統(tǒng)都將拋出錯(cuò)誤。
ServletFileUpload方式在upload.parseRequest(request)時(shí)拋出錯(cuò)誤
MultipartRequest方式在new MultipartRequest(。。。)時(shí)拋出錯(cuò)誤
MultipartParser方式在new MultipartParser(。。。)時(shí)拋出錯(cuò)誤
問題4、上傳同名文件時(shí),他們保存到臨時(shí)目錄是的沖突問題
ServletFileUpload方式,不會(huì)有沖突,系統(tǒng)會(huì)把上傳得文件按照一定的規(guī)則重新命名,保證不會(huì)沖突
MultipartParser方式,會(huì)產(chǎn)生沖突,系統(tǒng)會(huì)把文件按照上傳時(shí)的文件名,保存到臨時(shí)目錄下,如果兩個(gè)用會(huì)同時(shí)上傳文件名相同的文件,那么就可能會(huì)產(chǎn)生沖突,一方把另一方的臨時(shí)文件給替換了。
MultipartRequest方式,在初始化時(shí)如果提供了一個(gè)名稱轉(zhuǎn)換策略,就不會(huì)有沖突,如果不提桶,就會(huì)有沖突。在上面的例子中我們提供了一個(gè)new DefaultFileRenamePolicy()保證了文件名不會(huì)有沖突發(fā)生。
問題5:表單中有兩個(gè)同名的文件上傳選擇框,就像我們例子中的myfile一樣,每個(gè)表單中有兩個(gè)name=“myfile”的上傳框
ServletFileUpload方式,可以處理,可以分別得到他們各自的文件,
MultipartRequest方式,不可以處理,會(huì)發(fā)生沖突,會(huì)有一個(gè)上傳框的文件覆蓋了另外一個(gè)。
MultipartParser方式,可以處理,可以分別得到他們各自的文件,
備注:
代碼比較亂,主要是為了說明他們間的區(qū)別。他們的詳細(xì)地使用說明還是要參考他的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
//先鎖表,然后再判斷是否已經(jīng)存在數(shù)據(jù),以防止出現(xiàn)重復(fù)行
String lockSql = "update YHZHMX set YHZHMX_DJBH=YHZHMX_DJBH where 1=2";
//上面的語法貌似不好用.故采用下面的語法
lockSql = "SELECT * FROM YHZHMX FOR UPDATE";
一、jquery核心函數(shù)的學(xué)習(xí)
1、
jQuery(exp,[context]),這個(gè)函數(shù)接受一個(gè)包含css選擇器的字符串,然后用這個(gè)字符串去匹配一組元素,通俗的講,exp參數(shù)是要匹配的表達(dá)式,context是匹配的范圍,可以是dom元素,文檔或者jquery對(duì)象。
jQuery的核心功能都是通過這個(gè)函數(shù)實(shí)現(xiàn)的,
例子:
a.找到所有p元素,并且這些元素都是div元素的子元素
HTML代碼:<p>guoxzh</p><div><p>guoxiaozheng</p></div><p>guoxzh</p.
jQuery代碼:$("div>p")
b.在文檔的第一個(gè)表單中,查找所有的當(dāng)選按鈕
HTML代碼:是帶有type值為radio的input元素
JQuery代碼:$("input:radio",document.forms[0]);
c.在一個(gè)有AJAX返回的xml文檔中,查找所有的div元素
$("div",xml.responseXML);
2.
jQuery(html)根據(jù)提供的原始的HTMl標(biāo)記字符串,動(dòng)態(tài)創(chuàng)建有jQuery對(duì)象包含的Dom元素,你可以傳遞一個(gè)手寫的 HTML 字符串,或者由某些模板引擎或插件創(chuàng)建的字符串,也可以是通過 AJAX 加載過來的字符串。但是在你創(chuàng)建 input 元素的時(shí)會(huì)有限制,可以參考第二個(gè)示例。當(dāng)然這個(gè)字符串可以包含斜杠 (比如一個(gè)圖像地址),還有反斜杠。當(dāng)你創(chuàng)建單個(gè)元素時(shí),請(qǐng)使用閉合標(biāo)簽或 XHTML 格式。例如,創(chuàng)建一個(gè) span ,可以用 $("<span/>") 或 $("<span></span>") ,但不推薦 $("<span>");
返回值:
JQuery
參數(shù):
用于動(dòng)態(tài)創(chuàng)建dom元素的HTML標(biāo)簽的字符串,
例子:
a.動(dòng)態(tài)創(chuàng)建一個(gè)div元素,追加到body里
jQuery代碼:
$("<div><input type="text" name="name" value=""></div>").appendTo("body");
b.創(chuàng)建一個(gè)<input>元素必須同時(shí)設(shè)定type屬性,
jQuery代碼:
IE中無效
$("<input>").attr("type","checkbox");
在IE中有效
$("<input type='checkbox'>");
3.jQuery(element)將一個(gè)或多個(gè)元素DOM元素轉(zhuǎn)化為jQuery對(duì)象
這個(gè)函數(shù)也可以接收XML文檔和Window對(duì)象(雖然它們不是DOM元素)作為有效的參數(shù)。
返回值:jQuery
例子:
a.設(shè)置頁面的背景色
jQuery代碼:
$("document.body").css("background","black");
b.隱藏一個(gè)表單中所有元素
jQuery代碼:
$("myForm.elements").hide();
Java棧與堆
----對(duì)這兩個(gè)概念的理解總是忘記,今天從網(wǎng)上搜到一篇比較好的文章收藏
1. 棧(stack)與堆(heap)都是Java用來在Ram中存放數(shù)據(jù)的地方。與C++不同,Java自動(dòng)管理?xiàng):投眩绦騿T不能直接地設(shè)置棧或堆。
2. 棧的優(yōu)勢(shì)是,存取速度比堆要快,僅次于直接位于CPU中的寄存器。但缺點(diǎn)是,存在棧中的數(shù)據(jù)大小與生存期必須是確定的,缺乏靈活性。另外,棧數(shù)據(jù)可以共享,詳見第3點(diǎn)。堆的優(yōu)勢(shì)是可以動(dòng)態(tài)地分配內(nèi)存大小,生存期也不必事先告訴編譯器,Java的垃圾收集器會(huì)自動(dòng)收走這些不再使用的數(shù)據(jù)。但缺點(diǎn)是,由于要在運(yùn)行時(shí)動(dòng)態(tài)分配內(nèi)存,存取速度較慢。
3. Java中的數(shù)據(jù)類型有兩種。
一種是基本類型(primitive types), 共有8種,即int, short, long, byte, float, double, boolean, char(注意,并沒有string的基本類型)。這種類型的定義是通過諸如int a = 3; long b = 255L;的形式來定義的,稱為自動(dòng)變量。值得注意的是,自動(dòng)變量存的是字面值,不是類的實(shí)例,即不是類的引用,這里并沒有類的存在。如int a = 3; 這里的a是一個(gè)指向int類型的引用,指向3這個(gè)字面值。這些字面值的數(shù)據(jù),由于大小可知,生存期可知(這些字面值固定定義在某個(gè)程序塊里面,程序塊退出后,字段值就消失了),出于追求速度的原因,就存在于棧中。
另外,棧有一個(gè)很重要的特殊性,就是存在棧中的數(shù)據(jù)可以共享。假設(shè)我們同時(shí)定義:
復(fù)制內(nèi)容到剪貼板代碼:
int a = 3;
int b = 3;
編譯器先處理int a = 3;首先它會(huì)在棧中創(chuàng)建一個(gè)變量為a的引用,然后查找有沒有字面值為3的地址,沒找到,就開辟一個(gè)存放3這個(gè)字面值的地址,然后將a指向3的地址。接著處理int b = 3;在創(chuàng)建完b的引用變量后,由于在棧中已經(jīng)有3這個(gè)字面值,便將b直接指向3的地址。這樣,就出現(xiàn)了a與b同時(shí)均指向3的情況。
特別注意的是,這種字面值的引用與類對(duì)象的引用不同。假定兩個(gè)類對(duì)象的引用同時(shí)指向一個(gè)對(duì)象,如果一個(gè)對(duì)象引用變量修改了這個(gè)對(duì)象的內(nèi)部狀態(tài),那么另一個(gè)對(duì)象引用變量也即刻反映出這個(gè)變化。相反,通過字面值的引用來修改其值,不會(huì)導(dǎo)致另一個(gè)指向此字面值的引用的值也跟著改變的情況。如上例,我們定義完a與b的值后,再令a=4;那么,b不會(huì)等于4,還是等于3。在編譯器內(nèi)部,遇到a=4;時(shí),它就會(huì)重新搜索棧中是否有4的字面值,如果沒有,重新開辟地址存放4的值;如果已經(jīng)有了,則直接將a指向這個(gè)地址。因此a值的改變不會(huì)影響到b的值。
另一種是包裝類數(shù)據(jù),如Integer, String, Double等將相應(yīng)的基本數(shù)據(jù)類型包裝起來的類。這些類數(shù)據(jù)全部存在于堆中,Java用new()語句來顯示地告訴編譯器,在運(yùn)行時(shí)才根據(jù)需要?jiǎng)討B(tài)創(chuàng)建,因此比較靈活,但缺點(diǎn)是要占用更多的時(shí)間。 4. String是一個(gè)特殊的包裝類數(shù)據(jù)。即可以用String str = new String("abc");的形式來創(chuàng)建,也可以用String str = "abc";的形式來創(chuàng)建(作為對(duì)比,在JDK 5.0之前,你從未見過Integer i = 3;的表達(dá)式,因?yàn)轭惻c字面值是不能通用的,除了String。而在JDK 5.0中,這種表達(dá)式是可以的!因?yàn)榫幾g器在后臺(tái)進(jìn)行Integer i = new Integer(3)的轉(zhuǎn)換)。前者是規(guī)范的類的創(chuàng)建過程,即在Java中,一切都是對(duì)象,而對(duì)象是類的實(shí)例,全部通過new()的形式來創(chuàng)建。Java中的有些類,如DateFormat類,可以通過該類的getInstance()方法來返回一個(gè)新創(chuàng)建的類,似乎違反了此原則。其實(shí)不然。該類運(yùn)用了單例模式來返回類的實(shí)例,只不過這個(gè)實(shí)例是在該類內(nèi)部通過new()來創(chuàng)建的,而getInstance()向外部隱藏了此細(xì)節(jié)。那為什么在String str = "abc";中,并沒有通過new()來創(chuàng)建實(shí)例,是不是違反了上述原則?其實(shí)沒有。
5. 關(guān)于String str = "abc"的內(nèi)部工作。Java內(nèi)部將此語句轉(zhuǎn)化為以下幾個(gè)步驟:
(1)先定義一個(gè)名為str的對(duì)String類的對(duì)象引用變量:String str;
(2)在棧中查找有沒有存放值為"abc"的地址,如果沒有,則開辟一個(gè)存放字面值為"abc"的地址,接著創(chuàng)建一個(gè)新的String類的對(duì)象o,并將o的字符串值指向這個(gè)地址,而且在棧中這個(gè)地址旁邊記下這個(gè)引用的對(duì)象o。如果已經(jīng)有了值為"abc"的地址,則查找對(duì)象o,并返回o的地址。
(3)將str指向?qū)ο髈的地址。
值得注意的是,一般String類中字符串值都是直接存值的。但像String str = "abc";這種場(chǎng)合下,其字符串值卻是保存了一個(gè)指向存在棧中數(shù)據(jù)的引用!
為了更好地說明這個(gè)問題,我們可以通過以下的幾個(gè)代碼進(jìn)行驗(yàn)證。
復(fù)制內(nèi)容到剪貼板代碼:
String str1 = "abc";
String str2 = "abc";
System.out.println(str1==str2); //true
注意,我們這里并不用str1.equals(str2);的方式,因?yàn)檫@將比較兩個(gè)字符串的值是否相等。==號(hào),根據(jù)JDK的說明,只有在兩個(gè)引用都指向了同一個(gè)對(duì)象時(shí)才返回真值。而我們?cè)谶@里要看的是,str1與str2是否都指向了同一個(gè)對(duì)象。
結(jié)果說明,JVM創(chuàng)建了兩個(gè)引用str1和str2,但只創(chuàng)建了一個(gè)對(duì)象,而且兩個(gè)引用都指向了這個(gè)對(duì)象。
我們?cè)賮砀M(jìn)一步,將以上代碼改成:
復(fù)制內(nèi)容到剪貼板代碼:
String str1 = "abc";
String str2 = "abc";
str1 = "bcd";
System.out.println(str1 + "," + str2); //bcd, abc
System.out.println(str1==str2); //false
這就是說,賦值的變化導(dǎo)致了類對(duì)象引用的變化,str1指向了另外一個(gè)新對(duì)象!而str2仍舊指向原來的對(duì)象。上例中,當(dāng)我們將str1的值改為"bcd"時(shí),JVM發(fā)現(xiàn)在棧中沒有存放該值的地址,便開辟了這個(gè)地址,并創(chuàng)建了一個(gè)新的對(duì)象,其字符串的值指向這個(gè)地址。
事實(shí)上,String類被設(shè)計(jì)成為不可改變(immutable)的類。如果你要改變其值,可以,但JVM在運(yùn)行時(shí)根據(jù)新值悄悄創(chuàng)建了一個(gè)新對(duì)象,然后將這個(gè)對(duì)象的地址返回給原來類的引用。這個(gè)創(chuàng)建過程雖說是完全自動(dòng)進(jìn)行的,但它畢竟占用了更多的時(shí)間。在對(duì)時(shí)間要求比較敏感的環(huán)境中,會(huì)帶有一定的不良影響。
再修改原來代碼:
復(fù)制內(nèi)容到剪貼板代碼:
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這個(gè)對(duì)象的引用直接指向str1所指向的對(duì)象(注意,str3并沒有創(chuàng)建新對(duì)象)。當(dāng)str1改完其值后,再創(chuàng)建一個(gè)String的引用str4,并指向因str1修改值而創(chuàng)建的新的對(duì)象。可以發(fā)現(xiàn),這回str4也沒有創(chuàng)建新的對(duì)象,從而再次實(shí)現(xiàn)棧中數(shù)據(jù)的共享。
我們?cè)俳又匆韵碌拇a。
復(fù)制內(nèi)容到剪貼板代碼:
String str1 = new String("abc");
String str2 = "abc";
System.out.println(str1==str2); //false 創(chuàng)建了兩個(gè)引用。創(chuàng)建了兩個(gè)對(duì)象。兩個(gè)引用分別指向不同的兩個(gè)對(duì)象。
String str1 = "abc";
String str2 = new String("abc");
System.out.println(str1==str2); //false
創(chuàng)建了兩個(gè)引用。創(chuàng)建了兩個(gè)對(duì)象。兩個(gè)引用分別指向不同的兩個(gè)對(duì)象。
以上兩段代碼說明,只要是用new()來新建對(duì)象的,都會(huì)在堆中創(chuàng)建,而且其字符串是單獨(dú)存值的,即使與棧中的數(shù)據(jù)相同,也不會(huì)與棧中的數(shù)據(jù)共享。
6. 數(shù)據(jù)類型包裝類的值不可修改。不僅僅是String類的值不可修改,所有的數(shù)據(jù)類型包裝類都不能更改其內(nèi)部的值。
7. 結(jié)論與建議:
(1)我們?cè)谑褂弥T如String str = "abc";的格式定義類時(shí),總是想當(dāng)然地認(rèn)為,我們創(chuàng)建了String類的對(duì)象str。擔(dān)心陷阱!對(duì)象可能并沒有被創(chuàng)建!唯一可以肯定的是,指向String類的引用被創(chuàng)建了。至于這個(gè)引用到底是否指向了一個(gè)新的對(duì)象,必須根據(jù)上下文來考慮,除非你通過new()方法來顯要地創(chuàng)建一個(gè)新的對(duì)象。因此,更為準(zhǔn)確的說法是,我們創(chuàng)建了一個(gè)指向String類的對(duì)象的引用變量str,這個(gè)對(duì)象引用變量指向了某個(gè)值為"abc"的String類。清醒地認(rèn)識(shí)到這一點(diǎn)對(duì)排除程序中難以發(fā)現(xiàn)的bug是很有幫助的。
(2)使用String str = "abc";的方式,可以在一定程度上提高程序的運(yùn)行速度,因?yàn)镴VM會(huì)自動(dòng)根據(jù)棧中數(shù)據(jù)的實(shí)際情況來決定是否有必要?jiǎng)?chuàng)建新對(duì)象。而對(duì)于String str = new String("abc");的代碼,則一概在堆中創(chuàng)建新對(duì)象,而不管其字符串值是否相等,是否有必要?jiǎng)?chuàng)建新對(duì)象,從而加重了程序的負(fù)擔(dān)。這個(gè)思想應(yīng)該是享元模式的思想,但JDK的內(nèi)部在這里實(shí)現(xiàn)是否應(yīng)用了這個(gè)模式,不得而知。
(3)當(dāng)比較包裝類里面的數(shù)值是否相等時(shí),用equals()方法;當(dāng)測(cè)試兩個(gè)包裝類的引用是否指向同一個(gè)對(duì)象時(shí),用==。
(4)由于String類的immutable性質(zhì),當(dāng)String變量需要經(jīng)常變換其值時(shí),應(yīng)該考慮使用StringBuffer類,以提高程序效率。