Java 压缩开关和稀疏开关dalvik操作码之间的差异

Java 压缩开关和稀疏开关dalvik操作码之间的差异,java,android,bytecode,dalvik,dex,Java,Android,Bytecode,Dalvik,Dex,我想知道dalvik中压缩交换机和稀疏交换机操作码之间的区别。请提供例子。谷歌提供的解释我不清楚 谢谢。听起来好像压缩开关相当于Java的表开关,而稀疏开关相当于查找开关 packed开关使用一个简单的跳转表,以low+n的形式索引,其中low是案例标签中的最低测试值,n是开关的输入。每个索引处的值表示每个情况下的字节码偏移量。查找正确的跳转地址是一个固定时间操作 稀疏开关使用键-值对的排序列表,其中每个键都是来自大小写标签的测试值,值是跳转偏移量。为查找开关查找正确的跳转目标需要对键进行二

我想知道dalvik中压缩交换机和稀疏交换机操作码之间的区别。请提供例子。谷歌提供的解释我不清楚


谢谢。

听起来好像
压缩开关
相当于Java的
表开关
,而
稀疏开关
相当于
查找开关

packed开关
使用一个简单的跳转表,以
low+n
的形式索引,其中
low
案例
标签中的最低测试值,
n
开关的输入。每个索引处的值表示每个
情况下的字节码偏移量。查找正确的跳转地址是一个固定时间操作

稀疏开关
使用键-值对的排序列表,其中每个键都是来自
大小写
标签的测试值,值是跳转偏移量。为
查找开关
查找正确的跳转目标需要对键进行二进制搜索,因此这是一个对数时间操作

编译器将选择使用哪个。如果键趋向于聚集或紧密地打包在一起,则可以有效地发出
打包开关
(或者,用Java术语来说,
表开关
)。但是如果键是稀疏的,并且值的范围(
高-低+1
)很大,那么使用跳转表将需要一大块字节码,因为该范围内的所有值都必须存在于跳转表中,而不管是否有相应的
大小写
标签。在这些场景中,编译器将发出一个
稀疏开关
查找开关

有趣的是,Dalvik工程师选择的命名方式描述了这些操作码应该用于的密钥分发,而Java工程师选择的命名方式描述了字节码操作数类似的概念数据结构

让我们看一些例子。考虑下面的java代码,它将产生<代码> TabLSwitCH (并且,当转换为Dalvik时,<代码>打包开关 >:

从概念上讲,
压缩交换机
操作码的有效负载如下所示:

正如你所见,它相当紧凑。五个插槽中有三个指向实际的
案例
目标,其余两个跳转到
默认
目标。但是,如果我们的测试值更分散,会怎么样

static String sparseSwitch(final int n) {
    switch (n) {
        case 500:
            return "Five Hundred";
        case 300:
            return "Three Hundred";
        case 100:
            return "One Hundred";
        default:
            return "Other";
    }
}
如果编译器试图将其作为
压缩开关发出
,则有效负载将如下所示:

请注意,几百个插槽中只有三个实际指向原始代码中的
case
标签。剩下的只是为了填满跳转表。不是很节省空间,是吗?这就是为什么编译器会发出一个
稀疏开关
,在这个特定示例中,它的字节码占用空间要小得多:

现在,这更合理了,你不觉得吗?然而,缺点是,我们不能根据输入准确地知道跳转到哪个索引,而是必须在表上执行二进制搜索,直到找到匹配的测试值。开关越大,对性能的影响越大,尽管其影响呈对数曲线。

请参见此处
static String sparseSwitch(final int n) {
    switch (n) {
        case 500:
            return "Five Hundred";
        case 300:
            return "Three Hundred";
        case 100:
            return "One Hundred";
        default:
            return "Other";
    }
}