Por que não há construtor padrão gerado se você define um construtor explícito?

9
class Employee{

    String name;
    int id;

   //No explicit constructors
}

Agora eu posso invocar a seguinte declaração:

Employee e1 = new Employee();

Com o código acima, o compilador fornecerá a definição para o construtor Employee().

Se eu definir um único construtor explícito da seguinte maneira:

 class Employee{

    String name;
    int id;

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

Agora, por que não consigo invocar a seguinte declaração:

Employee e2 = new Employee();

Mesmo que o compilador saiba como fornecer a definição de Employee().

Agora, apenas porque eu defini um construtor explícito Employee(String aName), por que não posso usar um construtor padrão?

Além disso, se o compilador tivesse permitido o uso do construtor padrão, mesmo depois de definir um explícito, isso teria nos ajudado a reutilizar o código do construtor padrão.

Harish_N
fonte
7
Não seria mais um construtor padrão . Eu seria um construtor constante porque está sempre lá.
Reactgular

Respostas:

6

Primeiro de tudo, o construtor padrão não é gerado, é fornecido pelo compilador se o construtor sem argumento não for escrito explicitamente.

Quando você não escreve explicitamente um construtor sem argumento para uma classe, o compilador não irá reclamar enquanto os objetos forem construídos sem construtores de parâmetro (desde que o compilador permita que o construtor padrão crie objetos, o que por si só chama o construtor sem argumento) )

Mas se você definir um construtor sem argumento, ao compilar, o compilador verificará a chamada ao construtor e sua definição na classe. É como autenticar qualquer outro método de uma classe.

Portanto, ocorrerá um erro se você chamar o construtor sem argumento depois de definir um construtor parametrizado, pois ele não encontra nenhum construtor sem argumento definido explicitamente na classe. E isso é logicamente correto, pois, se você deseja bloquear a criação de objetos sem nenhum dado, é uma boa maneira.

Por exemplo, considere que um objeto de funcionário deve ter uma identificação de funcionário associada a ele. Para conseguir isso, defina um construtor de argumento único e não defina construtor sem argumento.

Tyson
fonte
39

Um construtor com argumentos não é apenas uma forma prática de usar setters. Você escreve um construtor para garantir que um objeto nunca existirá sem a presença de certos dados.

Se não houver esse requisito, tudo bem. Mas se houver, como indicado pelo fato de você ter escrito esse construtor, seria irresponsável gerar um construtor padrão, por meio do qual um cliente pudesse contornar a regra "nenhum objeto sem dados". Duplamente, porque o construtor padrão gerado automaticamente é invisível para um leitor de código casual, o que oculta o fato de que ele existe! Não, se você deseja construtores com argumentos e um construtor padrão, você deve escrever o construtor padrão. De qualquer forma, não é muito difícil escrever um bloco vazio.

Kilian Foth
fonte
4
bem dito, se eu escrever um construtor com parâmetros, é porque esses valores são necessários para que as instâncias de classe funcionem. Se eu tiver alguns padrões úteis, escreverei um construtor no-args chamando o outro construtor enquanto forneço esses padrões.
Jwenting
+1. Além disso, se você não pudesse garantir que os campos fossem inicializados no construtor, nunca poderia ter objetos imutáveis, que é o que você prefere.
Doval
2
@Doval: qual você prefere, em determinadas situações. Como todo o resto, objetos imutáveis ​​têm vantagens e desvantagens, tornando-os bons para algumas situações e não para outras. Nenhuma bala de prata.
Whatsisname
1
@whatsisname Nunca chamou de bala de prata, mas é o melhor padrão.
Doval
Esta resposta é muito útil para ler em conjunto com a também boa resposta de Konrad Morawski: Sua resposta fornece uma boa analogia do mundo real para explicar essencialmente a mesma resposta.
Cellepo # 25/18
8

O Java que gera um construtor sem parâmetros quando você não tem outro é como um garçom educado levando seu casaco para você.

O Java ainda está gerando um construtor sem parâmetros depois que você define outra versão, é como o mesmo garçom tirando o casaco depois de dar uma indicação clara de que você tem seus próprios planos do que fazer com o casaco.

Se eu tiver uma classe (que eu quero ser imutável):

class Person
{
    final String firstName;
    final String lastName;

E eu adiciono um construtor:

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

E o Java ainda precisava fornecer um construtor padrão, sem parâmetros, então esse código não pode ser compilado, porque firstNamee os lastNamecampos são declarados como finais, mas não são definidos após a chamada Person p = new Person().

Você está me forçando a fornecer outra implementação:

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

E como eu não quero - como é inútil, posso me sentir inclinado a colocar caveiras e ossos cruzados:

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

Mas ainda não posso proibir outro desenvolvedor de criar um método (dentro da Personclasse, marcar o construtor como privado não ajudou):

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

Todo esse barulho pode ser - e é - evitado graças ao fato de que o Java (e não apenas o Java) funciona da maneira que funciona.

Se você definir um método setCoordinates(int x, int y), não espera que o compilador aceite automaticamente uma versão sem parâmetros - setCoordinates(). Não faria nada.

Como isso é diferente de esperar um construtor sem parâmetros? Bem, obviamente, um construtor sempre faz pelo menos uma coisa - ele cria um objeto (ou morre tentando).

Mas eu gosto de controlar como quero que meus objetos sejam instanciados. Forçar-me a ter um construtor sem parâmetros, não importa o que eu faça, tira esse controle de mim.

Konrad Morawski
fonte
Esta resposta é muito útil para ler em conjunto com a também boa resposta de Kilian Foth. Adoro a criatividade da explicação / analogia do garçom / casaco, que é válida e funciona!
Cellepo # 25/18
3

O idioma coloca o construtor padrão como um favor para você. A suposição é que, se você escreveu um construtor personalizado, seu construtor sem argumentos também pode exigir atenção especial. Não é um ótimo motivo, mas também não é horrível.

A identificação da razão secundária que a sujeira simplesmente se acumula nessa linguagem sem pensar em sua simetria com a prática existente e com muito pouco interesse em torná-la legível. O "C com Classes" original do Stoustroup era um pré-processador C hackeado que provavelmente não deveria sair do laboratório. O mundo é engraçado assim.

msw
fonte
3

Se você definir um construtor com um parâmetro, deve haver um motivo válido para fazê-lo. Talvez esse parâmetro seja tão importante para sua classe que, sem ele, o estado do objeto é inválido. É por isso que o Java não cria um construtor sem argumento para você quando você já o define.

Se você decidir que seria útil ter um construtor no-arg, ainda poderá defini-lo:

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