Pergunta

Em Java, os construtores não podem ser recursiva.Erro de tempo de compilação:"recursiva construtor de invocação".Vamos supor que a gente não tem essa restrição.

Coisas para manter em mente:

  • O tipo de retorno de um construtor é nula.Uma vez que é um método void, você não pode aproveitar o poder completo do recursão.
  • Um construtor pode chamar propriamente dito (ou qualquer outro construtor) usando este().Mas uma "chamada para esta deve ser a primeira instrução no construtor"
  • Podemos usar dados locais entre chamadas consecutivas para ainda ter algum ganho possível a partir recursiva de construtores.

Haveria algum benefício de permitir recursiva de construtores?

Foi útil?

Solução

Construtores (quando eles estão chamando uns aos outros) são como métodos que retornam void.Consequentemente, a única maneira que eles podem produzir resultados é por efeitos colaterais.Este é, então, limitado a mutação e o objeto que eles estão construindo ou por mutação dos valores passados como parâmetros.O último é bastante desagradável idéia em um construtor;um construtor normalmente leva informações a partir de seus parâmetros sem mutação-los.

Assim, transformando-o objeto que está sendo construído é a única opção para ter alguma forma de acompanhar o andamento da recursão, para terminar, eventualmente.E é muito difícil ver como isso iria ser mais fácil de escrever, mais fácil de ler, etc.que um simples loop dentro de um ordinário de seu construtor.

Chamando outro construtor (com this) de dentro de um construtor é, claro, totalmente diferente do uso de um new expressão dentro de um construtor:

class Node
{
    Node _left, _right;

    public Node(Node left, Node right)
    {
        _left = left != null ? new Node(left._left, left._right) : null;
        _right = right != null ? new Node(right._left, right._right) : null;
    }
}

Aqui o Node construtor chama a si mesmo, mas através de uma nova expressão.Esta é a diferença crucial.Um new expressão produz um valor, de modo que este é meramente "funcional", " não-mutação de coisas, e fornece uma maneira conveniente para fazer uma cópia de profundidade da árvore de nós.

Outras dicas

Construtores podem ser recursivos. (Isso está em C#, mas você pode fazer a mesma coisa em Java)

Vamos olhar para esse problema. Primeiro de tudo, o que acontece quando você invoca new MyClass("foo");? Bem, há duas coisas acontecendo. Primeiro de tudo, a máquina virtual alocará a memória necessária para armazenar um objeto do tipo MyClass. Então, o construtor é chamado. O trabalho de um construtor é inicializar isso apenas a memória alocada. Portanto, um construtor não possui um tipo de retorno (nem mesmo nulo). O valor retornado pelo novo operador é uma referência à memória alocada, para que o construtor também não possa retornar.

Então, qual seria o benefício da invocação de construtor recursivo. O único benefício dessa invocação seria lidar com certos parâmetros do construtor como os outros e fazendo isso reinvando o construtor. Embora isso seja possível, geralmente é fácil apenas ajustar os valores no próprio construtor (usando parâmetros não finais) e, depois disso, inicialize os atributos do objeto (em abreviação, você não precisa recursão para isso).

Segundo, você pode fazer a recursão com bastante facilidade, descarregando todo o trabalho para um método de trabalhador que pode recorrer o quanto quiser.

Uma pergunta mais interessante é a restrição de super ou esta invocação sendo a primeira declaração do construtor. Essa restrição provavelmente foi colocada para desencorajar práticas de programação desleixadas ou inseguras. A declaração é colocada em negrito aqui, mas é possível (embora não seja bonita) contornar essa restrição. Se você se lembra que as expressões podem ter efeitos colaterais (por exemplo, atribuições variáveis) e expressões usadas para parâmetros são invocadas antes da chamada em si, é possível criar expressões complicadas que façam todos os seus cálculos antes de invocar o construtor de delegados.

A razão geral pela qual você deseja ter uma invocação de delegados/super construtores posteriormente no corpo do construtor é a manipulação de parâmetros. Você pode fazer isso com funções auxiliares (estáticas) que fazem esses cálculos e fornecem os valores corretos. Isso geralmente é mais limpo, mas não em todos os casos. A velocidade real da execução não deve ser afetada, pois o hotspot pode incluir muito bem essas coisas.

Isso significa que, no final, a consideração se resume a fornecer a flexibilidade da colocação gratuita de delegados/super chamadas versus a segurança adicionada, proporcionando práticas incorretas muito mais difíceis. A escolha feita pelos designers de Java (e a filosofia geral Java) é tornar mais difícil fazer as coisas erradas à custa do poder da linguagem bruta nas mãos de especialistas (com maior complexidade). A escolha feita é para mim um válido, embora eu pessoalmente gostaria do poder (sempre pode -se implementar uma linguagem Java ++ na JVM que não possui essas restrições).

Você pode não ser capaz de escrever um construtor recursivo, mas pode chamar uma função recursiva do seu construtor. Eu nunca tive que fazer isso antes e não consigo pensar em uma situação em que você possa precisar, mas você pode fazê -lo, se quiser.

O que você quer dizer com permitir? Você pode ter construtores recursivos em Java. Eles permitem que você reutilize o código e projete seus construtores de uma maneira mais hierárquica.

No seguinte exemplo de construtor recursivo, posso ligar new User() ou new User("Marcus") e com qualquer um construtor que eu uso, newUser está configurado para true.

public class User() {
  public String userName;
  public boolean newUser;
  User() {
    newUser = true;
  }
  User(String userName) {
    // Recursively call no-argument constructor
    this();
    this.userName = userName;
  }
}

Aqui está a mesma coisa sem construtores recursivos. Observe a linha duplicada de código:

public class User() {
  public String userName;
  public boolean newUser;
  User() {
    newUser = true;
  }
  User(String userName) {
    newUser = true;
    this.userName = userName;
  }
}

No exemplo do construtor não recursivo a seguir, se eu não passar um nome para o construtor, o nome será definido como "novo usuário". Eu só gostaria de ligar para o construtor sem argumento se não estiver definindo o nome. Se eu fizesse uma chamada de construtor recursivo aqui, acabaria definindo o nome de usuário duas vezes:

public class User() {
  public String userName;
  User() {
    this.userName = "New User";
  }
  User(String userName) {
    this.userName = userName;
  }
}

Você só usará construtores recursivos se você:

  1. Tem mais de um construtor
  2. Tem código em seus construtores
  3. Quero usar o código recursivamente em outro construtor

O tipo de retorno de um construtor é nulo.

Não, não é.

Um construtor pode se invocar (ou qualquer outro construtor) usando isso ()

Não. Ele só pode invocar outros construtores e somente se isso não levar a uma invocação recursiva do construtor atual. É por isso que você recebe a mensagem de erro a que você se referiu.

Poderíamos usar dados não locais entre chamadas consecutivas para ainda ter algum ganho possível de construtores recursivos.

Como? Por que você iria querer -Inializar um objeto? Quando você não pode fazer isso sequencialmente em um passe? Nunca tive esse problema em 39 anos de programação de computadores e 20 anos de OO.

Haveria algum benefício ao permitir construtores recursivos?

Você não inventou nenhum ...

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top