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

2450

¿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)?

4
  • 2
    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. 6/07/18 a las 19:49
  • 1
    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.
    Richard
    21/01/19 a las 12:27
  • 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}
    Augusto
    24/07/19 a las 19:16
  • Llamar a un constructor desde otro constructor en Java es principalmente un medio de proporcionar valores predeterminados para los parámetros al constructor que realmente debería construir su objeto, y luego debería ser suficiente con asignar valores en el cuerpo del constructor. Si su objeto requiere una construcción compleja, es un olor a código que indica que su clase carece de cohesión. Si un constructor no es suficiente para ti, probablemente hayas hecho un mal trabajo al diseñar tus clases, lo que descubrirás cuando sea el momento de hacer cambios en el futuro. 18 de marzo a las 16:36
3191

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 en superlugar de this. Tenga en cuenta que solo puede encadenar a un constructor , y debe ser la primera declaración en el cuerpo de su constructor .

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

20
  • 37
    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. 2/11/12 a las 18:02
  • 34
    @ gsingh2011: De hecho. Sólo se puede cadena a uno de otro constructor. 2 nov. 12 a las 18:06
  • 49
    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). 11/0313 a las 20:34
  • 10
    @ 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
    13 de mayo de 2013 a las 7:23
  • 2
    @Andrej: Eso sería "llamar a un constructor desde otro" pero no estaría haciendo lo que quiere el OP, que es inicializar un solo objeto a través de múltiples constructores, uno encadenado a otro. Crear dos objetos simplemente creando un objeto separado dentro de una llamada al constructor no es lo mismo en absoluto. 26/09/19 a las 22:10
273

Utilizando 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.

6
  • 28
    Si se utilizan muchos parámetros de constructor, considere un constructor. Consulte el artículo 2 de "Java eficaz" de Joshua Bloch.
    koppor
    13/11/12 a las 20:16
  • 5
    El problema con la implementación del último enfoque usando el método de fábrica newCons, es que está tratando de cambiar el estado de un objeto, usando setArg1(...), que probablemente debería tener sus campos configurados como finales. Como estamos tratando de 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.
    YoYo
    30 de enero de 2016 a las 6:46
  • 2
    ¿No preferirías hacer :: public Cons () {this (madeUpArg1Value, madeUpArg2Value); } 16/04/18 a las 13:31
  • 3
    @ RodneyP.Barbati Es bastante común en Java que los constructores de nivel inferior llamen a constructores de nivel superior y luego no hagan nada más . 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, si btiene un defecto razonable, no puede haber un constructor de una sola arg K(A a) { this(a, DEFAULT_B); }, y si hay un defecto aasí, tenemos un constructor por defecto: K() { this(DEFAULT_A); }. Esa es una convención bastante común en Java. 17 de mayo de 2018 a las 13:12
  • @ RodneyP.Barbati Si tiene un campo final (por lo que debe establecerse), entonces el constructor predeterminado tendría que 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. 17 de mayo de 2018 a las 13:14
228

[ 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, thistenga en cuenta que debe 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;
  }
}

Eso thistiene 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;

  }

}
5
  • dieciséis
    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 asumir que se ha cometido un error horrible en alguna parte y que el diseño tal vez necesite un replanteamiento. 8 de junio de 2016 a las 23:00
  • dieciséis
    Estoy de acuerdo en que una transformación muy 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 admitir código heredado. (Si bien estoy de acuerdo con su conclusión, no veo por qué justificaría una votación en contra). 16/06/2016 a las 17:36
  • 2
    @ 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 pueden ser final(los campos finales se pueden inicializar solo una vez). 13/06/18 a las 6:06
  • 1
    @ 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 de un objeto requiere una tarea compleja (la inicialización del objeto no es perezosa) 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. 13/06/18 a las 8:13
  • Para un método más general de superar la limitación de "debe ser la primera declaración en el constructor", consulte esta respuesta . Se aplica tanto super()y this()llamadas. 29/07/18 a las 1:34
41

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);
   }
}
30

Dentro de un constructor, puede usar la thispalabra clave para invocar a otro constructor en la misma clase. Hacerlo se denomina invocación explícita al 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.

2
  • 1
    ¿Por qué no llamas al segundo constructor que está Rectangle(int width, int height)en Rectangle()lugar de Rectangle(int x, int y, int width, int height)?
    ANjaNA
    18 de julio de 2015 a las 2:58
  • 1
    @ RodneyP.Barbati No puedo estar de acuerdo en este caso. Ese patrón no permite campos finales.
    Wes
    23 oct 2018 a las 12:30
18

Como todo el mundo ya ha dicho, use this(…), que se llama una 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 puede hacer referencia a

  • cualquier variable de instancia o
  • cualquier método de instancia o
  • cualquier clase interna declarada en esta clase o cualquier superclase, o
  • this o
  • super.

Como se indica en JLS (§8.8.7.1).

14

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 la this()llamada al constructor con la thispalabra clave]. this()o 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.

12

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

that new constructor call must be the first statement in the current constructor

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.

9

Te diré una manera facil

Hay 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.

1
  • 4
    Tiene lo siguiente en el método principal: // this (); error porque "debe ser la primera declaración en el constructor Esta declaración no tiene mucho sentido. Si está tratando de decir que this () no se puede llamar desde dentro del método principal , entonces sí, no puede ser porque main es estático y no tendrá referencia a esta() 7 de ene. De 2017 a las 13:31
8

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 ..

0
8

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()call

8

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.

0
7

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);
   }
0
6

La palabra clave this 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

6

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 });
4

Sé que hay muchos 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");
        }
    }
4

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, podría ser útil https://medium.com/@modestofiguereo/design-patterns-2-the-builder-pattern-and-the-telescoping-constructor-anti-pattern-60a33de7522e

4

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

Sin embargo, dicha llamada debe ser la primera declaración de su constructor. Para superar esta limitación, use esta respuesta .

2

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 de Constructor Chaining en Java

1

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

Solo para completar: también existe 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 {...}"

0

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;
    }
}
0

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;
      }

 }
0

Se llama encadenamiento de constructores. El encadenamiento de constructores es el proceso de llamar a un constructor desde otro constructor con respecto al objeto actual. El encadenamiento de constructores se puede realizar de dos formas:

1. Dentro de la misma clase: se puede hacer usando esta palabra clave () para constructores en la misma clase 2. Desde la clase base: usando la palabra clave super () para llamar a un constructor desde la clase base.