当前位置: 首页 > 面试题库 >

包含2000 + 1枚举常量的枚举类是否达到任何限制?

南宫阳冰
2023-03-14
问题内容

以下代码以NullPointerExceptionin main
失败(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() );
    }
}

运行环境:

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)


问题答案:

这些类型的问题来自某些初始化程序代码(通常由编译器生成)超过65536字节字节代码的事实。单个方法所包含的字节码不能超过字节数(由于类文件格式的限制)。

像这样的问题的一个常见来源是像这样的大数组:

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

这里的问题是,此类字段实际上是在生成的初始化程序(构造函数或静态初始化程序)中使用 someBigValue 赋值语句初始化的。

枚举值实际上是以类似的方式初始化的。

给定以下枚举类:

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字节的代码,从而使该类不可编译。

一种可能的解决方法是通过减少参数的数量(例如,根据枚举值的索引而不是使用参数来计算传入的数量)来减小初始化代码的大小。那可能只是给您足够的摆动空间,以进一步扩展此范围。

另外,您可以尝试通过实现公共接口将枚举拆分为多个枚举。枚举可以按区域/意图/类别/ …进行分组:

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, ...
}

我假设枚举值实际上是在代码中的某个地方引用的,而不仅仅是纯值持有者,如果它们只保存值,而单个值在您的代码中并未得到不同对待,则将其替换为每个数据项实例化一次的单个类存储在中央资源中可能是最好的方法。



 类似资料:
  • 问题内容: 通过阅读SCJP书籍,我在第1章“自测”中发现了类似的内容: 注意:代码编译正常。我不明白的是为什么我们可以从变量访问DOG,CAT或FISH常量。我认为(并且也写在书中)DOG,FISH,CAT是常量,其实现方式类似于。 所以,如果它们确实是静态的,为什么我们可以从中访问它们呢?最后一行是我熟悉的方式。 问题答案: 写作 和写作一样。也就是说,编译器将用其编译时类型Animal替换变

  • 问题内容: 例如,我该怎么做: 结果示例: 问题答案: 迅捷4.2+ 从Swift 4.2(使用Xcode 10)开始,只需添加协议一致性即可从中受益。要添加此协议一致性,您只需要在某处写: 如果枚举是您自己的,则可以直接在声明中指定一致性: 然后,以下代码将打印所有可能的值: 与早期Swift版本(3.x和4.x)的兼容性 如果您需要支持Swift 3.x或4.0,则可以通过添加以下代码来模仿S

  • 问题内容: 这不是卡住我的问题,而是我正在寻找一种编写代码的整洁方法。 本质上,我正在编写一个事件驱动的应用程序。用户触发一个事件,该事件被发送到适当的对象,然后这些对象处理事件。现在,我正在编写偶数处理程序方法,并且希望使用switch语句确定如何处理事件。现在,在我研究通用结构时,事件类非常简单: 然后,在另一堂课中,我会看到类似以下内容的内容: 我会 喜欢 做的就是这样的事情(尽管我当然会坚

  • 主要内容:声明常量,实例,VB.Net打印和显示常量,声明枚举,实例常量指的是程序在执行过程中可能不会改变的固定值。 这些固定值也被称为文字。 常量可以是任何基本数据类型,如整数常量,浮点常量,字符常量或字符串文字。 也有枚举常量。 常量的处理方式与常规变量一样,只是它们的值在定义之后无法修改。 枚举是一组命名的整数常量。 声明常量 在VB.Net中,使用语句声明常量。 语句用于模块,类,结构,过程或块级别,以代替文字值。 语句的语法是: 其中, attribut

  • 当您需要定义错误码和错误信息时,可能会使用以下方式, <?php class ErrorCode { const SERVER_ERROR = 500; const PARAMS_INVALID = 1000; public static $messages = [ self::SERVER_ERROR => 'Server Error',

  • 问题内容: Python 3.4引入了一个新模块,该模块向该语言添加了枚举类型。的文档提供了一个示例来演示如何扩展它: 此示例还演示了一个问题:在property方法中,定义了一个常量,该常量通常在类级别定义- 但是尝试在a级别内执行此操作只会将其添加为枚举的成员之一,因此,在方法内部定义。 如果该类想在其他方法中使用此常量,则也必须在其中定义它,这显然不是理想的选择。 有什么方法可以在中定义类常