java - 包含 2000 +1枚举常量的枚举类是否命中任何限制?

  显示原文与译文双语对照的内容
0 0

下面的代码将失败,并显示 NullPointerExceptionmain中 (map==null). 则只有当我定义问题2001或多个Enum常量,2000很好地发挥。

为什么不是静态代码块不执行?

我们按任意键静默限制编译器的( 没有警告,没有错误) 或JVM?

已编译的类文件超过172KB,

import java.util.HashMap;
public enum EnumTest {
    E(1),E(2),...,E(2001);
    private static HashMap<Integer, EnumTest>   map = new HashMap<Integer, EnumTest>();
    static {
        for ( EnumTest f : EnumTest.values() ) {
            map.put( (int) f.id, f );
        }
    }
    short id;
    private EnumTest(int id) {
        this.id = (short) id;
    };
    public short getId() {
        return id;
    }
    public static final EnumTest fromInt(int id) {
        EnumTest e = map.get( id );
        if ( e != null ) {
            return e;
        }
        throw new IllegalArgumentException( "" + id );
    }
    public static void main(String[] args) {
        System.out.println( "size:" + map.size() );
    }
}

运行环境(RuntimeEnvironment) :

java version "1.7.0_01"
Java(TM) SE Runtime Environment (build 1.7.0_01-b08)
Java HotSpot(TM) 64-Bit Server VM (build 21.1-b02, mixed mode)

还后果:

java version "1.6.0_32" Java(TM) SE Runtime Environment (build
1.6.0_32-b05) Java HotSpot(TM) Client VM (build 20.7-b02, mixed mode, sharing)
时间:原作者:7个回答

0 0

这类问题通常来自于这样一个事实,即一些( 编译器生成) 初始值设定项代码超过65536个字节的字节代码。 一个方法不能包含超过字节的最大的字节码被执行( 由于限制在类文件格式 ) 。

一个常见的问题来源是这样的大数组,如下所示:

byte someBytes = { 1, 2, 3, ..., someBigValue };

其问题在于,实际上这样的字段来初始化 someBigValue 生成赋值语句中的初始化函数( 构造函数或静态初始值设定项) 。

实际上enum值初始化方式是相似的。

假设有下列Enum类:

public enum Foo {
  CONSTANT(1);
  private Foo(int i) {
  }
}

我们看到的输出。 javap -v然后看看下面的代码块:

  static {};
    flags: ACC_STATIC
    Code:
      stack=5, locals=0, args_size=0
         0: new           #4                  // class Foo
         3: dup
         4: ldc           #7                  // String CONSTANT
         6: iconst_0
         7: iconst_1
         8: invokespecial #8                  // Method "<init>":(Ljava/lang/String;II)V
        11: putstatic     #9                  // Field CONSTANT:LFoo;
        14: iconst_1
        15: anewarray     #4                  // class Foo
        18: dup
        19: iconst_0
        20: getstatic     #9                  // Field CONSTANT:LFoo;
        23: aastore
        24: putstatic     #1                  // Field $VALUES:[LFoo;
        27: return

正如你所看到的有了相当多的字节码操作句柄实例化 CONSTANT使用正确的值。 如果有等众多枚举值,然后静态初始值设定项的块的大小可能很容易超出64k字节的代码,从而使该类不可编译。

可能的解决方法是缩小初始化代码通过减少参数的数目( 例如通过计算传入的数根据枚举的索引值而不是使用参数) 。 这也许能给你足够的回旋余地来扩展此更多。

另外,你也可以尝试在枚举分割为多个枚举连接通过实现同一个接口。 枚举可能是按area/intention/category/分组。.:

public interface MessageType {
  int getId();
}
public enum ConnectionMessage implements MessageType {
  INIT_CONNECTION(1),
  LOGIN(2),
  LOGOUT(3),
  CLOSE_CONNECTION(4);
  // getId code, constructor, ...
}
public enum FrobnicationMessage implements MessageType {
  FROBNICATE_FOO(5),
  FROBNICATE_BAR(6),
  DEFROB_FOO(7),
  DEFROB_BAR(8),
  ...
  // getId code, constructor, ...
}

我觉得对引用的枚举值实际上是在代码中的某处并不仅仅是纯值持有者,如果他们只保存值和各个值不在代码中处理略有不同,然后将其替换为一个类实例化一次每个数据项存储在集中的资源可能是最佳方法。

原作者:
0 0

我怀疑你应该看到的是编译时错误

error: code too large

也许你的版本的编译器有错误和不显示这个信息。

当我创造2500枚举值与此错误而失败但是有2400枚举值它运行正确。

每页最多可有64 KB的字节代码中的任何方法和枚举是初始化一个方法的静态初始化块。

问题是许多字节码指令使用的字节偏移量作为16位值这会将此限制总的来说方法( 即使没有这样的指令末尾方法)

javac不够"聪明分手静态initialiser块分成多个sub方法,但是接下来有成千上万的 enums建议你可以做它所需要的另一种方法。

原作者:
...