tl;dr
对于具有合理功能的类,您首先会遇到其他问题,包括技术和非技术问题。类文件格式的常量池对无用类施加的技术限制是:
- 65526 用于具有您选择的名称的类。
- 65527 用于名为
Code 的类(每个类加载器一个)。
- 65530 用于名为
java.lang.Object 的类(每个 VM 一个)。
详情
在我发布答案之前,该问题已关闭。所以这里有一些关于@Holger 已经涵盖的内容。
JVM 规范的相关部分是 Java SE 11 版本中的4.1. The ClassFile Structure。
u2 constant_pool_count;
cp_info constant_pool[constant_pool_count-1];
注意-1。条目从 1 开始编号。0 用于表示:
- 没有超类的类(有趣!)
- 没有名字的形参
- 没有版本信息的模块
- 没有版本信息的模块依赖
如果该类被称为Code,则此字符串常量将使用所需的Code 属性名称进行重复数据删除(请参阅@Holger 的答案)。如果您想从默认包之外访问它,您将需要一个非常旧版本的 javac。
如果写入字节码不是作弊,则可以通过抛出null(不是字节码中的常量)而不是调用super() 或类似方法来删除几个条目。我不记得构造函数字节码验证的确切细节——如果不调用this() 或super(),它们肯定无法正常终止。
javac 运行越来越慢 (O(n^2)ish?) 是优雅降级的一个很好的例子。 :)
游戏时间
通过编译具有不同数量构造函数的小类,您可以很容易地看到这一点。
public class Min1 {
public Min1() {
}
/* Followed by (int a), (byte a), (int a, byte b), etc. */
}
在没有调试信息的情况下编译(人们还会不小心分发带有调试信息的类文件吗?)。
javac -g:none Min1.java
用好旧的javap列出内容。
javap -verbose Min1
应该给你类似的东西
Classfile /Users/tackline/code/scratch/minimal_class/Min1.class
Last modified Dec 5, 2018; size 119 bytes
MD5 checksum c1a6b7c31c286165e01cc4ff240e7718
public class Min1
minor version: 0
major version: 52
flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
#1 = Methodref #3.#7 // java/lang/Object."<init>":()V
#2 = Class #8 // Min1
#3 = Class #9 // java/lang/Object
#4 = Utf8 <init>
#5 = Utf8 ()V
#6 = Utf8 Code
#7 = NameAndType #4:#5 // "<init>":()V
#8 = Utf8 Min1
#9 = Utf8 java/lang/Object
{
public Min1();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
}