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

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

1077818 次浏览

是的,这是可能的:

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

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

另请参阅这个相关问题,它是关于C#的,但适用相同的原则。

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

public class Cons {
public Cons() {// A no arguments constructor that sends default values to the largestthis(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 largestthis(arg1,arg2, madeUpArg3Value);}
// Largest constructor that does the workpublic Cons(int arg1, int arg2, int arg3) {this.arg1 = arg1;this.arg2 = arg2;this.arg3 = arg3;}}

您还可以使用最近提倡的value eOf方法或仅使用“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;}}

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

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

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

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

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

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

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

class MyClass {int field;

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

但大多数情况下,我试图通过尽可能从第一行的简单构造函数中调用更复杂的构造函数来做到这一点。对于上面的例子

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

正如每个人都已经说过的,你使用this(…),它被称为显式构造函数调用

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

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

如JLS(§8.8.7.1)所述。

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

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

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”关键字从同一类的另一个构造函数中构造函数。示例-

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

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

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

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

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

示例:

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. 参数化构造函数

我将用一个例子来解释

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 constructornew ConstructorDemo();//-------(2)ConstructorDemo g=new ConstructorDemo(3);---(3)}}

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

  1. this()调用this必须是构造函数中的第一个语句
  2. 这是无名称对象。这会自动调用默认构造函数。3.这将调用参数化构造函数。

备注:这必须是构造函数中的第一条语句。

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

新的构造函数调用必须是当前构造函数中的第一条语句

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

所以,下面这样的东西是行不通的。

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

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

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

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

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

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

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

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

Bellow是一个链接,我解释了关于构造函数和getters()和setters()的其他主题,我使用了一个带有两个构造函数的类。我希望解释和示例对你有帮助。

Setter方法或构造函数

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

使用最新的java和lambda的添加,可以轻松创建一个可以接受您想要的任何初始化代码的构造函数。

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

打电话给…

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

很简单嘛

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 0this.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}

这里有一些额外的小信贷:

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

希望这有帮助。

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

    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 wordSystem.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");}}

它被称为伸缩构造函数反模式或构造函数链。是的,你绝对可以做到。我在上面看到了很多例子,我想补充说,如果你知道你只需要两三个构造函数,这可能是可以的。但是如果你需要更多,请尝试使用不同的设计模式,如Builder模式。例如:

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

您可能需要更多。在这种情况下,生成器模式将是一个很好的解决方案。这是一篇文章,可能会有所帮助https://medium.com//设计模式-2-构建模式和伸缩构造函数反模式-60a33de7522e

您可以通过#0关键字(当您需要调用来自同一类的构造函数时)或#1关键字调用另一个构造函数(当你需要从超类调用构造函数时)。

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

最初来自Mirko Klemm的回答,稍微修改以解决问题:

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

所以在你的情况下

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

还有一个“静态”版本来初始化静态成员:“静态{…}”

我更喜欢这种方式:

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

是的,您可以从另一个构造函数调用构造函数。例如:

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

您还可以阅读详细信息构造器链在Java

使用这个关键字,我们可以在同一个类中的另一个构造函数中调用一个构造函数。

示例:-

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