在Java中,我们可以在一个类中创建多少个构造函数。
答案 0 :(得分:19)
严格来说,JVM类文件格式将一个类的方法(包括所有构造函数)限制为少于65536。而且,根据汤姆·霍顿(Tom Hawtin)的说法,有效限制为65527。每个方法签名都在常量池中占用一个插槽。 。由于65535池条目中的某些条目(不可避免地)被其他事物消耗,因此格式良好的类文件不可能使用所有可能的方法/构造函数ID。
参考-JVMS 4.1 The ClassFile Structure
但是,如果您以正常方式编写明智的Java代码,则不会遇到该限制。
您应该有多少 ?这取决于类的用例。经常有多个“便利”构造函数重载,并使用this(...)
来实现它们以链接到“主”构造函数,这是很好的选择。 (但是,您可以转到顶部。N个不同参数的N个可能组合(重载)。)
如果发现编写的构造函数过多(主观!),则应考虑使用Builder Pattern之类的替代方案。
答案 1 :(得分:12)
与the maximum number of lambdas或the maximum of nested method invocations一样,由于正式指定的类文件格式或由于编译器的限制或错误,我们必须在正式的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几乎无法使用。在关闭调试符号并稍加耐心的情况下,我设法使用65565构造函数编译了一个类。声明65528构造函数会产生有关太多常量池条目的错误消息,并且声明65527构造函数会揭示Eclipse中的错误,从而生成一个损坏的类文件,声明零个常量池条目(如前所述,数字存储为 count加一/ em>,因此编译器供应商必须记住该限制不是65535,而是65534。)
答案 2 :(得分:6)
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;
}
}
答案 3 :(得分:2)
您可以在一个类中有65535个构造函数(根据Oracle文档)。但是重要的是要牢记这一点。我们仅通过构造器重载(https://beginnersbook.com/2013/05/constructor-overloading/)实现此目的。您可以创建许多构造函数,但是具有不同的签名。
答案 4 :(得分:0)
您可以在一个类中拥有任意数量的构造函数。.JAVA对一个类可以具有的构造函数数量没有任何限制。.构造函数可以是参数化的也可以是默认的。
默认构造函数:默认构造函数没有参数,用于初始化具有相同数据的每个对象。
参数化的构造函数:参数化的构造函数具有一个或多个参数,用于用不同的数据初始化每个对象。
答案 5 :(得分:0)
tl; dr
对于具有合理功能的课程,您首先会遇到技术和非技术方面的其他问题。对于无用的类,由类文件格式的常量池施加的技术限制是:
Code
的类(每个类加载器一个)。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
}
答案 6 :(得分:-1)
您可以在一个类中创建65535个构造函数
更多信息:Oracle Docs
答案 7 :(得分:-2)
一个类可以拥有的构造函数数量没有限制。