Java 为什么允许从一个构造函数调用另一个构造函数?

Java 为什么允许从一个构造函数调用另一个构造函数?,java,constructor,Java,Constructor,我在看其他的问题,但是我没有看到对我的问题的解释。我读到从另一个构造函数调用构造函数(使用this关键字)是有效的,但我不理解为什么它是有效的 以前,我认为每个对象只能有一个构造函数。构造函数链接似乎打破了这种逻辑,在调用一个构造函数时,它会与原始的目标构造函数一起运行另一个构造函数。为什么构造函数链接起作用?委托构造函数减少了重复代码的数量,因为您可以通过从另一个构造函数调用它来利用在一个构造函数中设置的功能 在这个特性被设计成语言之前,我们必须依赖于从构造函数调用的“初始化”类型的函数。这是

我在看其他的问题,但是我没有看到对我的问题的解释。我读到从另一个构造函数调用构造函数(使用this关键字)是有效的,但我不理解为什么它是有效的


以前,我认为每个对象只能有一个构造函数。构造函数链接似乎打破了这种逻辑,在调用一个构造函数时,它会与原始的目标构造函数一起运行另一个构造函数。为什么构造函数链接起作用?

委托构造函数减少了重复代码的数量,因为您可以通过从另一个构造函数调用它来利用在一个构造函数中设置的功能


在这个特性被设计成语言之前,我们必须依赖于从构造函数调用的“初始化”类型的函数。这是一种痛苦,原因有两个:(i)您无法保证函数仅从构造函数调用,(ii)从构造函数调用类方法始终是一种设计“味道”。

这里不是Java开发人员,但在Python中,这也是允许的,非常正常

每当您继承一个类时,您可能希望在添加自己的内容和配方之前调用父类的构造函数

这使您能够受益于父类的构造功能。每当你不知道父类到底是什么的时候,大多数时候你总是先调用它,以避免父类的特性和方法被破坏。

我们在同一个类中链接(调用)一个构造函数和另一个构造函数,以避免代码重复。如果不链接每个构造函数,我们最终会重复业务细节,这会导致代码重复,并且很难维护代码

假设您正在创建一辆公共汽车

public class Bus {  
      int noOfSeats;  
      String busColor;  

      public Bus() {  
           this(40); //// Using another constructor and proceeding with default values..   
      }  
      public Bus(int seats) {   
           this(seats,"red"); // Using another constructor and proceeding..   
      }  
      public Bus(int seats, String color) {  
           this.noOfSeats = seats; 
           this.busColor = color;  
      }  
 } 
使用这个类的人一次只能使用构造函数,因为您在内部使用链接。假设您有一个方法,该方法使用默认值初始化并在构造函数中调用它。这没什么不对的,对吧


只是澄清一下,创建对象的人只调用了一个构造函数。被调用的构造函数调用该类内部的其他构造函数。

它允许澄清逻辑并减少代码

将构造函数链接在一起是合理的,参数较少的版本调用参数较多的版本。它非常清楚发生了什么,所有真正的“逻辑”(超出默认值)都在一个地方。例如:


每个实例都应该调用一个ctor,这一事实是完全正确的。链接到另一个构造函数的构造函数用于避免代码重复和简单性,因为复制相同的代码实际上是开销。有时我们可能需要两个构造函数,第一个只取两个参数,另一个取三个参数。但是,三个参数ctor使用两个参数ctor的相同变量。你喜欢复制粘贴相同的赋值,还是只通过
this
调用另一个ctor?

作为其他答案的补充,我想分享从我经常使用的构造函数调用构造函数的另一个用途

我发现另一个有用的构造函数链接策略是为接口提供默认实现/自动注入

public class Foo {

    private readonly ILogger _logger;

    //Default implementation for most cases
    public Foo() : this(new DefaultLoggerImplementation()) {}

    //DI Constructor that allows for different implementations of ILogger 
   //(Or Mocks in testing)
    public Foo(ILogger logger)
    {
        _logger = logger;
    }

    public void Log(string message)
    {
        _logger.log(message);
    } 
}
这样,如果您有一个接口的默认实现,它将通过
newfoo()自动注入


如果您有一个具有不同
ILogger
行为的案例,那么它很容易注入,这也提高了在单元测试框架中模拟接口的能力

顺便说一句,OP在Java中使用
this
,这意味着他们没有要求调用父类构造函数。在Java中,您需要使用
super
来访问父类构造函数。是的,在Python中也是如此(u_u超级()uu),但我不知道Java是什么。Python中没有私有方法本身,因此您甚至可以调用“private”方法。若构造函数方法采用参数,那个么它们可能会很有用,所以我想在Java中公开这些参数是有意义的。(在Python构造函数中不返回值…不知道java)为什么它应该无效?它是C++的,直到C++ 11(即大约30年)。对我来说,这个问题是有效的。为了澄清@ Bathsheba的评论:在C++中,构造函数链接是无效的,直到C++ 11。(乍看之下,我错误地读到它,好像它是(C++)支持的,直到C++ 11),目前的答案只说明为什么授权CCTs是有用的,而不是为什么它们不失效。@ LordFarquaad是的。我的观点是,上面的答案根本没有提到任何类似的东西。因此,为了澄清,程序员可以使用内部构造函数链接,但是类的用户只能为每个对象调用一个显式构造函数,对吗?而且,这是一个非常奇怪的例子。你可以坐没有座位也没有颜色的巴士吗?“通常你用另一种方式把它们拴起来。”奥兰吉多格纠正道。默认情况下,我指的是无组织构造函数。而且,完全重构了我的示例。希望一切都会好起来。@KaienYang您可以将构造函数作为一种语言功能来链接,以减少重复,从而使类(writer)受益-类用户仍然只能调用单个构造函数。另一个缺点是(i)的推论:在初始化方法中初始化的字段不能声明为final。
public class Foo {

    private readonly ILogger _logger;

    //Default implementation for most cases
    public Foo() : this(new DefaultLoggerImplementation()) {}

    //DI Constructor that allows for different implementations of ILogger 
   //(Or Mocks in testing)
    public Foo(ILogger logger)
    {
        _logger = logger;
    }

    public void Log(string message)
    {
        _logger.log(message);
    } 
}