String s = "1";
    byte[] arr = s.getBytes("UNICODE");
    System.out.println(Arrays.toString(arr)); // 12请写出运行结果,并从源代码级解释原因。JDK 为 6.0

解决方案 »

  1.   

    具体的运行结果应该是0xfe 0xff 0x00 0x31
      

  2.   

    No JDK now, also I have not used this method...
      

  3.   

    楼上正解!为了在读取字节时能知道所采用的字节序,在传输时采用了一个名为
    “ZERO WIDTH NON-BREAKING SPACE”(U+FEFF)的字符用于限定字节
    序,开头两个字节为 FE FF 时为 Big-Endian,为 FF FE 时为 Little-Endian。
    详见 RFC2781 3.2 节。在 Java 中直接使用 Unicode 转码时会按照 UTF-16LE 的方式拆分,并加上 BOM。如果采用 UTF-16 拆分,在 Java 中默认采用带有 BOM 的 UTF-16BE 拆分。
      

  4.   

    Oh! Christ! I remember you told this before. But...I...forgot...it...at that time...
      

  5.   

    Unicode规范中推荐的标记字节顺序的方法是BOM。BOM不是“Bill Of Material”的BOM表,而是Byte Order Mark。(Unicode是一种字符编码方法,不过它是由国际组织设计,可以容纳全世界所有语言文字的编码方案。Unicode的学名是"Universal Multiple-Octet Coded Character Set",简称为UCS。UCS可以看作是"Unicode Character Set"的缩写。)在UCS编码中有一个叫做"ZERO WIDTH NO-BREAK SPACE"的字符,它的编码是FEFF。而FFFE在UCS中是不存在的字符,所以不应该出现在实际传输中。UCS规范建议在传输字节流前,先传输字符"ZERO WIDTH NO-BREAK SPACE"。这样如果接收者收到FEFF,就表明这个字节流是Big-Endian的;如果收到FFFE,就表明这个字节流是Little-Endian的。因此字符"ZERO WIDTH NO-BREAK SPACE"又被称作BOM。
    在 Java 中直接使用Unicode 转码时会按照UTF-16LE 的方式拆分,并加上 BOM。 如果采用 UTF-16 拆分,在 Java 中默认采用带有 BOM 的 UTF-16BE 拆分。 (其实Unicode与UTF-8是完全一样的)
      

  6.   

    2个疑问,1 为何UTF-8没有
    2 我想知道,在源代码里的哪个部分做的这个判断。
      

  7.   

    应该是sun.nio.cs.UTF_16$Encoder这个类的 byte[] encode(char[] cs, int off, int len) 方法;
    因为sun.nio.cs.UTF_16没有源码,所以无法跟踪了。
    从class的文件名来看,每种编码形式对应的类,其内部都有一个Encoder类和一个Decoder类,用来编码和解码。现在我的手头上只有JDK1.4的反编译器,所以,无法看到JDK6的源码。
      

  8.   

    嗯,UTF-8 是通过 Unicode 转换而来的,是 Unicode 的表现形式之一。
    只能回答你第一个问题:UTF-8 是采用 1~4 个字节来表示 Unicode 字符的,每个 Unicode 的 UTF-8 编码的
    第一个字节是有一定范围的,如果读取到某个字节的最高位为 0 那么采用一个字节表
    示,如果最高位是两个“1”就采用两个字节表示,最高位是三个“1”采用三个字节表
    示,以此类推。多字节表示时,第二个和后面的字节的最高位只能是“10”,也就是说
    UTF-8 编码时字符的第一个字节的最高位不可能是“10”。因此,UTF-8 只能采用 Big-Endian 的 BOM 方式。BOM 头 U+FEFF,UTF-8 编码为 EF BB BF
    就稳含掉了。如果采用 LE 方式时,字节序颠倒了,第一个字节最高位就是“10”了,这时 UTF-8 读
    取时会产生错误,这时会采用一个被称为 Replacement Character (U+FFFD) 的字符来代替。第二个问题正在看源代码……
      

  9.   

    楼上的大虾们,问个问题本地环境是 windows 
    服务器上是 unixif(str.getBytes().length != str.length())
    {
    return true;
    }
    return false;用该方法判断字符串是否包含中文或其它特殊字符本地环境  1中文字 getBytes 是2 length是4
    服务器    1中文字 getBytes 是2 length是2这是怎么回事??
      

  10.   

    java.lang.String#getBytes(String) 的源代码:public byte[] getBytes(String s) throws UnsupportedEncodingException {
        if(s == null)
            throw new NullPointerException();
        else
            return StringCoding.encode(s, value, offset, count);
    }java.lang.StringCoding.encode 的源代码:
    static byte[] encode(String s, char ac[], int i, int j) throws UnsupportedEncodingException {
        Object obj = (StringEncoder)deref(encoder);
        String s1 = s != null ? s : "ISO-8859-1";
        if(obj == null || !s1.equals(((StringEncoder) (obj)).requestedCharsetName()) && !s1.equals(((StringEncoder) (obj)).charsetName())) {
            obj = null;
            try {
                Charset charset = lookupCharset(s1);
                if(charset != null)
                    obj = new CharsetSE(charset, s1);
            } catch(IllegalCharsetNameException illegalcharsetnameexception) { }
            if(obj == null)
                obj = new ConverterSE(CharToByteConverter.getConverter(s1), s1);
            set(encoder, obj);
        }
        return ((StringEncoder) (obj)).encode(ac, i, j);
    }
    Unicode 编码不存在对应的 Charset 因此会执行 new ConverterSE(CharToByteConverter.getConverter(s1), s1);
    这一句。再通过其底层类库的字符集类 sun.io.CharacterEncoding 可以找出 Unicode 的转换器,
    是采用 sun.io.CharToByteUnicode 这个类的,这个类的 sun.io 包是读取 file.encoding.pkg 这
    个系统属性拼接字符串反射而来的。这个类是这样拼出来的:
         file.encoding.pkg 属性值 + "." + "CharToByte" + CharacterEncoding 中保存的名字这个类的构造是:public CharToByteUnicode() {
        usesMark = true;
        Written = false;
        byteOrder = 0;
        String s = (String)AccessController.doPrivileged(new GetPropertyAction("sun.io.unicode.encoding", "UnicodeBig"));
        if(s.equals("UnicodeBig"))
            byteOrder = 1;
        else
            if(s.equals("UnicodeLittle"))
                byteOrder = 2;
            else
                byteOrder = 1;
    }String s = (String)AccessController.doPrivileged(new GetPropertyAction("sun.io.unicode.encoding", "UnicodeBig"));
    这一句很关键,决定着 Unicode 编码时 byteOrder 的值是 1 还是 2。这里有个 sun.io.unicode.encoding
    这个系统属性,在 Windows 系统下的值为:UnicodeLittle,因此 byteOrder 值为 2。注:有苹果机的同学用 System.out.println(System.getProperty("sun.io.unicode.encoding")); 看看这个值
    是啥。至于 Unicode 是怎么转换的看看 sun.io.CharToByteUnicode 这个类的源代码就有了。
      

  11.   


    length 指的是什么?是 str.length() 还是什么?
    1 个中文字的 str.length() 是 1 啊,怎么可能是 2 或 4 呢?
      

  12.   


    汗,已经说了很清楚了啊,在 sun.io.CharToByteUnicode 这个类中啊。贴上源代码吧。01  public int convert(char ac[], int i, int j, byte abyte0[], int k, int l) throws ConversionBufferFullException, MalformedInputException {
    02      charOff = i;
    03      byteOff = k;
    04      if(i >= j)
    05          return 0;
    06      int i1 = i;
    07      int j1 = k;
    08      int k1 = l - 2;
    09      if(usesMark && !Written) {
    10          if(j1 > k1)
    11              throw new ConversionBufferFullException();
    12          if(byteOrder == 1) {
    13              abyte0[j1++] = -2;
    14              abyte0[j1++] = -1;
    15          } else {
    16              abyte0[j1++] = -1;
    17              abyte0[j1++] = -2;
    18          }
    19          Written = true;
    20      }
    21      if(byteOrder == 1)
    22          while(i1 < j) {
    23              if(j1 > k1) {
    24                  charOff = i1;
    25                  byteOff = j1;
    26                  throw new ConversionBufferFullException();
    27              }
    28              char c = ac[i1++];
    29              abyte0[j1++] = (byte)(c >> 8);
    30              abyte0[j1++] = (byte)(c & 255);
    31          }
    32      else
    33          while(i1 < j) {
    34              if(j1 > k1) {
    35                  charOff = i1;
    36                  byteOff = j1;
    37                  throw new ConversionBufferFullException();
    38              }
    39              char c1 = ac[i1++];
    40              abyte0[j1++] = (byte)(c1 & 255);
    41              abyte0[j1++] = (byte)(c1 >> 8);
    42          }
    43      charOff = i1;
    44      byteOff = j1;
    45      return j1 - k;
    46  }12 判断字节序,13~14 行写入 BE 的 BOM;16~17 行写入 LE 的 BOM。22~31 以 BE 方式写入字节,33~42 以 LE 方式写入字节。
    BE 和 LE 的写入方式仅在 29~30 和 40~41 行不同。29~30 为 BE 序先写入高字节,再写入低字节,而 40~41 为 LE 序,先写低字节,再写高字节的。
      

  13.   

    关于 Unicode 转为 byte 数组,做了个小实验,呵呵。public class Test1 {    private final static char[] HEX = "0123456789abcdef".toCharArray();    public static void main(String[] args) throws UnsupportedEncodingException {
            String str = "中国";
            String[] encoding = {
                    "Unicode", "UnicodeBig", "UnicodeLittle", 
                    "UnicodeBigUned", "UnicodeLittleUned",
                    "UTF-16", "UTF-16BE", "UTF-16LE"
                };
            
            for(int i = 0; i < encoding.length; i++) {
                System.out.printf("%-22s %s%n", 
                        encoding[i], 
                        bytes2HexString(str.getBytes(encoding[i]))
                    );
            }
        }
        
        public static String bytes2HexString(byte[] bys) {
            char[] chs = new char[bys.length * 2 + bys.length - 1];
            for(int i = 0, offset = 0; i < bys.length; i++) {
                if(i > 0) {
                    chs[offset++] = ' ';
                }
                chs[offset++] = HEX[bys[i] >> 4 & 0xf];
                chs[offset++] = HEX[bys[i] & 0xf];
            }
            return new String(chs);
        }
    }输出结果:Unicode                ff fe 2d 4e fd 56
    UnicodeBig             fe ff 4e 2d 56 fd
    UnicodeLittle          ff fe 2d 4e fd 56
    UnicodeBigUned     4e 2d 56 fd
    UnicodeLittleUned  2d 4e fd 56
    UTF-16                 fe ff 4e 2d 56 fd
    UTF-16BE               4e 2d 56 fd
    UTF-16LE               2d 4e fd 56总结:1. Unicode 的字节序方式采用 sun.io.unicode.encoding 的系统属性,并且是加上 BOM 的。
         转换类为:sun.io.CharToByteUnicode2. UnicodeBig 字节序为 BE 方式,加上 BOM
         转换类为:sun.io.CharToByteUnicode 不过在 sun.io.CharToByteUnicodeBig 中强制使用 BE 序,
         即即构造时强制设定 byteOrder 值为 13. UnicodeLittle 字节序为 LE 方式,加上 BOM
         转换类为:sun.io.CharToByteUnicode 不过在 sun.io.CharToByteUnicodeLittle 中强制使用 LE 序,
         即即构造时强制设定 byteOrder 值为 24. UnicodeBigUned 字节序为 BE 方式,有 Uned 不加 BOM
         转换类为:sun.io.CharToByteUnicode 不过在 sun.io.CharToByteUnicodeBigUned 中强制使用 BE 序和不加 BOM。
         即构造时强制设定 byteOrder 值为 1,usesMark 值为 false5. UnicodeLittleUned 字节序为 LE 方式,有 Uned 不加 BOM
         转换类为:sun.io.CharToByteUnicode 不过在 sun.io.CharToByteUnicodeLittleUned 中强制使用 LE 序和不加 BOM。
         即构造时强制设定 byteOrder 值为 2,usesMark 值为 false6. UTF-16 字节序为 BE 方式,加上 BOM
         转换类为:sun.io.CharToByteUnicode 不过在 sun.io.CharToByteUTF16 中强制使用 BE 序和加 BOM。
         即构造时强制设定 byteOrder 值为 1,usesMark 值为 true
         UTF-16 实际上与 UnicodeBig 是一样的。7. UTF-16BE 没有转换类,与 UnicodeBigUned 使用相同的转换器。8. UTF-16LE 没有转换类,与 UnicodeLittleUned 使用相同的转换器。
    上面的那些类都是 sun.io.CharToByteUnicode 的子类,这些子类中就只有设定各种格式的构造方法。根据 CharacterEncoding 的映射与 UnicodeBigUned 兼容的编码有:unicode-1-1, iso-10646-ucs-2, utf-16be, x-utf-16be 这么几个。而且 UnicodeLittleUned 兼容的有:utf-16le, x-utf-16le 这两个。     
      

  14.   

    之前的话:
    来迟了!但不可惜。呵呵。输出结果:
    [-2, -1, 0, 49]问题现象:
    “意外”地多了两个字节,即数组前两个元素,其值分别为-2、-1问题原因:
    楼上各位已经说得非常清楚,详见7楼与11楼相关源码:
    这是楼主最感兴趣的内容,所以说得详细一些。
    String的encode()方法里边调用了StringCoding的encode()方法。
    StringCoding的encode()方法有点复杂,包括缓存机制、Charset对象的创建等,但主要是调用了其嵌套类StringEncoder的encode()方法。
    而StringCoding.StringEncoder类的encode()方法又用到了CharsetEncoder类的encode()方法。
    CharsetEncoder的encode()又调用了它自己的encodeLoop()方法。——这就是答案所在。换句话说,输出BOM的源代码就在CharsetEncoder的encodeLoop()方法中。
    encodeLoop()方法是抽象方法,不同的子类有不同的实现。
    针对于“Unicode”编码,其对应的类为sun.nio.cs.UTF_16的嵌套类Encoder,以下是其源码: private static class Encoder extends UnicodeEncoder
    {
    public Encoder(Charset charset)
    {
    super(charset, 0, true);
    }
    }以下是其父类UnicodeEncoder的部分源码: //构造方法
    protected UnicodeEncoder(Charset charset, int i, boolean flag)
    {
    super(charset, 2.0F, flag ? 4F : 2.0F, i != 0 ? (new byte[] {
    -3, -1
    }) : (new byte[] {
    -1, -3
    }));
    usesMark = needsMark = flag;
    byteOrder = i;
    }
    //最终完成编码任务的方法——答案所在。
    protected CoderResult encodeLoop(CharBuffer charbuffer, ByteBuffer bytebuffer)
    {
    // 省略无关代码 if (needsMark)
    {
    if (bytebuffer.remaining() < 2)
    return CoderResult.OVERFLOW;
    put('\uFEFF', bytebuffer);
    needsMark = false;
    } // 省略无关代码
    }看完源码,再分析一下执行过程:
    1、因为当前使用的字符编码是“Unicode”,所以对应的CharsetEncoder是sun.nio.cs.UTF_16.Encoder
    2、在创建UTF_16.Encoder的对象时,其传给父类构造函数的第三个参数是true,意味着needsMark将被赋值为true
    3、由于needsMark为true,在encodeLoop()执行的时候,会写入0xFE、0xFF。然后needsMark被赋值为false,意味着BOM最多只写入一次
    4、0xFE、0xFF转换成byte,就分别是-2、-1问题补充:
    楼主又问到,为什么使用“UTF-8”时不会加BOM?
    参见第19楼。而从源代码的角度来说,因为“UTF-8”所对应的CharsetEncoder是sun.nio.cs.UTF_8.Encoder,
    在这个类的源代码中,encodeLoop()方法及与其的encodeArrayLoop()、encodeBufferLoop()方法的确没有写入BOM的操作,呵呵。后面的话:
    1、我的结论与27楼不太一致,27楼说的是sun.io.CharToByteUnicode,但我觉得我的跟踪和分析过程是正确的,我是在JDK6下做的这个过程。呵呵。
    2、强手如云啊,学习了!呵呵。
      

  15.   

    哦,我只有 JDK 5,我看的是 JDK 5 的。
      

  16.   

    JDK 6 底层的实现变掉了,请忽视我在 24、27、28 楼的回复,
    JDK 版本不符合要求,呵呵。
      

  17.   

    算是见识高手啦,我想解决这个问题,去研究JDK6的源码,还有编码知识啊。可惜我手上没有 6 的源码
      

  18.   

    怎么这里也有big endian,little endian的...................
    我也有个问题,为什么要使用unicode呢,好多软件里面的中文,少了一个字节,后面全错难道unicode有什么好处么为什么不用UTF,它的前2个字节也够保存很多东西了
      

  19.   

    public class TestEncoding { 
    public static void main(String[] args) throws Exception { 
    String s = "快乐123"; 
    byte[] arr = s.getBytes("Unicode"); 
    System.out.println(arr.length); // 12 
    arr = s.getBytes("GB2312"); 
    System.out.println(arr.length); // 7 

    } 请问第一处为何显示12而不是10 ? Unicode中一个字符占两个字节,这里有5个字符,应该是10啊,为何是12呢?在百度上有个类似的问题。
    最佳解释是这样的:
    在unicode编码会在开头包含ff fe这两个字节以表示是unicode编码,因此会多两个字节,所以是12,而不是10,把字节数组打印出来就知道了.换另一个字符串同样会存在ff fe这两个字节的。
      

  20.   

    具体可以参见sun.nio.cs.UnicodeEncoder类里的encodeLoop和put方法。核心语句如下:put('\uFEFF', bytebuffer);//生成-2,-1
    put(c, bytebuffer);//生成0,49jdk 5,6都一样
      

  21.   


    java.lang.StringCoding中的
    byte[] encode(char[] ca, int off, int len) {//ca[0] 为0,off为0,len为1
        int en = scale(len, ctb.getMaxBytesPerChar()); // 返回长度为4
        byte[] ba = new byte[en];
        if (len == 0)
    return ba;     ctb.reset();
        int n;
        try {
    n = ctb.convertAny(ca, off, (off + len),
       ba, 0, en);//我分析就是这部产生的-1,-2,但是我看不到源码。估计是Sun用自然语言写的东西,反编译都没有成功。
    n += ctb.flushAny(ba, ctb.nextByteIndex(), en);
        } catch (CharConversionException x) {
    throw new Error("Converter malfunction: " +
    ctb.getClass().getName(),
    x);
        }
        return trim(ba, n);
    }
      

  22.   

    我不懂什么规范,我只知道一件事情,在Windows下把一个文本文件以Unicode编码保存之后,再用VC以二进制方式打开这个文件看看,开头就是FF FE,可能就是结果的-1 -2
      

  23.   

    sun.nio.cs.UnicodeEncoder类里的encodeLoop和put方法
    put('\uFEFF', bytebuffer);//生成-2,-1
    put(c, bytebuffer);//生成0,49 
      

  24.   

    三维免费空间-最专业的免费ASP空间提供商,永久,快速,安全,稳定-!!
    免费用户可以开通ACCESS数据库
    免费用户可以开通FTP及二级域名                                   三维免费空间网址:http://3video.cn
      

  25.   

    太牛逼了,现在刚学java,不懂得太多了!!!
      

  26.   

    [-2, -1, 49,0] 是jdk1.5 的结果
      

  27.   

    昨天晚上弄到了两点还在看这个问题,呵呵,从下午在公司看过之后,由于放假了,就回到家再看,查过不少资料,本来也想发表一下自己的看法,但是作为刚刚毕业回家工作的我,呵呵,还算是新手了,以前研究没有这么深入,也没有细致到这些细节,其实很早就来过这个论坛,不过刚工作了才来这里经常泡泡,可能也是能学到不少东西吧,想成为一个程序门里面的人,如果说不想当一个高手,有人会说没有高原志向,如果说想当一个(或许是某一方面的)程序高手,对于我来说,只是不断地学习,觉得自己充实一些,再不断的充实就够了,我不算是一个特别能和别人争的人,只是能够让自己安心就可以,说了这么多,其实还是没有来回答楼主的问题,呵呵,不好意思了,以前在学校还是学的java,学了算是五年吧,呵呵,还算不错,学习到后来,觉得学习理论有些无用,现在想想,或者是工作这两个月的收获,的确指导性很强,好多东西,就像从一楼看到我这里,至少我都能够知道其中的东西,还有可以将之扩展一些出来,我想,这就是,万变不离其中吧,想再好好回去学学,呵呵,记得刚开始班上的编程高手,都是抱着书,写一些很高深的程序时,感觉自己视乎是不是不应该学习计算机,到后来,自己也同样的能够从document当中学习并且用到自己的程序当中时,才知道什么是成长的过程。
      

  28.   

    厉害  我佩服楼主啊  专家真牛啊!!! 我才刚学JAVA   受领教了 看到你们这精神 我要学好