¿Cómo llamo a un constructor de otro en Java?

¿Es posible llamar a un constructor desde otro (dentro de la misma clase, no desde una subclase)? Si es así, ¿cómo? ¿Y cuál podría ser la mejor forma de llamar a otro constructor (si hay varias formas de hacerlo)?

preguntado el 12 de noviembre de 08 a las 18:11

Creo que la premisa de su pregunta es incorrecta. En lugar de llamar a un constructor dentro de un constructor, use el patrón Factory. Un método de fábrica estático primero crea todos los objetos de nivel inferior. Luego construye los objetos de nivel superior que obtienen devoluciones de la llamada de fábrica. Esta técnica elimina la complejidad del modelo que ayuda al mantenimiento, la claridad y las pruebas. -

En general, cambié a constructores privados y métodos de fábrica, ya que los constructores, debido a sus limitaciones, están violando el principio de abierto-cerrado. Creo que este comentario debería ser la respuesta correcta, todo lo demás confundirá muchísimo a tus compañeros de equipo. -

Sroy, pero esa no es una buena práctica si quieres hacer algo así, sobrecargar al constructor. Si desea envolver un contenido, puede hacerlo, pero para otro propósito. No es el constructor public class Foo {private int x; public Foo () {} public Foo (int x) {this.x = x; } public Foo (int x, int y) {this.x = x; this.y = y} -

23 Respuestas

Sí, es posible:

public class Foo {
    private int x;

    public Foo() {
        this(1);
    }

    public Foo(int x) {
        this.x = x;
    }
}

Para encadenar a un constructor de superclase en particular en lugar de uno en la misma clase, use super en lugar de this. Tenga en cuenta que solo puedes encadenar a un constructor y tiene que ser la primera declaración en el cuerpo de su constructor.

Vea también esta pregunta relacionada, que trata sobre C # pero donde se aplican los mismos principios.

contestado el 23 de mayo de 17 a las 13:05

Entonces, supuse que no es posible llamar a un superconstructor y a otro constructor de la misma clase, ya que ambos deben ser la primera línea. - gsingh2011

@ gsingh2011: De hecho. Solo puedes encadenarte a . otro constructor. - jon skeet

Esto tiene que aparecer en la primera línea, pero puede hacer cálculos en el constructor antes de que se llame: Puede usar métodos estáticos en los argumentos de this () en la primera línea y encapsular cualquier cálculo que deba realizarse antes de la llamada. al otro constructor en ese método estático. (He agregado esto como una respuesta separada). - Papas fritas cristianas

@ gsingh2011 Sé que es tarde, pero como una forma de evitarlo, puede llamar al constructor sobrecargado usando este (...) y luego, en ese constructor sobrecargado, puede hacer una llamada al constructor de la clase base usando super (...) - Ali

Sé que llego tarde a la sección de comentarios, pero no entiendo por qué new Foo(1); no funcionaría? - Andrei

Usar this(args). El patrón preferido es trabajar desde el constructor más pequeño hasta el más grande.

public class Cons {

    public Cons() {
        // A no arguments constructor that sends default values to the largest
        this(madeUpArg1Value,madeUpArg2Value,madeUpArg3Value);
    }

    public Cons(int arg1, int arg2) {
       // An example of a partial constructor that uses the passed in arguments
        // and sends a hidden default value to the largest
        this(arg1,arg2, madeUpArg3Value);
    }

    // Largest constructor that does the work
    public Cons(int arg1, int arg2, int arg3) {
        this.arg1 = arg1;
        this.arg2 = arg2;
        this.arg3 = arg3;
    }
}

También puede utilizar un enfoque recomendado más recientemente de valueOf o simplemente "of":

public class Cons {
    public static Cons newCons(int arg1,...) {
        // This function is commonly called valueOf, like Integer.valueOf(..)
        // More recently called "of", like EnumSet.of(..)
        Cons c = new Cons(...);
        c.setArg1(....);
        return c;
    }
} 

Para llamar a una superclase, use super(someValue). La llamada a super debe ser la primera llamada en el constructor o obtendrá un error del compilador.

Respondido 26 ago 19, 10:08

Si se utilizan muchos parámetros de constructor, considere un constructor. Consulte el artículo 2 de "Java eficaz" de Joshua Bloch. - koppor

El problema con la implementación del último enfoque utilizando el método de fábrica, newCons, es que está intentando cambiar el estado de un objeto, utilizando setArg1(...), que probablemente debería tener sus campos configurados como finales. Como intentamos mantener la mayor cantidad posible de un objeto inmutable, si no completamente, un patrón de construcción abordará este problema de manera más correcta. - Yoyó

¿No preferirías hacer :: public Cons () {this (madeUpArg1Value, madeUpArg2Value); } - SeñorHieros

@ RodneyP.Barbati Es bastante común en Java que los constructores de nivel inferior llamen a constructores de nivel superior y luego no hagas nada mas. si una clase K tiene, por ejemplo, dos campos finales a, b, entonces el "constructor general" sería K(A a, B b) { this.a = a; this.b = b; }. Entonces sí b tiene un valor predeterminado razonable, puede haber un constructor de un argumento K(A a) { this(a, DEFAULT_B); }y si hay un valor predeterminado a además, tenemos un constructor predeterminado: K() { this(DEFAULT_A); }. Esa es una convención bastante común en Java. - josue taylor

@ RodneyP.Barbati Si tiene un campo final (por lo que debe establecerse), entonces el constructor predeterminado debería establecerlo. Si sus constructores superiores llaman al constructor predeterminado (lo que debería hacerse antes que cualquier otra cosa), entonces los constructores superiores nunca tienen opciones para establecer ninguno de esos campos. - josue taylor

[Nota: solo quiero agregar un aspecto, que no vi en las otras respuestas: cómo superar las limitaciones del requisito de que este () debe estar en la primera línea).]

En Java, se puede llamar a otro constructor de la misma clase desde un constructor a través de this(). Sin embargo, tenga en cuenta que this tiene que estar en la primera línea.

public class MyClass {

  public MyClass(double argument1, double argument2) {
    this(argument1, argument2, 0.0);
  }

  public MyClass(double argument1, double argument2, double argument3) {
    this.argument1 = argument1;
    this.argument2 = argument2;
    this.argument3 = argument3;
  }
}

Esa this tiene que aparecer en la primera línea parece una gran limitación, pero puede construir los argumentos de otros constructores a través de métodos estáticos. Por ejemplo:

public class MyClass {

  public MyClass(double argument1, double argument2) {
    this(argument1, argument2, getDefaultArg3(argument1, argument2));
  }

  public MyClass(double argument1, double argument2, double argument3) {
    this.argument1 = argument1;
    this.argument2 = argument2;
    this.argument3 = argument3;
  }

  private static double getDefaultArg3(double argument1, double argument2) {
    double argument3 = 0;

    // Calculate argument3 here if you like.

    return argument3;

  }

}

Respondido 10 Feb 16, 02:02

Es cierto que puede llamar a métodos estáticos de esta manera para realizar cálculos complejos para valores de argumentos, lo cual está bien. Sin embargo, si uno siente que se necesita código antes de la delegación del constructor (this(...)) entonces sería razonable suponer que se ha cometido un error horrible en alguna parte y que el diseño tal vez necesite un replanteamiento. - Ingeniero de software

Estaría de acuerdo en que un La transformación compleja probablemente indica un problema de diseño. Pero 1) hay algunas transformaciones simples para las cuales esto puede ser útil - no todos los constructores son solo proyecciones lineales en otros y 2) puede haber otra situación en la que esta información podría convertirse en manual, como soportar código heredado. (Si bien estoy de acuerdo con su conclusión, no veo por qué justificaría una votación en contra). - Papas fritas cristianas

@ RodneyP.Barbati: Veo algunos problemas al hacerlo de la forma en que lo describe: a) Al hacerlo de esa manera, no es posible ilustrar el uso del método estático en un constructor (y esa es la intención del ejemplo); -) yb) si lo hace a su manera, los campos no se pueden final (los campos finales solo se pueden inicializar una vez). - Papas fritas cristianas

@ RodneyP.Barbati: Otros dos aspectos: c) Creo que siempre debes hacer la inicialización del objeto en un solo punto, que tiene que ser el constructor más general. Si la inicialización del objeto requiere una tarea compleja (el objeto init no es perezoso) o verificar o adquirir algunos recursos (como un archivo), entonces le gustaría hacerlo solo una vez. Y d) Agregando otro argumento (digamos argumento4) para el cual la inicialización depende del valor de argumento1 a argumento3, tendría que cambiar todos los constructores en su caso, mientras que aquí solo tiene que agregar uno y dejar que el 3-arg llame al 4 -arg constructor. - Papas fritas cristianas

Para un método más general de superar la limitación "debe ser la primera declaración en el constructor", consulte esta respuesta. Se aplica a ambos super() y this() llamadas. - John McClane

Cuando necesito llamar a otro constructor desde dentro del código (no en la primera línea), generalmente uso un método auxiliar como este:

class MyClass {
   int field;


   MyClass() {
      init(0);
   } 
   MyClass(int value) {
      if (value<0) {
          init(0);
      } 
      else { 
          init(value);
      }
   }
   void init(int x) {
      field = x;
   }
}

Pero la mayoría de las veces trato de hacerlo al revés llamando a los constructores más complejos de los más simples en la primera línea, en la medida de lo posible. Para el ejemplo anterior

class MyClass {
   int field;

   MyClass(int value) {
      if (value<0)
         field = 0;
      else
         field = value;
   }
   MyClass() {
      this(0);
   }
}

Respondido 24 Abr '13, 00:04

Dentro de un constructor, puede utilizar el this palabra clave para invocar a otro constructor en la misma clase. Hacerlo se llama invocación explícita del constructor.

Aquí hay otra clase Rectangle, con una implementación diferente a la de la sección Objetos.

public class Rectangle {
    private int x, y;
    private int width, height;

    public Rectangle() {
        this(1, 1);
    }
    public Rectangle(int width, int height) {
        this( 0,0,width, height);
    }
    public Rectangle(int x, int y, int width, int height) {
        this.x = x;
        this.y = y;
        this.width = width;
        this.height = height;
    }

}

Esta clase contiene un conjunto de constructores. Cada constructor inicializa algunas o todas las variables miembro del rectángulo.

Respondido 12 Feb 16, 01:02

¿Por qué no llamas al segundo constructor que es Rectangle(int width, int height) in Rectangle() en lugar de Rectangle(int x, int y, int width, int height) ? - ANjaNA

@ RodneyP.Barbati No puedo estar de acuerdo en este caso. Ese patrón no permite campos finales. - Wes

Como todo el mundo ya ha dicho, usa this(…), que se llama invocación explícita del constructor.

Sin embargo, tenga en cuenta que dentro de una declaración de invocación de constructor tan explícita no puedes referirte a

  • cualquier variables de instancia or
  • cualquier métodos de instancia or
  • cualquier clases internas declarado en esta clase o en cualquier superclase, o
  • this or
  • super.

Como se indica en JLS (§8.8.7.1).

contestado el 07 de mayo de 15 a las 23:05

Sí, cualquier número de constructores puede estar presente en una clase y pueden ser llamados por otro constructor usando this() [Por favor, no confunda this() llamada al constructor con this palabra clave]. this() or this(args) debería ser la primera línea del constructor.

Ejemplo:

Class Test {
    Test() {
        this(10); // calls the constructor with integer args, Test(int a)
    }
    Test(int a) {
        this(10.5); // call the constructor with double arg, Test(double a)
    }
    Test(double a) {
        System.out.println("I am a double arg constructor");
    }
}

Esto se conoce como sobrecarga del constructor.
Tenga en cuenta que para el constructor, solo se aplica el concepto de sobrecarga y no la herencia ni la anulación.

Respondido el 21 de junio de 18 a las 06:06

Sí, es posible llamar a un constructor desde otro. Pero hay una regla para ello. Si se realiza una llamada de un constructor a otro, entonces

esa nueva llamada al constructor debe ser la primera declaración en el constructor actual

public class Product {
     private int productId;
     private String productName;
     private double productPrice;
     private String category;

    public Product(int id, String name) {
        this(id,name,1.0);
    }

    public Product(int id, String name, double price) {
        this(id,name,price,"DEFAULT");
    }

    public Product(int id,String name,double price, String category){
        this.productId=id;
        this.productName=name;
        this.productPrice=price;
        this.category=category;
    }
}

Entonces, algo como a continuación no funcionará.

public Product(int id, String name, double price) {
    System.out.println("Calling constructor with price");
    this(id,name,price,"DEFAULT");
}

Además, en el caso de la herencia, cuando se crea el objeto de la subclase, primero se llama al constructor de la superclase.

public class SuperClass {
    public SuperClass() {
       System.out.println("Inside super class constructor");
    }
}
public class SubClass extends SuperClass {
    public SubClass () {
       //Even if we do not add, Java adds the call to super class's constructor like 
       // super();
       System.out.println("Inside sub class constructor");
    }
}

Por lo tanto, en este caso también se declara primero otra llamada al constructor antes que cualquier otra declaración.

Respondido 22 ago 18, 18:08

Te diré una manera facil

Existen dos tipos de constructores:

  1. Constructor predeterminado
  2. Constructor parametrizado

Lo explicaré en un ejemplo

class ConstructorDemo 
{
      ConstructorDemo()//Default Constructor
      {
         System.out.println("D.constructor ");
      }

      ConstructorDemo(int k)//Parameterized constructor
      {
         this();//-------------(1)
         System.out.println("P.Constructor ="+k);       
      }

      public static void main(String[] args) 
      {
         //this(); error because "must be first statement in constructor
         new ConstructorDemo();//-------(2)
         ConstructorDemo g=new ConstructorDemo(3);---(3)    
       }
   }                  

En el ejemplo anterior, mostré 3 tipos de llamadas.

  1. this () llamada a this debe ser la primera declaración en el constructor
  2. Este es el objeto sin nombre. esto llama automáticamente al constructor predeterminado. 3. Esto llama al constructor parametrizado.

Nota: esta debe ser la primera declaración en el constructor.

Respondido el 19 de diciembre de 17 a las 05:12

Tienes lo siguiente en el método principal: //esto(); error porque "debe ser la primera declaración en el constructor Esta afirmación no tiene mucho sentido. Si estas tratando de decir eso esto() no se puede llamar desde adentro principal método, entonces sí, no puede ser porque main es estático y no tendrá referencia a esto() - SR Chaitanya

Puede crear un constructor de otro constructor de la misma clase utilizando la palabra clave "this". Ejemplo -

class This1
{
    This1()
    {
        this("Hello");
        System.out.println("Default constructor..");
    }
    This1(int a)
    {
        this();
        System.out.println("int as arg constructor.."); 
    }
    This1(String s)
    {
        System.out.println("string as arg constructor..");  
    }

    public static void main(String args[])
    {
        new This1(100);
    }
}

Salida - cadena como constructor arg .. Constructor predeterminado .. int como constructor arg ..

respondido 27 nov., 15:19

Llamar al constructor desde otro constructor

class MyConstructorDemo extends ConstructorDemo
{
    MyConstructorDemo()
    {
        this("calling another constructor");
    }
    MyConstructorDemo(String arg)
    {
        System.out.print("This is passed String by another constructor :"+arg);
    }
}

También puede llamar al constructor padre usando super() llamar al

respondido 03 mar '17, 09:03

Bastante simple

public class SomeClass{

    private int number;
    private String someString;

    public SomeClass(){
        number = 0;
        someString = new String();
    }

    public SomeClass(int number){
        this(); //set the class to 0
        this.setNumber(number); 
    }

    public SomeClass(int number, String someString){
        this(number); //call public SomeClass( int number )
        this.setString(someString);
    }

    public void setNumber(int number){
        this.number = number;
    }
    public void setString(String someString){
        this.someString = someString;
    }
    //.... add some accessors
}

ahora aquí hay un pequeño crédito adicional:

public SomeOtherClass extends SomeClass {
    public SomeOtherClass(int number, String someString){
         super(number, someString); //calls public SomeClass(int number, String someString)
    }
    //.... Some other code.
}

Espero que esto ayude.

Respondido el 23 de enero de 19 a las 15:01

Sí, es posible llamar a un constructor desde otro con el uso de this()

class Example{
   private int a = 1;
   Example(){
        this(5); //here another constructor called based on constructor argument
        System.out.println("number a is "+a);   
   }
   Example(int b){
        System.out.println("number b is "+b);
   }

Respondido 11 Abr '18, 03:04

La palabra clave este se puede usar para llamar a un constructor desde un constructor, al escribir varios constructores para una clase, hay ocasiones en las que le gustaría llamar a un constructor desde otro para evitar el código duplicado.

A continuación hay un enlace en el que explico otro tema sobre constructor y getters () y setters () y usé una clase con dos constructores. Espero que las explicaciones y los ejemplos te ayuden.

Setter métodos o constructores

contestado el 23 de mayo de 17 a las 13:05

Hay patrones de diseño que cubren la necesidad de una construcción compleja; si no se puede hacer de manera sucinta, cree un método de fábrica o una clase de fábrica.

Con la última versión de Java y la adición de lambdas, es fácil crear un constructor que pueda aceptar cualquier código de inicialización que desee.

class LambdaInitedClass {

   public LamdaInitedClass(Consumer<LambdaInitedClass> init) {
       init.accept(this);
   }
}

Llámalo con ...

 new LambdaInitedClass(l -> { // init l any way you want });

respondido 13 nov., 17:23

Sé que hay tantos ejemplos de esta pregunta, pero lo que encontré lo estoy poniendo aquí para compartir mi idea. Hay dos formas de encadenar el constructor. En la misma clase, puede utilizar esta palabra clave. en Herencia, debe usar super palabra clave.

    import java.util.*;
    import java.lang.*;

    class Test
    {  
        public static void main(String args[])
        {
            Dog d = new Dog(); // Both Calling Same Constructor of Parent Class i.e. 0 args Constructor.
            Dog cs = new Dog("Bite"); // Both Calling Same Constructor of Parent Class i.e. 0 args Constructor.

            // You need to Explicitly tell the java compiler to use Argument constructor so you need to use "super" key word
            System.out.println("------------------------------");
            Cat c = new Cat();
            Cat caty = new Cat("10");

            System.out.println("------------------------------");
            // Self s = new Self();
            Self ss = new Self("self");
        }
    }

    class Animal
    {
        String i;

        public Animal()
        {
            i = "10";
            System.out.println("Animal Constructor :" +i);
        }
        public Animal(String h)
        {
            i = "20";
            System.out.println("Animal Constructor Habit :"+ i);
        }
    }

    class Dog extends Animal
    {
        public Dog()
        {
            System.out.println("Dog Constructor");
        }
        public Dog(String h)
        {
            System.out.println("Dog Constructor with habit");
        }
    }

    class Cat extends Animal
    {
        public Cat()
        {
            System.out.println("Cat Constructor");
        }
        public Cat(String i)
        {
            super(i); // Calling Super Class Paremetrize Constructor.
            System.out.println("Cat Constructor with habit");
        }
    }

    class Self
    {
        public Self()
        {
            System.out.println("Self Constructor");
        }
        public Self(String h)
        {
            this(); // Explicitly calling 0 args constructor. 
            System.out.println("Slef Constructor with value");
        }
    }

Respondido 13 Feb 18, 14:02

Se llama anti-patrón de constructor telescópico o encadenamiento de constructor. Sí, definitivamente puedes hacerlo. Veo muchos ejemplos arriba y quiero agregar diciendo que si sabe que solo necesita dos o tres constructores, podría estar bien. Pero si necesita más, intente utilizar un patrón de diseño diferente como el patrón Builder. Como por ejemplo:

 public Omar(){};
 public Omar(a){};
 public Omar(a,b){};
 public Omar(a,b,c){};
 public Omar(a,b,c,d){};
 ...

Puede que necesite más. El patrón de constructor sería una gran solución en este caso. Aquí hay un artículo, puede ser útil. https://medium.com/@modestofiguereo/design-patterns-2-the-builder-pattern-and-the-telescoping-constructor-anti-pattern-60a33de7522e

Respondido el 06 de junio de 18 a las 20:06

Puede llamar a otro constructor a través del this(...) palabra clave (cuando necesita llamar a un constructor de la misma clase) o la super(...) palabra clave (cuando necesita llamar a un constructor de una superclase).

Sin embargo, tal llamada debe ser la en el primer declaración de su constructor. A superar esta limitación, uso esta respuesta.

Respondido 29 Jul 18, 02:07

Sí, puede llamar a constructores desde otro constructor. Por ejemplo:

public class Animal {
    private int animalType;

    public Animal() {
        this(1); //here this(1) internally make call to Animal(1);
    }

    public Animal(int animalType) {
        this.animalType = animalType;
    }
}

también puede leer en detalle desde Encadenamiento de constructores en Java

Respondido el 20 de junio de 20 a las 10:06

Originalmente de un anser de Mirko Klemm, ligeramente modificado para abordar la pregunta:

Solo para completar: también está el Bloque de inicialización de instancia que se ejecuta siempre y antes de que se llame a cualquier otro constructor. Consiste simplemente en un bloque de declaraciones "{...}" en algún lugar del cuerpo de la definición de su clase. Incluso puedes tener más de uno. No puede llamarlos, pero son como un código de "constructor compartido" si desea reutilizar algún código entre constructores, de forma similar a los métodos de llamada.

Entonces en tu caso

{ 
  System.out.println("this is shared constructor code executed before the constructor");
  field1 = 3;
}

También hay una versión "estática" de esto para inicializar miembros estáticos: "static {...}"

contestado el 24 de mayo de 19 a las 17:05

Prefiero esta forma:

    class User {
        private long id;
        private String username;
        private int imageRes;

    public User() {
        init(defaultID,defaultUsername,defaultRes);
    }
    public User(String username) {
        init(defaultID,username, defaultRes());
    }

    public User(String username, int imageRes) {
        init(defaultID,username, imageRes);
    }

    public User(long id, String username, int imageRes) {
        init(id,username, imageRes);

    }

    private void init(long id, String username, int imageRes) {
        this.id=id;
        this.username = username;
        this.imageRes = imageRes;
    }
}

Respondido el 19 de junio de 19 a las 09:06

Usando esta palabra clave podemos llamar a un constructor en otro constructor dentro de la misma clase.

Ejemplo: -

 public class Example {
   
      private String name;
   
      public Example() {
          this("Mahesh");
      }

      public Example(String name) {
          this.name = name;
      }

 }

Respondido el 16 de enero de 21 a las 02:01

Sí, es posible

public class User {

 private String name = "";
 private String surname = "";
 private int age = 0;
 public User(){
    this("name is undefined","surname is undefined",0);
 }
    public User(String name,String surname){
      this(name,surname,0);
   }


    public User(String name, String surname, int age) {
      this.name = name;
      this.surname = surname;
      this.age = age;
  }
}

Respondido 13 Feb 21, 18:02

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.