【问题标题】:Why would I ever call a constructor from another one(Java)?为什么我会从另一个(Java)调用构造函数?
【发布时间】:2016-07-20 22:20:35
【问题描述】:

最近刚开始学习java,在我的教科书中我遇到了this,一开始很困惑,但现在它开始变得有意义了。现在,在我的书中,我们 开始了构造函数的基本应用程序,并作为页面上的注释this,也可用于调用其他构造函数。我当时有点迷茫 看看关于this的其他问题。我想我现在已经达到了一定程度,但我为什么要这样做呢?考虑一下我刚刚编造的以下内容。

private double balance;
private double interest;
public Account(double initialBalance){
    balance = initialBalance;

}
public Account(double balance, double interest){
    this(0);
    balance = initialBalance;
    this.interest = interest;
}

这里this(0);,据我了解寻找另一个带有一个参数的构造函数,找到Account(double initialBalance),并将initialBalance 设置为零。 伟大的。嗯,但我为什么不直接这样做呢?只需将余额设置为零!我确信它非常有用,但我想不出任何例子。 谢谢!

【问题讨论】:

  • 不管你是不是这样写,你总是这样。 a(ny) 构造函数的第一条语句是调用父类的构造函数
  • @Stultuske 这与父类无关。没有双关语。
  • @Zircon:调用另一个构造函数......这基本上就是我所描述的。如果它来自同一个班级,那么他发布的代码要么不是他书中的代码,要么他们用它作为不应该做的例子,或者这是一本糟糕的书。
  • 当然,如果你在构造函数中所做的只是简单的赋值,那并没有太大的区别,但是如果你的构造函数更复杂(例如参数验证)怎么办?您不希望在多个构造函数中编写相同的代码。

标签: java


【解决方案1】:

非常实用,避免代码重复

public Account(){
    this(0);
}

public Account(double initialBalance){
    this(initialBalance, DEFAULT_INTEREST_RATE);
}

public Account(double balance, double interest){
    balance = initialBalance;
    this.interest = interest;
}

带有 less 参数的构造函数委托给带有 more 参数的构造函数,为缺少的参数传递默认值。

如果这不可能,则需要一种人工的init(..) 方法来接受参数,并从所有构造函数中调用。这不太安全,因为此方法可能会被重复调用。

【讨论】:

  • 您能否扩展一个需要人工 init(..) 的内容,或者我以后会学到什么?
  • @Peter 的意思是,如果 Java 不允许一个构造函数调用另一个构造函数,那么避免多个构造函数中代码重复的一种方法是让每个构造函数调用一个执行否则会被复制的代码。他碰巧将该方法命名为“init”。这是不安全的,因为该方法也可以在类的其他地方调用。
  • 正如@FredK 所说的那样^^
【解决方案2】:

来自 Java documentation 的示例可能比您手头的示例更有意义:

public class Rectangle {
    private int x, y;
    private int width, height;

    public Rectangle() {
        this(0, 0, 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;
    }
    ...
}

【讨论】:

    【解决方案3】:

    想想你可以用另一种方式来做:你的“基本”构造函数是

    public Account(double balance, double interest){
        balance = initialBalance;
        this.interest = interest;
    }
    

    在此基础上,您可以添加一些简化:

    public Account(double initialBalance){
        this(initialBalance, DEFAULT_INTEREST);
    }
    
    public Account(){
        this(DEFAULT_INITIAL_BALANCE, DEFAULT_INTEREST);
    }
    

    调用这些构造函数可以简化改变主要行为:如果我,e. g.,想在某处注册新对象,我可以在一个中心位置进行,并让其他构造函数依赖它。

    【讨论】:

    • 我们不需要定义DEFAULT_INTEREST,DEFAULT_INITIAL_BALANCE吗?
    • @cresjoy 是什么阻止我们这样做?
    • 我应该在哪里定义它们?我只是让它们成为实例变量吗?
    • @cresjoy 你通常会在班级的顶部做类似private static final double DEFAULT_INITIAL_BALANCE = 0.0 的事情。如果您需要课堂之外的价值,也可以使用protectedpublic
    • 下一章我们将学习最终变量和静态变量。现在我可以只做私人双 DEFAULT_INTEREST 吗?
    【解决方案4】:

    这是一个使用同一对象的另一个构造函数的好例子:

    public Person(String name, String street, String location) {
       (...)
       //handle them
    }
    
    public Person() {
       this("default name", "default street", "default location");
    }
    

    它基本上是一种快捷方式(重载),因此您可以避免冗余代码。

    【讨论】:

      【解决方案5】:

      重载构造函数可能会派上用场很多次。 一个例子是当您有多个参数但并非所有参数都是强制性的。

      使用重载,您可以执行以下操作:

      public Account(string id, double balance, string name, strings address){
          this.id = id;
          this.balance = balance;
          this.name = name;
          this.address = address;
      }
      
      public Account(string id, double balance, string name){
          this(id, balance, name, null);
      }
      
      public Account(string id, double balance){
          this(id, balance, "Unknown" ,null);
      }
      
      public Account(string id){
          this(id, 0, "Unknown" ,null);
      }
      

      【讨论】:

        【解决方案6】:

        这个例子确实没有多大意义。

        以下是。

        private double balance;
        private double interest;
        
        public Account(double initialBalance){
            this(initialBalance, 9.99);
        }
        
        public Account(double balance, double interest){
            this.balance = balance;
            this.interest = interest;
        }
        

        确实有人调用了另一个构造函数,它通常会做一些工作而不仅仅是分配。

        对于原始示例,可能是先创建了简单构造函数,然后为额外字段 interest 添加了带有额外参数的构造函数。

        所以人们可能会经常看到这种结构,它可以与对super(...)的调用相媲美

        同样在简单的情况下,这种用法遵循 DRY 原则:不要重复自己。请注意,如果其中一个构造函数在时间上只是有一些不同的赋值,那么程序将变得依赖于构造函数的大小写。现在你知道了,同样的代码被遍历了,你不必测试这个功能 N 次。

        【讨论】:

          【解决方案7】:

          这称为“构造函数重载”。就像方法重载一样,这是 Java 允许您为单个方法提供不同数量的参数的方式。

          它通常用于方法,或者在这种情况下,用于具有“可选”参数的构造函数。这是一个更明显的例子:

          class Cat{
              private int paws;
              private String name;
          
              public Cat(String name){
                  //Assume that the cat is physically not handicapped, and thus has 4 paws
                  this(name,4);
              }
          
              public Cat(String name, int paws){
                  this.name = name;
                  this.paws = paws;
              }
          }
          

          【讨论】:

            【解决方案8】:

            如果你把它反过来说会更有意义。

            public Account(double initialBalance){
                this(initialBalance, 2.0); // 2.0 being a default interest (whatever you'd like, could be 0).
            }
            
            public Account(double balance, double interest){
                this.balance = balance;
                this.interest = interest;
                // Some more very difficult business logic
            }
            

            这样可以防止重复代码。对困难业务逻辑的更改只需更改一次(如果需要)。

            【讨论】:

              猜你喜欢
              • 2016-07-03
              • 2011-03-24
              • 2010-09-22
              • 2015-07-02
              • 1970-01-01
              • 2020-03-14
              相关资源
              最近更新 更多