哪里是中国性格“”在一个Java类文件

问题描述:

我有这样一个Java类:哪里是中国性格“”在一个Java类文件

public class UnicodeTest { 
     public static void main(String[] args) { 
      String s = "中"; 
      String s1 = ""; 
      System.out.println(s.length()); 
      System.out.println(s1.length()); 
      System.out.println(s1.toCharArray().length); 
     } 

    } 

然后我用XXD看到编译的类文件:

0000000: cafe babe 0000 0032 0031 0700 0201 000b .......2.1...... 
0000010: 556e 6963 6f64 6554 6573 7407 0004 0100 UnicodeTest..... 
0000020: 106a 6176 612f 6c61 6e67 2f4f 626a 6563 .java/lang/Objec 
0000030: 7401 0006 3c69 6e69 743e 0100 0328 2956 t...<init>...()V 
0000040: 0100 0443 6f64 650a 0003 0009 0c00 0500 ...Code......... 
0000050: 0601 000f 4c69 6e65 4e75 6d62 6572 5461 ....LineNumberTa 
0000060: 626c 6501 0012 4c6f 6361 6c56 6172 6961 ble...LocalVaria 
0000070: 626c 6554 6162 6c65 0100 0474 6869 7301 bleTable...this. 
0000080: 000d 4c55 6e69 636f 6465 5465 7374 3b01 ..LUnicodeTest;. 
0000090: 0004 6d61 696e 0100 1628 5b4c 6a61 7661 ..main...([Ljava 
00000a0: 2f6c 616e 672f 5374 7269 6e67 3b29 5608 /lang/String;)V. 
00000b0: 0011 0100 03e4 b8ad 0800 1301 0006 eda1 ................ 
00000c0: a4ed b480 0900 1500 1707 0016 0100 106a ...............j 
00000d0: 6176 612f 6c61 6e67 2f53 7973 7465 6d0c ava/lang/System. 
00000e0: 0018 0019 0100 036f 7574 0100 154c 6a61 .......out...Lja 
00000f0: 7661 2f69 6f2f 5072 696e 7453 7472 6561 va/io/PrintStrea 
0000100: 6d3b 0a00 1b00 1d07 001c 0100 106a 6176 m;...........jav 
0000110: 612f 6c61 6e67 2f53 7472 696e 670c 001e a/lang/String... 
0000120: 001f 0100 066c 656e 6774 6801 0003 2829 .....length...() 
0000130: 490a 0021 0023 0700 2201 0013 6a61 7661 I..!.#.."...java 
0000140: 2f69 6f2f 5072 696e 7453 7472 6561 6d0c /io/PrintStream. 
0000150: 0024 0025 0100 0770 7269 6e74 6c6e 0100 .$.%...println.. 
0000160: 0428 4929 560a 001b 0027 0c00 2800 2901 .(I)V....'..(.). 
0000170: 000b 746f 4368 6172 4172 7261 7901 0004 ..toCharArray... 
0000180: 2829 5b43 0100 0461 7267 7301 0013 5b4c ()[C...args...[L 
0000190: 6a61 7661 2f6c 616e 672f 5374 7269 6e67 java/lang/String 
00001a0: 3b01 0001 7301 0012 4c6a 6176 612f 6c61 ;...s...Ljava/la 
00001b0: 6e67 2f53 7472 696e 673b 0100 0273 3101 ng/String;...s1. 
00001c0: 000a 536f 7572 6365 4669 6c65 0100 1055 ..SourceFile...U 
00001d0: 6e69 636f 6465 5465 7374 2e6a 6176 6100 nicodeTest.java. 
00001e0: 2100 0100 0300 0000 0000 0200 0100 0500 !............... 
00001f0: 0600 0100 0700 0000 2f00 0100 0100 0000 ......../....... 
0000200: 052a b700 08b1 0000 0002 000a 0000 0006 .*.............. 
0000210: 0001 0000 0002 000b 0000 000c 0001 0000 ................ 
0000220: 0005 000c 000d 0000 0009 000e 000f 0001 ................ 
0000230: 0007 0000 0078 0002 0003 0000 0026 1210 .....x.......&.. 
0000240: 4c12 124d b200 142b b600 1ab6 0020 b200 L..M...+..... .. 
0000250: 142c b600 1ab6 0020 b200 142c b600 26be .,..... ...,..&. 
0000260: b600 20b1 0000 0002 000a 0000 001a 0006 .. ............. 
0000270: 0000 0005 0003 0006 0006 0007 0010 0008 ................ 
0000280: 001a 0009 0025 000a 000b 0000 0020 0003 .....%....... .. 
0000290: 0000 0026 002a 002b 0000 0003 0023 002c ...&.*.+.....#., 
00002a0: 002d 0001 0006 0020 002e 002d 0002 0001 .-..... ...-.... 
00002b0: 002f 0000 0002 0030      ./.....0 

我有在第12行03e4 b8ad中发现了汉字“中”,unicode U + 4E2D,它在UTF-8中是E4 B8 AD,但是我找不到另一个字符“”,unicode U + 29100,我期望像“04 F0 A9 84 80“,为什么?

+1

U + 29100在UTF-16中表示为'\ uD864 \ uDD00',您是否在搜索这些字节? –

+0

是的,没有找到。 – OldFarmer

让我们使用javap

编译先用 javac UnicodeTest.java

然后用 javap -v UnicodeTest.class拆卸(截断到相关部分):

Constant pool: 
    #1 = Methodref   #9.#18   // java/lang/Object."<init>":()V 
    #2 = String    #19   // 中 
    #3 = String    #20   // 
    #4 = Fieldref   #21.#22  // 
... truncated 
    #17 = Utf8    UnicodeTest.java 
    #18 = NameAndType  #10:#11  // "<init>":()V 
    #19 = Utf8    中 
    #20 = Utf8    

在常量池中的项目#20是你在找什么。

现在,您可以查看JVM class file format

Utf8数据结构是CONSTANT_Utf8_info

CONSTANT_Utf8_info { 
    u1 tag; 
    u2 length; 
    u1 bytes[length]; 
} 

标签是CONSTANT_Utf8(01)。长度为00 06,字节为ed a1 a4 ed b4 80

根据unicode查找,提到的字符应该有代码点0x29100。

现在回到JVM规范。

性状与上述U + FFFF代码点(所谓的补充 字符)被独立地编码它们的UTF-16表示的两个替代 码单元表示。每个替代代码 单位由三个字节表示。这意味着补充 字符由六个字节,U,V,W,X,Y和Z表示:

我不会因为它太长粘贴此内容,但你可以看看它作为表4.12。根据CONSTANT_Utf8_info信息(上面的链接)

所以这就是为什么它是6字节长。

现在,让我们式

0x10000 + ((v & 0x0f) << 16) + ((w & 0x3f) << 10) + 
((y & 0x0f) << 6) + (z & 0x3f) 

通过代vwyz输出是168192(10),其是0x29100,预计代码点。

+0

为了详细阐述JVM规范,它描述的内容更正式地称为[Modified UTF-8](https://en.wikipedia.org/wiki/UTF-8#Modified_UTF-8),稍后将对其进行描述有关['DataInput'类]的Java文档中的更多详细信息(https://docs.oracle.com/javase/8/docs/api/java/io/DataInput.html) –

您可以使用的经典技术是通过其他方式更改值并检查十六进制转储的差异。八十年代,当你“剽窃”保存游戏以增加游戏时,这已经被使用了。角色扮演角色的属性等。

我改变了字符a,看起来该字符可以在偏移量0xBE-0xC3处找到并且具有值ED A1 A4 ED B4 80。我将不得不查看它的具体细节,以便能够解释为什么值与预期的值不同,但Java对Unicode的原始支持限于两个字节(这就是定义类型char。 +字节以上需要在字节码一种特殊的方式来告诉它需要以不同的方式被处理的类加载器进行编码。