为什么在Java构造函数和静态初始值设定项中会超过65535字节的限制?

为什么在Java构造函数和静态初始值设定项中会超过65535字节的限制?,java,jls,Java,Jls,免责声明:我意识到我可以用Java在运行时生成这个,这是在性能测试某些代码时非常特殊的情况下需要的。我发现了一种不同的方法,所以现在这只是一种好奇,而不是任何实际的做法。 我尝试将以下内容作为静态字段、实例字段,并直接在构造函数中初始化。每次eclipse通知我“构造函数TestData()的代码超过了65535字节的限制”或“静态初始值设定项的代码超过了65535字节的限制” 有10000个整数。如果每个int是4字节(32位),那么不是40000字节吗?除了仅仅构建阵列的数据之外,是否还有超

免责声明:我意识到我可以用Java在运行时生成这个,这是在性能测试某些代码时非常特殊的情况下需要的。我发现了一种不同的方法,所以现在这只是一种好奇,而不是任何实际的做法。

我尝试将以下内容作为静态字段、实例字段,并直接在构造函数中初始化。每次eclipse通知我“构造函数TestData()的代码超过了65535字节的限制”或“静态初始值设定项的代码超过了65535字节的限制”

有10000个整数。如果每个int是4字节(32位),那么不是40000字节吗?除了仅仅构建阵列的数据之外,是否还有超过250000字节的开销

数据是用一小段python生成的:

#!/usr/bin/python

import random;
print "public final int[] RANDOM_INTEGERS = new int[] {";
for i in range(1,10000):
    print str(int(random.uniform(0,0x7fffffff))) + ",";
print "};";
以下是一个小样本:

public final int[] RANDOM_INTEGERS = new int[] {
    963056418, 460816633, 1426956928, 1836901854, 334443802, 721185237, 488810483,
    1734703787, 1858674527, 112552804, 1467830977, 1533524842, 1140643114, 1452361499,
    716999590, 652029167, 1448309605, 1111915190, 1032718128, 1194366355, 112834025,
    419247979, 944166634, 205228045, 1920916263, 1102820742, 1504720637, 757008315,
    67604636, 1686232265, 597601176, 1090143513, 205960256, 1611222388, 1997832237,
    1429883982, 1693885243, 1987916675, 159802771, 1092244159, 1224816153, 1675311441,
    1873372604, 1787757434, 1347615328, 1868311855, 1401477617, 508641277, 1352501377,
    1442984254, 1468392589, 1059757519, 1898445041, 1368044543, 513517087, 99625132,
    1291863875, 654253390, 169170318, 2117466849, 1711924068, 564675178, 208741732,
    1095240821, 1993892374, 87422510, 1651783681, 1536657700, 1039420228, 674134447,
    1083424612, 2137469237, 1294104182, 964677542, 1506442822, 1521039575, 64073383,
    929517073, 206993014, 466196357, 1139633501, 1692533218, 1934476545, 2066226407,
    550646675, 624977767, 1494512072, 1230119126, 1956454185, 1321128794, 2099617717,
    //.... to 10,0000 instances

我认为这可能是以字母数字表示这些整数所需的内存量。我认为这一限制可能适用于代码本身,因此,每个int,例如:1494512072实际上需要10个字节(每个数字一个字节),而不是int32只需要4个字节。

我认为字符中的代码大小超过65535个字符。不是10000个整数占用的内存

除了整数的值之外,构造函数和初始值设定项还需要包含用于将整数加载到数组中的JVM指令

数组文字被转换为字节码,用值填充数组,因此每个数字需要多几个字节

为什么不将数据移出到静态初始值设定项块中类加载时加载的资源中?这可以通过使用MyClass.class.getClassLoader().getResourceAsStream()轻松完成。不管怎么说,这似乎是它的归属


或者更好的是,使用可用的Java工具在静态初始值设定项块中创建随机值。如果您需要可重复的“随机”数字,则每次只需使用固定但随机选择的数字为
随机
实例种子。

以下是用于初始化带有{1000001、1000002、1000003}的数组的字节码:

 5  iconst_3
 6  newarray int [10]
 8  dup
 9  iconst_0
10  ldc <Integer 1000001> [12]
12  iastore
13  dup
14  iconst_1
15  ldc <Integer 1000002> [13]
17  iastore
18  dup
19  iconst_2
20  ldc <Integer 1000003> [14]
22  iastore
23  putfield net.jstuber.test.TestArrayInitializingConstructor.data : int[] [15]
5 iconst_3
6新数组整数[10]
8次重复
9 iconst_0
10最不发达国家[12]
12 iStore
13次重复
14 iconst_1
15最不发达国家[13]
17 iStore
18次重复
19 iconst_2
20最不发达国家[14]
22 iStore
23 putfield net.jstuber.test.TestArrayInitializingConstructor.data:int[][15]
因此,对于这个小数组,每个元素需要5字节的Java字节码。对于较大的数组,数组索引和常量池中的索引对大多数元素都将使用3个字节,这导致每个数组元素使用8个字节。因此,对于10000个元素,需要大约80kB的字节码

用于初始化具有16位索引的大型阵列的代码如下所示:

2016  dup
2017  sipush 298
2020  ldc_w <Integer 100298> [310]
2023  iastore
2024  dup
2025  sipush 299
2028  ldc_w <Integer 100299> [311]
2016 dup
2017年sipush 298
2020最不发达国家西部[310]
2023年国际存储
2024 dup
2025年西普什299
2028年最不发达国家西部[311]

一种更简单、更实用的方法是将数字以二进制格式或文本形式存储在文件中


我不知道是什么java用这种方式初始化数组,但它不能有效地初始化大型数组。

11个字符乘以10000个条目等于110000字节,或多或少。绝对超过极限为什么这个答案被否决了?这是正确的,以一种最简单的方式。我相当肯定错误消息中引用的“代码”是指生成的字节码。在阅读这篇文章时,我发现这个限制适用于所有方法(包括构造函数)以及静态初始值设定项。有趣!正在测试的环境不允许文件I/O访问。但是您正在加载类,因此您可能可以执行MyClass.class.getResourceAsStream()并从打包应用程序的jar中加载它。这应该总是可能的。所以我猜这就是我所期望的,只是让人惊讶的是数组文本初始化代码>25000字节(我确信在类/方法/等的设置中会有一些小开销)。你可以使用javap来查看发生了什么。字符串文本是专门处理的吗?它们是唯一的东西吗?通过将数据打包成字符串文字来初始化数组是否有意义[可能是说,对于
int
值,数字+/-16383存储为一个字符,+/-268435455或某些其他选择值存储为两个,其他任何值存储为三个]?@supercat是的,这可以工作。每个字符串使用两个常量池索引,一个用于字符串(),另一个用于实际UTF-8数据()。就我所见,没有其他任意大小的常量类型(参见4.4常量池)。虽然我宁愿使用资源也不愿使用这种黑客。