假设这个时候 switch 表达式的值是 3,我直接根据偏移量 3,就可以取到 3 对应的接下来需要执行的地方 69,然后接着执行 default 语句了:
所以,0,1,2 不叫稀疏,0,2,4 也不叫稀疏。
它们都不 sparse ,缺一点点的情况下,我们可以补位。
所以现在你理解官网上的这句话了吗:
当 switch 语句里面 case 的值比较“稀疏”(sparse)的时候,用 tableswitch 指令的话空间利用率就会很低下。
比较稀疏的时候,假设三个 case 分别是 100,200,300。你不可能把 100 到 300 之间的数,除了 200 都补上吧?
那玩意补上了之后 case 得膨胀成什么样子?
空间占的多了,但是实际要用的就 3 个值,所以空间利用率低下。
那 tableswitch 指令不让用了怎么办呢?
别急,官方说可以用 lookupswitch 指令。
lookupswitch 指令拿着 switch 表达式计算出来的 int 值和一个表中偏移量进行配对(pairs)。
配对的时候,如果表里面一个 key 值与表达式的值配上了,就可以在这个 key 值关联的下一执行语句处继续执行。
如果表里面没有匹配上的键,则在 default 处继续执行。
你看明白了吗?迷迷糊糊的对不对?
什么玩意就出来一个表呢?
没事,别急,官方给了个例子:
这次的例子叫做 chooseFar 。因为 case 里面的值不是挨着的,0 到 100 之间隔得还是有点距离。
我不能像 tableswitch 似的,拿着 100 然后去找偏移量为 100 的位置吧。这里就三个数,根本就找不到 100 。
只能怎么办?
就拿着我传进来的 100 一个个的去和 case 里面的值比了,这就叫 pairs。
其实官网上的这个例子没有给好,你看我给你一个例子:
你看左边的 java 代码,里面的 case 是乱序的,到字节码文件里面后就排好序了。
而官方文档里面说的这个“table”:
为什么要排序呢?
答案就在虚拟机规范里面:
排序之后的查找比线性查找快。这个没啥说的吧。它这里虽然没有说,但其实它用的是二分查找,时间复杂度为O(log n)。
哦,对了。tableswitch 由于是直接根据偏移量定位,所以时间复杂度是 O(1)。
好了,到这里我就把 tableswitch 和 lookupswitch 这两个指令讲完了。
我不知道你在看的时候有没有产生什么疑问,反正我看到这个地方的时候我就在想:
虚拟机规范里面就说了个 sparse,那什么时候是稀疏,什么时候是不稀疏呢?
说实话,作为程序员,我对“稀疏”这个词还是很敏感的,特别是前面再加上毛发两个字的时候。
不知道为什么说到“稀疏”,我就想起了谢广坤。广坤叔你知道吧,这才叫“稀疏”: