Von*_*onC 21
.class根据来自Yohann Coppel 的2008年"Reflecting Scala"关系,我认为信息存储在文件的"腌制"部分,在Martin Odersky教授的监督下.
在编译过程中(如图2所示),Scala编译器生成两种类型的数据.
- 第一个是一些经典的Java字节码,可以由标准Java虚拟机读取和执行.
- 第二个是所谓的"Pickled data",它代表了原始源文件的基本结构.
此信息包含在.class文件中.
Java字节码规范允许编译器"定义和发出包含类文件结构的属性表中的新属性的类文件".如果JVM无法识别这些属性,则会默默忽略这些属性.

Scala编译器为Scala程序中的任何数据结构生成pickle数据,在pickler上下文中称为符号.
符号以图3所示的格式线性存储.

- 标签代表存储的数据类型,
- 然后长度给出后续数据块的长度.
- 数据块可以包含多个信息,例如符号的名称.
ScalaSig = "ScalaSig" Version Symtab
Version = Major_Nat Minor_Nat <====
Symtab = numberOfEntries_Nat {Entry}
Run Code Online (Sandbox Code Playgroud)
ScalaSig属性定义.
更完整的定义可以在源文件(现在scala.tools.nsc.symtab.PickleFormatscala.reflect.internal.pickling.PickleFormat).
您还可以查看如何阅读Pickled数据scala.tools.nsc.util.ShowPickled.
此页面显示了一个脚本(未测试),它将显示pickle数据:
#!/bin/sh
#
# Shows the pickled scala data in a classfile.
if [ $# == 0 ] ; then
echo "Usage: $0 [--bare] [-cp classpath] <class*>"
exit 1
fi
TOOLSDIR=`dirname $0`
CPOF="$TOOLSDIR/cpof"
PACK="$TOOLSDIR/../build/pack/lib"
QUICK="$TOOLSDIR/../build/quick/classes"
STARR="$TOOLSDIR/../lib"
CP=""
if [ -f "${PACK}/scala-library.jar" ] ; then
CP=`${TOOLSDIR}/packcp`
elif [ -d "${QUICK}/library" ] ; then
CP=`${TOOLSDIR}/quickcp`
else
CP=`${TOOLSDIR}/starrcp`
fi
if [ "$1" == "-cp" ] ; then
shift
CP="${1}:${CP}"
shift
fi
java -cp "$CP" scala.tools.nsc.util.ShowPickled $*
Run Code Online (Sandbox Code Playgroud)
如果使用javapverbose选项,则可以在类文件中看到Scala Major/Minor版本.例如,对于使用scala 2.8.0 final编译的文件,显示以下内容:
javap -private -verbose T
Compiled from "SomeTest.scala"
public interface T
SourceFile: "SomeTest.scala"
ScalaSig: length = 0x3
05 00 00
RuntimeVisibleAnnotations: length = 0xB
00 01 00 06 00 01 00 07 73 00 08
minor version: 0
major version: 49
Constant pool:
const #1 = Asciz SourceFile;
const #2 = Asciz SomeTest.scala;
const #3 = Asciz s;
const #4 = Asciz ()Ljava/lang/String;;
const #5 = Asciz ScalaSig;
//etc etc...
Run Code Online (Sandbox Code Playgroud)
而以下是使用scala 2.7.7编译的文件的输出:
javap -verbose T2
Compiled from "SomeTest2.scala"
public interface T2
SourceFile: "SomeTest2.scala"
ScalaSig: length = 0x87
04 01 1B 06 08 01 02 FFFFFF84 FFFFFF90 FFFFFF80 FFFFFF91 00 05 02 02 54
32 0A 01 03 01 07 3C 65 6D 70 74 79 3E 03 00 13
02 00 06 10 02 07 0C 0D 01 08 0A 02 09 0A 01 04
6C 61 6E 67 0A 01 0B 01 04 6A 61 76 61 09 02 0D
08 02 06 4F 62 6A 65 63 74 08 05 0F 00 FFFFFF86 00 10
01 01 73 15 01 11 10 02 12 18 0E 02 13 16 0D 01
14 0A 01 15 01 05 73 63 61 6C 61 09 02 17 14 01
06 50 72 65 64 65 66 09 02 19 1A 02 06 53 74 72
69 6E 67 0A 02 17 14
minor version: 0
major version: 49
Constant pool:
const #1 = Asciz SourceFile;
const #2 = Asciz SomeTest2.scala;
//etc etc...
Run Code Online (Sandbox Code Playgroud)
ScalaSig常量条目的前两个字节应该代表Scala Major/Minor版本,我相信它们是在PickleFormat中定义的.可在此处找到2.7.7版本的PickleFormat ,并显示主要/次要版本与2.8.0版本不同.
我也检查了这个类的2.7.1版本,但是这里的Major/Minor版本与2.7.7版本相同,所以你可能无法通过使用这种方法区分小scala版本.
| 归档时间: |
|
| 查看次数: |
2032 次 |
| 最近记录: |