亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

java string的一些細(xì)節(jié)剖析

 更新時(shí)間:2012年11月14日 14:13:22   作者:  
首先說明這里指的是Java中String的一些細(xì)節(jié)部分,需要的朋友可以參考
首先說明這里指的是Java中的String,雖然我已經(jīng)決定轉(zhuǎn)戰(zhàn)C/C++了,但是因?yàn)榻裉炫龅揭粋€(gè)問題,還是來看一下。String的定義如下:
復(fù)制代碼 代碼如下:

public final class String
{
private final char value[]; // 保存的字符串
private final int offset; // 開始的位置
private final int count; // 字符數(shù)目
private int hash; // 緩存的hash值
......
}

在Debug的時(shí)候可以看到保存的值如下:
 
需要說明一下的是:如果沒有調(diào)用過hashCode(),那么hash的值為0。容易知道這里的value也就是真正保存的字符串的值(也就是“字符串測(cè)試”)的char數(shù)組,而每個(gè)char的值是多少呢?很容易驗(yàn)證:Unicode。
到這里大家也就猜到我們常用的subString是怎么實(shí)現(xiàn)的了:如果是讓我們實(shí)現(xiàn)的話讓new String使用相同的value(char數(shù)組),只修改offset和count就可以了。這樣的話既省空間又快(不需要拷貝),而事實(shí)上也是這樣的:
復(fù)制代碼 代碼如下:

public String substring(int beginIndex) {
return substring(beginIndex, count);
}
public String substring(int beginIndex, int endIndex) {
......
return ((beginIndex == 0) && (endIndex == count)) ? this :
new String(offset + beginIndex, endIndex - beginIndex, value);
}
String(int offset, int count, char value[]) {
this.value = value;
this.offset = offset;
this.count = count;
}

既然是在討論字符串,JVM默認(rèn)使用的是什么編碼呢?通過調(diào)試可以發(fā)現(xiàn):
復(fù)制代碼 代碼如下:

public static Charset defaultCharset() {
if (defaultCharset == null) {
synchronized (Charset.class) {
java.security.PrivilegedAction pa = new GetPropertyAction("file.encoding");
String csn = (String)AccessController.doPrivileged(pa);
Charset cs = lookup(csn);
if (cs != null)
defaultCharset = cs;
else
defaultCharset = forName("UTF-8");
}
}

其中defaultCharset的值可以通過:
  -Dfile.encoding=utf-8
進(jìn)行設(shè)置。當(dāng)然如果你想設(shè)置為“abc”也可以,但會(huì)默認(rèn)設(shè)置為UTF-8??梢酝ㄟ^System.getProperty("file.encoding")來看具體的值??磀efaultCharset是為什么呢?因?yàn)榫W(wǎng)絡(luò)傳輸?shù)倪^程中應(yīng)該都是byte數(shù)組,不同的編碼方式得到的byte數(shù)組可能是不相同的。所以,我們得知道編碼方式是怎么得到的吧?具體得到byte數(shù)組的方法也就是我們下面重點(diǎn)要看的getBytes了,它最終要調(diào)用的是CharsetEncoder的encode方法,如下:
復(fù)制代碼 代碼如下:

public final CoderResult encode(CharBuffer in, ByteBuffer out, boolean endOfInput) {
int newState = endOfInput ? ST_END : ST_CODING;
if ((state != ST_RESET) && (state != ST_CODING) && !(endOfInput && (state == ST_END)))
throwIllegalStateException(state, newState);
state = newState;
for (;;) {
CoderResult cr;
try {
cr = encodeLoop(in, out);
} catch (BufferUnderflowException x) {
throw new CoderMalfunctionError(x);
} catch (BufferOverflowException x) {
throw new CoderMalfunctionError(x);
}
if (cr.isOverflow())
return cr;
if (cr.isUnderflow()) {
if (endOfInput && in.hasRemaining()) {
cr = CoderResult.malformedForLength(in.remaining());
} else {
return cr;
}
}
CodingErrorAction action = null;
if (cr.isMalformed())
action = malformedInputAction;
else if (cr.isUnmappable())
action = unmappableCharacterAction;
else
assert false : cr.toString();
if (action == CodingErrorAction.REPORT)
return cr;
if (action == CodingErrorAction.REPLACE) {
if (out.remaining() < replacement.length)
return CoderResult.OVERFLOW;
out.put(replacement);
}
if ((action == CodingErrorAction.IGNORE) || (action == CodingErrorAction.REPLACE)) {
in.position(in.position() + cr.length());
continue;
}
assert false;
}
}

當(dāng)然首先會(huì)根據(jù)需要的編碼格式選擇對(duì)應(yīng)的CharsetEncoder,而最主要的是不同的CharsetEncoder實(shí)現(xiàn)了不同的encodeLoop方法。這里可能會(huì)不明白為什么這里有個(gè)for(;;)?其實(shí)看CharsetEncoder所處的包(nio)和它的參數(shù)也就大概明白了:這個(gè)函數(shù)是可以處理流的(雖然我們這里使用的時(shí)候不會(huì)循環(huán))。
在encodeLoop方法中會(huì)將盡可能多的char轉(zhuǎn)換為byte,new String差不多就是上面的逆過程。
在實(shí)際的開發(fā)過程中經(jīng)常會(huì)遇到亂碼問題:
在上傳文件的時(shí)候取到文件名;
JS傳到后端的字符串;
首先先嘗試下下面代碼的的運(yùn)行結(jié)果:
復(fù)制代碼 代碼如下:

public static void main(String[] args) throws Exception {
String str = "字符串";
// -41 -42 -73 -5 -76 -82
printArray(str.getBytes());
// -27 -83 -105 -25 -84 -90 -28 -72 -78
printArray(str.getBytes("utf-8"));
// ???
System.out.println(new String(str.getBytes(), "utf-8"));
// 瀛楃涓?
System.out.println(new String(str.getBytes("utf-8"), "gbk"));
// 字符??
System.out.println(new String("瀛楃涓?".getBytes("gbk"), "utf-8"));
// -41 -42 -73 -5 63 63
printArray(new String("瀛楃涓?".getBytes("gbk"), "utf-8").getBytes());
}
public static void printArray(byte[] bs){
for(int i = 0; i < bs.length; i++){
System.out.print(bs[i] + " ");
}
System.out.println();
}

在程序中的注釋中說明了輸出結(jié)果:
因?yàn)镚BK中2個(gè)byte表示一個(gè)漢字,所以就有了6個(gè)byte;
因?yàn)閁TF-8中3個(gè)byte表示一個(gè)漢字,所以就有了9個(gè)byte;
因?yàn)橥ㄟ^無法通過GBK生成的byte數(shù)組再根據(jù)UTF-8的規(guī)則去生成字符串,所以顯示???;
這個(gè)是經(jīng)常遇到亂碼的原因,GBK使用UTF-8生成的byte能生成字符串;
雖然上面生成的是亂碼,但是電腦并不這么認(rèn)為,所以還是能通過getBytes得到字節(jié)數(shù)組,而這個(gè)數(shù)組中是utf-8是可以識(shí)別的;
最后的兩個(gè)63(?)應(yīng)該是encode填充的(或者是字節(jié)不夠直接填充的,這個(gè)地方?jīng)]有細(xì)看);
GBK和UTF-8對(duì)于因?yàn)樽帜负蛿?shù)字的編碼是相同的,所以在這幾種字符的處理上是不會(huì)出現(xiàn)亂碼的,但是他們對(duì)漢字的編碼確實(shí)不一樣的,這就是很多問題的起源,看下面代碼:
  new String(new String("我們".getBytes("UTF-8"), "GBK").getBytes("GBK"), "UTF-8);
顯然這段代碼的結(jié)果是“我們”,但是對(duì)我們有什么用?首先我們注意到:
  new String("我們".getBytes("UTF-8"), "GBK");
這段代碼的結(jié)果是亂碼,而且很多的亂碼都是“亂成這樣的”。但是要記?。哼@里的亂是對(duì)我們而言,對(duì)電腦來說無所謂“亂”與“不亂”,它在我們幾乎放棄的時(shí)候還能從亂碼中通過“getBytes("GBK")”得到它的“主心骨”,然后我們就可以用“主心骨”還原出原來的字符串。
貌似上面的這段代碼能解決“GBK”和“UTF-8”之間的亂碼問題,但是這種解決方法也只限于一種特殊情況:所有連續(xù)漢字的個(gè)數(shù)都是偶數(shù)個(gè)!原因在上面已經(jīng)說過了,這里就不贅述了。
那么怎么解決這個(gè)問題呢?
第一種解決方法:encodeURI
為什么要用這種方法呢?原因很簡(jiǎn)單:GBK和UTF-8對(duì)于%、數(shù)字、字母的編碼是統(tǒng)一的,所以在傳輸encode之后的串可以100%保證在這兩種編碼下得到的是同一個(gè)東西,然后再decode得到字符串就可以。根據(jù)String的格式可以猜測(cè)encode和decode的效率是非常非常高的,所以這也算是一種很好的解決方法了。
第二種解決方法:統(tǒng)一編碼格式
這邊使用的是Webx礦建,只需要將webx.xml中設(shè)置defaultCharset="UTF-8"就可以了。

相關(guān)文章

  • 一文帶你搞懂Java中的泛型和通配符

    一文帶你搞懂Java中的泛型和通配符

    泛型機(jī)制在項(xiàng)目中一直都在使用,甚至很多源碼中都用到了泛型機(jī)制。但是里面很多的機(jī)制和特性一直沒有明白,尤其通配符這塊,經(jīng)常忘記。本文對(duì)此做了一些總結(jié),具有一定借鑒價(jià)值,希望有所幫助
    2022-09-09
  • NameNode?重啟恢復(fù)數(shù)據(jù)的流程詳解

    NameNode?重啟恢復(fù)數(shù)據(jù)的流程詳解

    這篇文章主要為大家介紹了NameNode?重啟恢復(fù)數(shù)據(jù)的流程詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-02-02
  • java實(shí)現(xiàn)簡(jiǎn)單銀行管理系統(tǒng)

    java實(shí)現(xiàn)簡(jiǎn)單銀行管理系統(tǒng)

    這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)簡(jiǎn)單銀行管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-12-12
  • hibernate中HQL如何調(diào)用自定義函數(shù)

    hibernate中HQL如何調(diào)用自定義函數(shù)

    這篇文章主要介紹了hibernate中HQL如何調(diào)用自定義函數(shù)問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-09-09
  • java開發(fā)web前端cookie session及token會(huì)話機(jī)制詳解

    java開發(fā)web前端cookie session及token會(huì)話機(jī)制詳解

    如果把人體比作一個(gè)web系統(tǒng)的話,cookie、session和token就好像人體的經(jīng)絡(luò)和血管一樣,而web系統(tǒng)中的數(shù)據(jù),就好像人體的血液一樣。血液依靠著血管在人體內(nèi)流動(dòng),就如數(shù)據(jù)根據(jù)cookie和session機(jī)制在web系統(tǒng)中流動(dòng)一樣
    2021-10-10
  • Java窗口精細(xì)全方位講解

    Java窗口精細(xì)全方位講解

    這篇文章呢,將會(huì)系統(tǒng)的精細(xì)的教會(huì)鐵鐵們?nèi)绾巫约簩懸粋€(gè)完整的窗口;看完之后窗口穩(wěn)拿下!!!所以呢由于詳細(xì),知識(shí)點(diǎn)多,可能有點(diǎn)長(zhǎng),鐵鐵們慢慢仔細(xì)閱讀吧;文章寫的還是一如既往快樂的,哈哈哈
    2021-08-08
  • java 中堆內(nèi)存和棧內(nèi)存理解

    java 中堆內(nèi)存和棧內(nèi)存理解

    這篇文章主要介紹了java 中的堆內(nèi)存和棧內(nèi)存的知識(shí),有需要的朋友可以參考下
    2017-03-03
  • 詳解使用Spring Security OAuth 實(shí)現(xiàn)OAuth 2.0 授權(quán)

    詳解使用Spring Security OAuth 實(shí)現(xiàn)OAuth 2.0 授權(quán)

    本篇文章主要介紹了詳解使用Spring Security OAuth 實(shí)現(xiàn)OAuth 2.0 授權(quán),小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-01-01
  • java繪制國(guó)際象棋與中國(guó)象棋棋盤

    java繪制國(guó)際象棋與中國(guó)象棋棋盤

    這篇文章主要為大家詳細(xì)介紹了java繪制國(guó)際象棋與中國(guó)象棋棋盤,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-05-05
  • 使用Java實(shí)現(xiàn)簡(jiǎn)單串口通信

    使用Java實(shí)現(xiàn)簡(jiǎn)單串口通信

    這篇文章主要介紹了使用Java實(shí)現(xiàn)簡(jiǎn)單串口通信,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-07-07

最新評(píng)論