是否可以从另一个(在同一个类中,而不是从子类中)调用构造函数?如果是怎么办?调用另一个构造函数的最佳方法是什么(如果有几种方法可以做到)?
对的,这是可能的:
public class Foo {
private int x;
public Foo() {
this(1);
}
public Foo(int x) {
this.x = x;
}
}
要链接到特定的超类构造函数而不是同一类中的构造函数,请使用 super
而不是 this
。请注意,您只能链接到一个构造函数,并且它必须是构造函数主体中的第一条语句。
另请参阅 this related question,它是关于 C#,但适用相同的原则。
使用 this(args)
。首选模式是从最小的构造函数到最大的构造函数。
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;
}
}
您还可以使用最近提倡的 valueOf 或只是“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)
。对 super 的调用必须是构造函数中的第一个调用,否则会出现编译器错误。
newCons
实现最后一种方法的问题在于,您正在尝试使用 setArg1(...)
更改对象的状态,该对象很可能应该将其字段设置为 final。当我们试图尽可能多地保持对象不可变时,如果不是完全不可变的话,构建器模式将更正确地解决这个问题。
K(A a, B b) { this.a = a; this.b = b; }
。然后,如果 b
有一个合理的默认值,则可以有一个单参数构造函数 K(A a) { this(a, DEFAULT_B); }
,如果也有一个默认值 a
,我们就有一个默认构造函数:K() { this(DEFAULT_A); }
。这是 Java 中非常常见的约定。
[注意:我只想添加一个方面,我在其他答案中没有看到:如何克服 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;
}
}
this(...)
) 之前需要代码,那么可以合理地假设某处发生了可怕的错误,并且可能需要重新考虑设计。
final
(最终字段只能初始化一次)。
当我需要从代码内部(不是在第一行)调用另一个构造函数时,我通常使用这样的辅助方法:
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;
else
field = value;
}
MyClass() {
this(0);
}
}
在构造函数中,您可以使用 this
关键字来调用同一类中的另一个构造函数。这样做称为显式构造函数调用。
这是另一个 Rectangle 类,与 Objects 部分中的实现不同。
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;
}
}
此类包含一组构造函数。每个构造函数初始化矩形的部分或全部成员变量。
Rectangle()
中的 Rectangle(int width, int height)
而不是 Rectangle(int x, int y, int width, int height)
的第二个构造函数?
正如大家已经说过的,您使用 this(…)
,这称为 显式构造函数调用。
但是,请记住,在这样的显式构造函数调用语句中,您可能不会引用
任何实例变量或
任何实例方法或
在此类或任何超类中声明的任何内部类,或
这个或
极好的。
如 JLS (§8.8.7.1) 中所述。
是的,一个类中可以存在任意数量的构造函数,并且它们可以由另一个构造函数使用 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");
}
}
这称为构造函数重载。请注意,对于构造函数,仅适用于重载概念,不适用于继承或覆盖。
是的,可以从另一个构造函数调用一个构造函数。但它有一个规则。如果从一个构造函数调用另一个构造函数,则
新的构造函数调用必须是当前构造函数中的第一条语句
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");
}
}
因此,在这种情况下,另一个构造函数调用首先在任何其他语句之前声明。
使用这个关键字,我们可以在同一个类的另一个构造函数中调用一个构造函数。
例子 :-
public class Example {
private String name;
public Example() {
this("Mahesh");
}
public Example(String name) {
this.name = name;
}
}
我告诉你一个简单的方法
有两种类型的构造函数:
默认构造函数参数化构造函数
我将在一个例子中解释
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 种调用类型
this() 对 this 的调用必须是构造函数中的第一条语句 This is Nameless Object。这会自动调用默认构造函数。 3.这会调用参数化构造函数。
注意:这必须是构造函数中的第一条语句。
您可以使用“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 构造函数..
从另一个构造函数调用构造函数
class MyConstructorDemo extends ConstructorDemo
{
MyConstructorDemo()
{
this("calling another constructor");
}
MyConstructorDemo(String arg)
{
System.out.print("This is passed String by another constructor :"+arg);
}
}
您也可以使用 super()
调用来调用父构造函数
很简单
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
}
现在这里有一些额外的功劳:
public SomeOtherClass extends SomeClass {
public SomeOtherClass(int number, String someString){
super(number, someString); //calls public SomeClass(int number, String someString)
}
//.... Some other code.
}
希望这可以帮助。
有一些设计模式可以满足复杂构造的需求——如果不能简洁地完成,请创建工厂方法或工厂类。
使用最新的 java 和添加的 lambda,很容易创建一个可以接受任何你想要的初始化代码的构造函数。
class LambdaInitedClass {
public LamdaInitedClass(Consumer<LambdaInitedClass> init) {
init.accept(this);
}
}
用...调用它
new LambdaInitedClass(l -> { // init l any way you want });
是的,可以使用 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);
}
关键字 this 可用于从构造函数调用构造函数,当为一个类编写多个构造函数时,有时您希望从另一个构造函数调用一个构造函数以避免重复代码。
Bellow 是一个链接,我解释了有关构造函数和 getters() 和 setters() 的其他主题,并且我使用了一个具有两个构造函数的类。我希望解释和示例对您有所帮助。
Setter methods or constructors
您可以通过 this(...)
关键字(当您需要从同一个类调用构造函数时)或 super(...)
关键字(当您需要从超类调用构造函数时)调用另一个构造函数。
但是,这样的调用必须是构造函数的 first 语句。要克服此限制,请使用 this answer。
我知道这个问题有很多例子,但我发现我放在这里是为了分享我的想法。有两种方法可以链接构造函数。在同一类中,您可以使用此关键字。在继承中,您需要使用 super 关键字。
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");
}
}
它被称为伸缩构造函数反模式或构造函数链接。是的,你绝对可以。我在上面看到了很多例子,我想补充一点,如果你知道你只需要两个或三个构造函数,那可能没问题。但如果您需要更多,请尝试使用不同的设计模式,如 Builder 模式。例如:
public Omar(){};
public Omar(a){};
public Omar(a,b){};
public Omar(a,b,c){};
public Omar(a,b,c,d){};
...
你可能需要更多。在这种情况下,构建器模式将是一个很好的解决方案。这是一篇文章,它可能会有所帮助https://medium.com/@modestofiguereo/design-patterns-2-the-builder-pattern-and-the-telescoping-constructor-anti-pattern-60a33de7522e
是的,您可以从另一个构造函数调用构造函数。例如:
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;
}
}
您还可以从 Constructor Chaining in Java 阅读详细信息
最初来自 Mirko Klemm 的分析器,稍作修改以解决问题:
仅出于完整性考虑:还有 Instance initialization block 始终在调用任何其他构造函数之前执行。它仅由类定义主体中某处的语句块“{ ... }”组成。你甚至可以拥有不止一个。你不能调用它们,但如果你想跨构造函数重用一些代码,它们就像“共享构造函数”代码,类似于调用方法。
所以在你的情况下
{
System.out.println("this is shared constructor code executed before the constructor");
field1 = 3;
}
还有一个“静态”版本来初始化静态成员:“static { ... }”
我更喜欢这种方式:
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;
}
}
它被称为构造函数链接。构造函数链接是相对于当前对象从另一个构造函数调用一个构造函数的过程。构造函数链接可以通过两种方式完成:
1.在同一个类中:对于同一个类的构造函数,可以使用this()关键字来完成。 2.从基类:使用super()关键字从基类调用构造函数。