如何调用Java中的另一个构造函数?

How do I call one constructor from another in Java?

是否可以从另一个(在同一类中,而不是从子类中)调用构造函数?如果是,怎么办?调用另一个构造函数的最佳方法是什么(如果有几种方法可以做到这一点)?


是的,有可能:

1
2
3
4
5
6
7
8
9
10
11
public class Foo {
    private int x;

    public Foo() {
        this(1);
    }

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

要链接到特定的超类构造函数而不是同一类中的一个,请使用super而不是this。注意,您只能链接到一个构造函数,它必须是您的构造函数体中的第一条语句。

另见这一相关问题,这是关于C,但在同样的原则适用的地方。


使用this(args)。首选模式是从最小的构造器工作到最大的构造器。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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;
 }
}

您还可以使用最近提倡的"价值"或"价值"方法:

1
2
3
4
5
6
7
8
9
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;
 }
}

要调用超级类,请使用super(someValue)。对super的调用必须是构造函数中的第一个调用,否则将出现编译器错误。


[注:我只想添加一个方面,在其他答案中我没有看到:如何克服这个()必须在第一行的要求的限制。]

在Java中,同一类的另一个构造函数可以通过EDCOX1(4)来从构造函数调用。但是请注意,this必须位于第一行。

1
2
3
4
5
6
7
8
9
10
11
12
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;
  }
}

EDOCX1[1]必须出现在第一行,这看起来是一个很大的限制,但是您可以通过静态方法构造其他构造函数的参数。例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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;

  }

}


当我需要从代码内部(而不是第一行)调用另一个构造函数时,我通常使用这样的助手方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class MyClass {
   int field;


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

但大多数情况下,我试图用另一种方法来实现,尽可能地从第一行的简单构造函数调用更复杂的构造函数。对于上述示例

1
2
3
4
5
6
7
8
9
10
11
12
13
class MyClass {
   int field;

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

在构造函数中,可以使用this关键字调用同一类中的另一个构造函数。这样做被称为显式构造函数调用。

这是另一个矩形类,其实现与"对象"部分中的实现不同。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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;
    }

}

此类包含一组构造函数。每个构造函数初始化矩形的部分或全部成员变量。


正如大家已经说过的,您使用的是this(…),它被称为显式构造函数调用。

但是,请记住,在这样一个显式的构造函数调用语句中,您可能不会引用

  • 任何实例变量或
  • 任何实例方法或
  • 在这个类或任何超类中声明的任何内部类,或者
  • this
  • super

如JLS(§8.8.7.1)所述。


是的,可以从另一个构造函数调用一个构造函数。但这是有规律的。如果从一个构造函数调用另一个构造函数,则

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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;
    }
}

所以,像下面这样的事情是行不通的。

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

另外,在继承的情况下,当创建子类的对象时,首先调用超级类构造函数。

1
2
3
4
5
6
7
8
9
10
11
12
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");
    }
}

因此,在这种情况下,另一个构造函数调用首先声明在任何其他语句之前。


是的,一个类中可以存在任何数量的构造函数,并且可以由另一个使用this()的构造函数调用它们[请不要将this()构造函数调用与this关键字混淆]。this()this(args)应该是构造函数中的第一行。

例子:

1
2
3
4
5
6
7
8
9
10
11
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");
    }
}

这称为构造函数重载。请注意,对于构造函数,只有重载概念才适用,而不是继承或重写。


我会告诉你一个简单的方法

有两种类型的构造函数:

  • 默认构造函数
  • 参数化构造函数
  • 我用一个例子来解释

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    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)    
           }
       }

    在上面的示例中,我展示了3种类型的调用

  • 此()调用必须是构造函数中的第一个语句
  • 这是一个没有名字的对象。这将自动调用默认的构造函数。3.调用参数化构造函数。
  • 注:这必须是构造函数中的第一条语句。


    从另一个构造函数调用构造函数

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    class MyConstructorDemo extends ConstructorDemo
    {
        MyConstructorDemo()
        {
            this("calling another constructor");
        }
        MyConstructorDemo(String arg)
        {
            System.out.print("This is passed String by another constructor :"+arg);
        }
    }

    也可以使用super()调用来调用父构造函数


    是的,使用this()可以从另一个构造函数调用一个构造函数。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    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);
       }


    您可以使用"this"关键字从同一类的另一个构造函数创建构造函数。示例-

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    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);
        }
    }

    输出-字符串作为参数构造函数..默认构造函数..int作为arg构造函数..


    关键字this可用于从构造函数调用构造函数,当为一个类编写多个构造函数时,有时您希望从另一个构造函数调用一个构造函数以避免代码重复。

    下面是一个链接,我解释了关于构造函数和getters()和setters()的其他主题,并且使用了一个包含两个构造函数的类。我希望这些解释和例子对你有所帮助。

    setter方法或构造函数


    有一些设计模式可以满足复杂构造的需要——如果不能简单地完成,那么创建一个工厂方法或工厂类。

    使用最新的Java和添加LAMBDAS,很容易创建一个构造函数,它可以接受任何您想要的初始化代码。

    1
    2
    3
    4
    5
    6
    class LambdaInitedClass {

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

    打电话给……

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

    相当简单

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    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
    }

    下面是一些小的额外学分:

    1
    2
    3
    4
    5
    6
    public SomeOtherClass extends SomeClass {
        public SomeOtherClass(int number, String someString){
             super(number, someString); //calls public SomeClass(int number, String someString)
        }
        //.... Some other code.
    }

    希望这有帮助。


    我知道这个问题有很多例子,但是我发现我在这里是为了分享我的想法。有两种方法可以链接构造函数。在同一个类中,您可以使用这个关键字。在继承中,需要使用super关键字。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
        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");
            }
        }


    它被称为伸缩构造反模式或构造链。是的,你当然可以。我看到了上面的许多例子,我想补充一句,如果您知道您只需要两个或三个构造函数,那就可以了。但如果您需要更多,请尝试使用不同的设计模式,如生成器模式。例如:

    1
    2
    3
    4
    5
    6
     public Omar(){};
     public Omar(a){};
     public Omar(a,b){};
     public Omar(a,b,c){};
     public Omar(a,b,c,d){};
     ...

    你可能需要更多。在这种情况下,构建器模式将是一个很好的解决方案。这是一篇文章,可能会有所帮助https://medium.com/@modestofiguero/design-patterns-2-the-builder-pattern-and-the-scalexing-constructor-anti-pattern-60A33DE7522E


    可以通过this(...)关键字(当需要从同一类调用构造函数时)或super(...)关键字调用另一个构造函数。(当需要从超类调用构造函数时)。

    但是,这样的调用必须是构造函数的第一条语句。为了克服这个限制,使用这个答案。


    最初来自Mirko Klemm的Anser

    只是为了完整性:还有一个实例初始化块,它总是在调用任何其他构造函数之前执行。它仅仅由一组语句组成"……}"在你的类定义中的某个地方。您甚至可以拥有多个。您不能调用它们,但是如果您想在构造函数之间重用一些代码(类似于调用方法),它们就像"共享构造函数"代码。

    所以在你的情况下

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

    还有一个"静态"版本,用于初始化静态成员:"静态……}