Solución:
Estrictamente hablando, el formato de archivo de clase JVM limita el número de métodos (incluidos todos los constructores) para una clase a menos de 65536. Y según Tom Hawtin, el límite efectivo es 65527. Cada firma de método ocupa un espacio en el grupo constante. Dado que algunas de las entradas del grupo 65535 son (inevitablemente) consumidas por otras cosas, no es posible que un archivo de clase bien formado utilice todos los identificadores de método / constructor posibles.
Referencia – JVMS 4.1 La estructura de ClassFile
Sin embargo, si escribe código Java sensato de la forma habitual, no encontrará ese límite.
Cuantos deberían ¿tú tienes? Depende de los casos de uso de las clases. A menudo es bueno tener múltiples sobrecargas de constructores de “conveniencia” e implementarlas usando this(...)
encadenar a un constructor “maestro”. (Sin embargo, puede pasar por alto. Hay N! Combinaciones posibles (sobrecargas) de N parámetros distintos).
Si encuentra que está escribiendo un número excesivo (¡subjetivo!) De constructores, tal vez debería buscar alternativas como el Patrón de constructor.
Al igual que con el número máximo de lambdas o el máximo de invocaciones de métodos anidados, tenemos que hacer una distinción entre la especificación formal del lenguaje Java y los límites técnicos, ya sea debido al formato de archivo de clase especificado formalmente o debido a limitaciones o errores del compilador.
Como suele ocurrir, la especificación del lenguaje no define ningún límite en el número de constructores. Entonces, solo existe la limitación práctica de que la declaración de clase debe ser representable en el formato de código de bytes.
Los constructores se compilan en métodos especiales (llamados <init>
), por lo que en el archivo de clase, comparten una tabla con métodos ordinarios, que está limitada a 65535 entradas. Podemos maximizar esto al no declarar ningún método ordinario. Además, dado que cada constructor debe tener una firma distinta, cada constructor necesita su propia cadena de firma de tipo en el grupo constante, que está limitada a 65534 entradas por sí sola.
El grupo constante también sirve para otros propósitos, como mantener la declaración de esta clase, superclase y el nombre de la Code
atributo, que es necesario cuando se tienen constructores, así como la información de enlace del constructor de la superclase, que tenemos que invocar, por lo que este es el factor limitante en el lado del archivo de clase.
Por lo tanto, las entradas de grupo constantes mínimas necesarias son
- nombre de superclase (entrada UTF8 modificada)
- super class (tipo Class, refiriéndose a 1.)
- este nombre de clase (entrada UTF8 modificada)
- esta clase (tipo Class, refiriéndose a 3.)
- el nombre del “método” del constructor
<init>
(entrada UTF8 modificada) - una entrada de nombre y tipo que hace referencia a 5. y una firma de superconstructor (se puede compartir con una de las firmas de nuestro constructor)
- una entrada de método que hace referencia a 2. y 6. (para la invocación del superconstructor)
- el nombre del atributo
Code
(entrada UTF8 modificada)
Dadas estas entradas requeridas y el límite de 65534 entradas (el tamaño más uno se almacena como una cantidad de dos bytes sin firmar), obtenemos un límite de archivo de clase de 65526 constructores y, de hecho, podría generar un archivo de clase válido usando la biblioteca ASM con ese número de constructores y no más.
En realidad, podría obtener más si nombra su clase java.lang.Object
, como en ese caso especial, no hay superclase para declarar ni superconstructor para invocar. Decida usted mismo, a qué límite real desea llamar al número máximo …
Como se dijo, hay una tercera limitación, la implementación del compilador. Cuando utilice un compilador de Java, debe asegurarse de que no genere información de depuración (en caso de javac
, usar -g:none
) y ningún otro atributo opcional que pueda ocupar constantes entradas de grupo. Pero con javac
de JDK11, el rendimiento se reducirá significativamente cuando comience a definir muchos constructores. Obtuve los siguientes tiempos de compilación:
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
Entonces javac
finalmente logró maximizar el límite de archivos de clase, pero podemos considerar un límite práctico incluso antes de eso.
El compilador de Eclipse parece manejar mejor con tales archivos fuente, pero aún así, maximizar el número de constructores hizo que el IDE fuera casi inutilizable. Con los símbolos de depuración desactivados y un poco de paciencia, logré compilar una clase con 65526 constructores con Eclipse. Declarar 65528 constructores produjo un mensaje de error con respecto a demasiadas entradas de grupo constantes y declarar que los constructores 65527 revelaron un error en Eclipse, produciendo un archivo de clase corrupto declarando cero entradas de grupo constante (como se dijo anteriormente, el número se almacena como contar más uno, por lo que los proveedores de compiladores deben tener en cuenta que el límite no es 65535 sino 65534).
Sobrecarga del constructor de soporte de Java (cuando la clase java contiene varios constructores, se llama porque el constructor está sobrecargado). Una clase puede tener varios constructores, siempre que su firma (parámetro) no sea la misma. .No hay límite. Aquí hay un ejemplo: –
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;
}
}