![](/img/trans.png)
[英]How can we create more than one instance of a class from single Java class file?
[英]In Java how many constructor can we create in one class?
在Java中,我们可以在单个类中创建多少个构造函数。
严格地说,JVM类文件格式将类的方法(包括所有构造函数)的数量限制为小于65536.根据Tom Hawtin,有效限制为65527.每个方法签名占用常量池中的一个插槽。 由于某些65535个池条目(不可避免地)被其他东西占用,因此格式良好的类文件不可能使用所有可能的方法/构造函数ID。
参考 - JVMS 4.1 ClassFile结构
但是,如果您以正常方式编写合理的Java代码,则不会遇到该限制。
你应该有多少? 这取决于类用例。 拥有多个“方便”构造函数重载通常很好,并使用this(...)
实现它们以链接到“主”构造函数。 (但是,你可以超越顶部。有N个不同参数的N!个可能组合(重载)。)
如果你发现你正在编写一个过多的(主观!)数量的构造函数,你应该看看构建器模式等替代方案。
与lambda的最大数量或嵌套方法调用 的最大数量一样,我们必须区分正式的Java语言规范和技术限制,这可能是由于正式指定的类文件格式或由于编译器限制或错误。
通常,语言规范没有对构造函数的数量进行任何限制。 因此,只有实际的限制是类声明必须以字节代码格式表示。
构造函数被编译为特殊方法(名为<init>
),因此在类文件中,它们使用普通方法共享一个表,该方法限制为65535个条目。 我们可以通过不宣布任何普通方法来最大化这一点。 此外,由于每个构造函数必须具有不同的签名,因此每个构造函数在常量池中需要其自己的类型签名字符串,其自身限制为65534个条目。
常量池还有其他用途,比如保存这个类的声明,超类和Code
属性的名称,这在构造函数时是必需的,以及超类构造函数的链接信息,我们必须调用,这是类文件方面的限制因素。
因此,所需的最小常量池条目是
<init>
(修改后的UTF8条目) Code
(修改后的UTF8条目) 给定这些必需的条目和65534个条目的限制(大小加一个存储为无符号的两个字节数量),我们得到65526个构造函数的类文件限制,实际上,我可以使用带有该数字的ASM库生成一个有效的类文件建设者而不是更多。
实际上,如果您将类命名为java.lang.Object
,则可以获得更多,因为在特殊情况下,没有要声明的超类,也没有要调用的超级构造函数。 决定你自己,你想要调用最大数量的实际限制......
如上所述,存在第三个限制,即编译器实现。 使用Java编译器时,必须确保它不会生成调试信息(如果是javac
,请使用-g:none
),并且不能生成可能占用常量池条目的其他可选属性。 但是使用JDK11的javac
,当你开始定义很多构造函数时,性能会显着下降。 我得到了以下编译时间:
1000 constructors: 1 second
2000 constructors: 2 seconds
5000 constructors: 10 seconds
10000 constructors: 1 minute
15000 constructors: 2 minutes
20000 constructors: 4 minutes
30000 constructors: 10 minutes
40000 constructors: 20 minutes
50000 constructors: between 25 minutes and ½ hour
65526 constructors: between 45 minutes and 1 hour
所以javac
最终设法最大化了类文件限制,但我们甚至可以考虑实际限制。
Eclipse编译器似乎更好地处理了这样的源文件,但是,最大化构造函数的数量使得IDE几乎无法使用。 关闭调试符号并且有点耐心,我设法用Eclipse编译了一个带有65526构造函数的类。 声明65528构造函数生成了关于太多常量池条目的错误消息,并且声明65527构造函数在Eclipse中发现了一个错误,产生了一个声明零常量池条目的损坏的类文件(如前所述,该数字存储为count加1 ,因此编译器供应商必须记住,限制不是65535而是65534)。
Java支持构造函数重载(当java类包含多个构造函数时,它被称为构造函数被重载)。一个类可以有多个构造函数,只要它们的签名(参数)不一样。所以你可以根据需要定义许多构造函数。没有限制。 这是一个例子: -
class Demo {
private String name;
private String city;
private Double salary;
public Demo() {
}
public Demo(String name) {
this.name = name;
}
public Demo(Double salary) {
this.city = city;
}
public Demo(String name,String city) {
this.name = name;
this.city = city;
}
}
一个类中可以有65535个构造函数(根据Oracle文档)。 但重要的是要记住这一点。 我们只通过CONSTRUCTOR OVERLOADING( https://beginnersbook.com/2013/05/constructor-overloading/ )实现这一目标。 您可以创建许多构造函数但具有不同的签名。
你可以在一个类中拥有尽可能多的构造函数.JAVA不会对类可以拥有的构造函数的数量施加任何限制。只需构造函数可以参数化或默认。
默认构造函数:默认构造函数没有参数,用于初始化具有相同数据的每个对象。
参数化构造函数:参数化构造函数具有一个或多个参数,用于使用不同的数据初始化每个对象。
TL;博士
对于具有合理功能的类,您将首先遇到其他问题,包括技术问题和非技术问题。 无用类的类文件格式的常量池所施加的技术限制是:
Code
的类(每个类加载器一个)。 java.lang.Object
的类(每个VM一个)。 细节
在我发布答案之前,问题已经结束。 所以这里有@Holger已经涵盖的内容。
JVM规范的相关部分是4.1。 Java SE 11版中的ClassFile结构 。
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
}
您可以在一个类中创建65535个构造函数
更多信息: Oracle Docs
一个类可以拥有的构造函数数量没有限制。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.