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; } } |
要链接到特定的超类构造函数而不是同一类中的一个,请使用
另见这一相关问题,这是关于C,但在同样的原则适用的地方。
使用
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; } } |
要调用超级类,请使用
[注:我只想添加一个方面,在其他答案中我没有看到:如何克服这个()必须在第一行的要求的限制。]
在Java中,同一类的另一个构造函数可以通过EDCOX1(4)来从构造函数调用。但是请注意,
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); } } |
在构造函数中,可以使用
这是另一个矩形类,其实现与"对象"部分中的实现不同。
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 或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 |
另外,在继承的情况下,当创建子类的对象时,首先调用超级类构造函数。
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"); } } |
因此,在这种情况下,另一个构造函数调用首先声明在任何其他语句之前。
是的,一个类中可以存在任何数量的构造函数,并且可以由另一个使用
例子:
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种类型的调用
注:这必须是构造函数中的第一条语句。
从另一个构造函数调用构造函数
1 2 3 4 5 6 7 8 9 10 11 |
也可以使用
是的,使用
1 2 3 4 5 6 7 8 9 |
您可以使用"this"关键字从同一类的另一个构造函数创建构造函数。示例-
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
输出-字符串作为参数构造函数..默认构造函数..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
可以通过
但是,这样的调用必须是构造函数的第一条语句。为了克服这个限制,使用这个答案。
最初来自Mirko Klemm的Anser
只是为了完整性:还有一个实例初始化块,它总是在调用任何其他构造函数之前执行。它仅仅由一组语句组成"……}"在你的类定义中的某个地方。您甚至可以拥有多个。您不能调用它们,但是如果您想在构造函数之间重用一些代码(类似于调用方法),它们就像"共享构造函数"代码。
所以在你的情况下
1 2 3 4 | { System.out.println("this is shared constructor code executed before the constructor"); field1 = 3; } |
还有一个"静态"版本,用于初始化静态成员:"静态……}