¿Por qué no se genera un constructor predeterminado si define un constructor explícito?

9
class Employee{

    String name;
    int id;

   //No explicit constructors
}

Ahora puedo invocar la siguiente declaración:

Employee e1 = new Employee();

Con el código anterior, el compilador proporcionará la definición del constructor Employee().

Si defino un único constructor explícito de la siguiente manera:

 class Employee{

    String name;
    int id;

    Employee(String aName){
        this.name=aName;
    }
}

Ahora, ¿por qué no puedo invocar la siguiente declaración:

Employee e2 = new Employee();

Aunque el compilador sabe cómo proporcionar definición de Employee().

Ahora, solo porque he definido un constructor explícito Employee(String aName), ¿por qué no puedo usar un constructor predeterminado?

Además, si el compilador hubiera permitido el uso del constructor predeterminado incluso después de definir uno explícito, nos habría ayudado a reutilizar el código para el constructor predeterminado.

Harish_N
fuente
77
Ya no sería un constructor predeterminado . Sería un constructor constante porque siempre está ahí.
Reactgular

Respuestas:

6

En primer lugar, el constructor predeterminado no se genera, lo proporciona el compilador si el constructor sin argumentos no se escribe explícitamente.

Cuando no escribe explícitamente un constructor sin argumentos para una clase, el compilador no se quejará mientras los objetos se construyan sin constructores de parámetros. )

Pero si define un constructor sin argumentos, al compilar, el compilador verificará la llamada al constructor y su definición en clase. Es como autenticar cualquier otro método de una clase.

Por lo tanto, dará un error si llama al constructor sin argumentos después de definir un constructor parametrizado, ya que no encuentra ningún constructor sin argumentos explícitamente definido en la clase. Y, esto es lógicamente correcto ya que, si desea bloquear la creación de objetos sin ningún dato, esta es una buena manera.

Por ejemplo, considere que un objeto de empleado debe tener una identificación de empleado asociada. Para lograr esto, defina un constructor de argumento único y no defina un constructor sin argumento.

Tyson
fuente
39

Un constructor con argumentos no es solo una taquigrafía útil para usar setters. Usted escribe un constructor para asegurarse de que un objeto nunca existirá sin ciertos datos presentes.

Si no existe tal requisito, está bien. Pero si hay uno, como lo indica el hecho de que ha escrito un constructor de este tipo, entonces sería irresponsable generar un constructor predeterminado, a través del cual un cliente podría eludir la regla de "ningún objeto sin datos". Doblemente, porque el constructor predeterminado generado automáticamente es invisible para un lector de código casual, lo que oculta el hecho de que existe. No, si desea constructores con argumentos y un constructor predeterminado, debe escribir el constructor predeterminado usted mismo. De todos modos, no es como si fuera un gran esfuerzo escribir un bloque vacío.

Kilian Foth
fuente
44
Bien dicho, si escribo un constructor con parámetros, es porque esos valores son necesarios para que las instancias de clase funcionen. Si tengo algunos valores predeterminados útiles, escribiré un constructor sin argumentos llamando al otro constructor mientras proporciono esos valores predeterminados.
Jwenting
+1. Además, si no puede garantizar que los campos se inicializarán en el constructor, nunca podría tener objetos inmutables, que es lo que debería preferir.
Doval
2
@Doval: que debería preferir, en determinadas situaciones. Como todo lo demás, los objetos inmutables tienen compensaciones que los hacen buenos para algunas situaciones y no para otras. Sin bala de plata.
whatsisname
1
@whatsisname Nunca lo llamó una bala de plata, pero es el mejor valor predeterminado.
Doval
Esta respuesta es muy útil para leer junto con la también buena respuesta de Konrad Morawski: su respuesta proporciona una buena analogía del mundo real para explicar esencialmente la misma respuesta.
cellepo
8

Java que genera un constructor sin parámetros cuando no tienes otro es como un camarero educado que toma tu abrigo por ti.

Java sigue generando un constructor sin parámetros después de definir otra versión del mismo, es como si el mismo camarero le quitara el abrigo después de dar una clara indicación de que tiene sus propios planes de qué hacer con el abrigo.

Si tengo una clase (que quiero ser inmutable):

class Person
{
    final String firstName;
    final String lastName;

Y agrego un constructor:

    Person(String firstName, String lastName) 
    {
        this.firstName = firstName;
        this.lastName = lastName;
    }
}

Y Java era todavía para proporcionar un constructor por defecto, sin parámetros, a continuación, este código no puede compilar, porque firstNamey lastNamecampos son declarados como final, sin embargo, no se establecen después de su llamada Person p = new Person().

Me estás obligando a proporcionar otra implementación:

private Person() 
{
    this.firstName = null; // or "", or whatever
    this.lastName = null;
}

Y como no lo quiero, ya que es inútil, me siento inclinado a ponerle calavera y huesos cruzados:

@Deprecated
private Person() 
{
    // don't use this constructor! i don't want it to ever be called!
    throw new RuntimeException("Illegal constructor called");
}

Pero todavía no puedo prohibir a otro desarrollador que cree un método (dentro de la Personclase, por lo que marcar el constructor como privado no ayudó):

public static Person createPerson()
{
    return new Person(); // this will blow in our face
}

Todo este alboroto podría evitarse, y se evita, gracias al hecho de que Java (y no solo Java) funciona de la manera en que funciona.

Si define un método setCoordinates(int x, int y), no espera que el compilador acepte automáticamente una versión sin parámetros del mismo setCoordinates(). No haría nada.

¿Cómo es esto diferente de esperar un constructor sin parámetros? Bueno, obviamente, un constructor siempre hace al menos una cosa: crea un objeto (o muere en el intento).

Pero me gusta tener el control de cómo quiero que se instancian mis objetos. Obligarme a tener un constructor sin parámetros, no importa lo que haga, me quita este control.

Konrad Morawski
fuente
Esta respuesta es muy útil para leer junto con la también buena respuesta de Kilian Foth. Me encanta la creatividad de la explicación / analogía del camarero / abrigo, que es válida y funciona.
cellepo
3

El lenguaje pone el constructor predeterminado como un favor para usted. La presunción es que si ha escrito un constructor personalizado, su constructor sin argumentos también puede requerir atención especial. No es una gran razón, pero tampoco es horrible.

La razón secundaria por la que ese ruft simplemente se acumula en ese idioma sin pensar en su simetría con la práctica existente y con muy poco interés en hacerlo legible. La "C con clases" original de Stoustroup era un preprocesador C pirateado que probablemente no debería salir del laboratorio. El mundo es divertido de esa manera.

msw
fuente
3

Si define un constructor con un parámetro, entonces debe haber una razón válida para hacerlo. Tal vez este parámetro es tan importante para su clase que sin él el estado del objeto no es válido. Es por eso que Java no crea un constructor sin argumentos para usted cuando ya define uno.

Si decide que sería útil tener un constructor sin argumentos, aún puede definirlo:

Employee(){
  // good practice to call existing constructor with your favorite value
  this("");
}
MaxZoom
fuente