Minecraft(我的世界)中文论坛

 找回密码
 注册(register)
查看: 4427|回复: 9

[其它开发教程] [高难度]Java的class文件中的常量池概述

[复制链接]
发表于 2014-6-14 15:22:09 | 显示全部楼层 |阅读模式

您尚未登录,立即登录享受更好的浏览体验!

您需要 登录 才可以下载或查看,没有帐号?注册(register)

x
本帖最后由 linnaea 于 2014-6-14 15:24 编辑

首先请确保你会Java,不然我可以保证你看的一头雾水

对于汉化那些消息都写在class文件里的插件,这些东西还是比较有用的还有这些东西比较难懂,所以尽管问……

首先每个class文件中都有一个常量池,其中会存放不少东西,包括字符串
常量池中的数据分成14种,以下是比较常见的11种和他们之间的引用关系
  1. Fieldref_info           --\     /--> Class_info       --\
  2. Methodref_info          ---+===+---> NameAndType_info ---+===> Utf8_info
  3. InterfaceMethodref_info --/                             /
  4. String_info--------------------------------------------/

  5. Integer_info
  6. Float_info
  7. Long_info
  8. Double_info
复制代码
Fieldref_info:表示类中的字段
Methodref_info:表示中的方法
InterfaceMethodref_info:表示接口中的方法
Class_info:表示类和接口
NameAndType_info:表示字段或方法的名称和类型,含有两个对Utf8_info的引用
String_info:表示字符串常量
Utf8_info:实际保存字符串的地方
Integer_info:保存一个32位整数
Float_info:保存一个32位单精度浮点数
Long_info:保存一个64位整数,在这个常量后的一个常量必须是有效的,但是会被忽略(也就是不能使用)
Double_info:保存一个64位双精度浮点数,同上

常量池中的常量从1开始编号,最大为65535
class文件中,所有的数据都是大尾序的(也就是说,0x01020304保存为0x01 0x02 0x03 0x04四个字节,而小尾序是0x04 0x03 0x02 0x01)


对类的引用在class文件中表示为一个Class_info,这个结构中有一个表示相应的Utf8_info的编号的字段,而相应的Utf8_info中会记录实际的类名
类的名字很容易看,比如Java中的类com.example.foo.Bar,记录在class文件中时,把.换成/即可,也就是com/example/foo/Bar

对字段的引用在class文件中表示为一个Fieldref_info,这个结构中有一个表示所属的类的Class_info的编号的字段,还有一个表示字段名称和类型的NameAndType_info
NameAndType_info中有两个Utf8_info的编号,一个是名字,另外一个是类型。
class文件中,类型的信息是有自己的一个表示方式的。byte记为B,char记为C,double记为D,float记为F,int记为I,long记为J,short记为S,boolean记为Z,而某个特定的类记为 L类名; ,数组则是在相应的类型前加上[
比如,byte[]是[B,String[][]是[[Ljava/lang/String;,com.example.foo.Bar类型记为Lcom/example/foo/Bar;


对方法的引用和对字段的引用大体上是一样的,区别在于类型的标记方式。
一个方法可以接受多个参数,并且可以返回一个值(或者void类型,没有返回值)
这些信息一样是记录在NameAndType_info中表示类型的那个Utf8_info里的,记录方法是
  1. (参数1类型 参数2类型 ...)返回类型
复制代码
(注意实际上是没有空格的,这里的空格只是方便阅读)
特别的,对于void的返回类型,记作V
举例:java.lang.StringBuilder.append
  1. Methodref_info ---+---> Class_info        -------> Utf8_info "java/lang/StringBuilder"
  2.                    \--> NameAndType_info  ---+---> Utf8_info "append"
  3.                                               \--> Utf8_info "(Ljava/lang/String;)Ljava/lang/StringBuilder;"
复制代码
java.lang.Object.toString
  1. Methodref_info ---+---> Class_info        -------> Utf8_info "java/lang/Object"
  2.                    \--> NameAndType_info  ---+---> Utf8_info "toString"
  3.                                               \--> Utf8_info "()Ljava/lang/String;"
复制代码
boolean foobar(int i, double d, Thread t) (只表示NameAndType_info部分)
  1. NameAndType_info  ---+---> Utf8_info "foobar"
  2.                       \--> Utf8_info "(IDLjava/lang/Thread;)Z"
复制代码

对于字符串常量,String_info里有一个记录对应Utf8_info的编号的字段。非常简单的东西。


然后我们来考虑插件汉化……
考虑这种情况:你的程序里有一个地方使用了java.lang.StringBuilder.append(字符串之间用+都会用到这个),然后你又有一个字符串常量是"append"
那么在class文件里看起来就是这样的:
  1. Methodref_info ---+---> Class_info        --------> Utf8_info "java/lang/StringBuilder"
  2.                    \--> NameAndType_info  ---+----> Utf8_info "(Ljava/lang/String;)Ljava/lang/StringBuilder;"
  3.                                               \
  4. String_info    --------------------------------+--> Utf8_info "append"
复制代码
然后你把append汉化成“附加”了,于是本来调用java.lang.StringBuilder.append的地方就都变成java.lang.StringBuilder.附加,GG……(我没用过hhclass,不过我猜可能是这个原因导致有些插件没法汉化)
正确的做法:单独添加一个Utf8_info常量,内容是“附加”,然后把本来指向“append”的String_info改为指向这个新的常量。
软件的话,http://classeditor.sourceforge.net/

来练个手吧w
这是某个class文件中的常量池的一部分:
#8 Fieldref_info    Class_info#137,NameAndType_info#253
#39 String_info  Utf8_info#149
#63  Methodref_Info   Class_info#137,NameAndType_info#314
#137 Class_info   Utf8_info#375
#149 Utf8_Info  "compressor"
#150 Utf8_Info  "Lnet/jpountz/lz4/LZ4Compressor;"
#204 Utf8_Info  "setWorldsAutoSaving"
#205 Utf8_Info  "(Z)V"
#253 NameAndType_Info   Utf8_info#149  Utf8_info#150
#314 NameAndType_Info   Utf8_info#204  Utf8_info#205
#375 Utf8_Info "name/linnaea/mbdelta/cb/BukkitPlugin"
请试着指出Methodref_Info#63表示的方法所在的类,及其原型

请试着指出Fieldref_info#8表示的字段所在的类,以及字段的名称和类型

请试着指出String_info#39表示的字符串



之后我可能会试着自己写个这种东西,方便汉化什么的
不过这些东西放这里的话,我觉得肯定会有人比我先完成,因为……












我懒啊

评分

参与人数 5人气 +6 金粒 +47 收起 理由
gooding300 + 2 + 10 Bytecode大法好w望继续深入
andylizi + 2 欢迎来到bytecode编程
liuhui1362 + 1 + 20 Mcbbs有你更精彩~
taoo7 + 1 + 5 Mcbbs有你更精彩~
q513902026 + 12 教程不错

查看全部评分

发表于 2014-6-14 15:25:18 | 显示全部楼层
你成功保障了我看得一头雾水,哈哈
回复

使用道具 举报

发表于 2014-6-14 15:28:10 | 显示全部楼层
同上.......
回复

使用道具 举报

发表于 2014-6-14 15:30:02 | 显示全部楼层
= = 好深奥。。
回复

使用道具 举报

发表于 2014-6-14 15:35:06 | 显示全部楼层
小学生表示不懂
回复

使用道具 举报

发表于 2014-6-14 15:53:59 | 显示全部楼层
楼主加油!~哇啦啦~
回复

使用道具 举报

发表于 2014-6-14 15:54:15 | 显示全部楼层
哦,原来汉化是这样的,长知识了。
回复

使用道具 举报

发表于 2014-6-16 06:59:19 | 显示全部楼层
原来字节码是这样的,长见识了。
回复

使用道具 举报

 楼主| 发表于 2014-6-16 10:45:18 | 显示全部楼层
梦幻龙族Ⅱ 发表于 2014-6-16 06:59
原来字节码是这样的,长见识了。

字节码和执行栈之类的我还没讲到呢……
回复

使用道具 举报

发表于 2014-6-16 11:12:10 | 显示全部楼层
哦,好吧。常量池原来是这样的~
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册(register)

本版积分规则

Archiver|小黑屋|Mcbbs.net ( 京ICP备15023768号-1 ) | 手机版本

GMT+8, 2018-10-21 18:51 , Processed in 0.129134 second(s), 6 queries , Memcache On.

"Minecraft"以及"我的世界"为Mojang Synergies AB的商标。本站与Mojang以及微软公司没有从属关系。

© 2010-2017 我的世界中文论坛 版权所有。本站原创图文内容版权属于原创作者,未经许可不得转载。

快速回复 返回顶部 返回列表