中文字符在哪里""在java .class文件中

时间:2017-10-12 07:28:32

标签: java unicode

我有这样一个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

我找到了中文字符&#34;中&#34;在第12行03e4 b8ad,unicode U + 4E2D,其中UTF-8为E4 B8 AD,但我找不到另一个字符&#34;&#34;,unicode U + 29100,我期待的类似于&#34; 04 F0 A9 84 80&#34;,为什么?

2 个答案:

答案 0 :(得分:3)

让我们使用javap

首先编译 Post: /_aliases { "actions" : [ { "remove" : { "index" : "*", "alias" : "nameOfAlias" } } ] }

然后拆开 javac UnicodeTest.java(截断到相关部分):

javap -v UnicodeTest.class

常量池中的项目#20正是您要找的。

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

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 数据结构为CONSTANT_Utf8_info

Utf8

标签是CONSTANT_Utf8(CONSTANT_Utf8_info { u1 tag; u2 length; u1 bytes[length]; } )。长度为01,字节为00 06

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

现在回到JVM规范。

  

代码点高于U + FFFF的字符(所谓的补充   字符)通过分别编码两个代理来表示   UTF-16表示的代码单元。每个代理代码   单位由三个字节表示。这意味着补充   字符由六个字节u,v,w,x,y和z表示:

我不会在此处粘贴内容,因为它太长了,但您可以查看表4.12。在CONSTANT_Utf8_info信息下(上面的链接)

这就是为什么它长达6个字节。

现在让我们采用公式

ed a1 a4 ed b4 80

通过替换0x10000 + ((v & 0x0f) << 16) + ((w & 0x3f) << 10) + ((y & 0x0f) << 6) + (z & 0x3f) vwy输出为168192(10) 0x29100 ,这是预期的代码点

答案 1 :(得分:1)

您可以使用的经典技术是通过其他方式更改值,并检查hex-dump的差异。这已经在八十年代被用来了,当你&#34; hack&#34;为游戏保存游戏以增加角色扮演角色的属性等。

我将字符改为a,似乎可以在偏移量0xBE-0xC3处找到该字符,其值为ED A1 A4 ED B4 80。我必须查看其中的细节,以便能够解释为什么值与您预期的值不同,但Java对Unicode的原始支持限制为两个字节(这是{{1定义了类型。具有3个字节或更多字节的Unicode字符需要在字节码中以特定方式进行编码,以告诉ClassLoader它需要以不同的方式处理。