113

有几个类似的话题,但我找不到一个有足够答案的话题。

我想知道Java中构造函数重载的最佳实践是什么。我已经对这个主题有了自己的想法,但我想听听更多的建议。

我指的是简单类中的构造函数重载和在继承已经重载的类时构造函数重载(意味着基类具有重载的构造函数)。

谢谢 :)

4

6 回答 6

177

虽然没有“官方指南”,但我遵循 KISS 和 DRY 的原则。使重载的构造函数尽可能简单,最简单的方法是它们只调用 this(...)。这样,您只需检查和处理一次参数。

public class Simple {

    public Simple() {
        this(null);
    }

    public Simple(Resource r) {
        this(r, null);
    }

    public Simple(Resource r1, Resource r2) {
        // Guard statements, initialize resources or throw exceptions if
        // the resources are wrong
        if (r1 == null) {
            r1 = new Resource();
        }
        if (r2 == null) {
            r2 = new Resource();
        }

        // do whatever with resources
    }

}

从单元测试的角度来看,测试类将变得很容易,因为您可以将资源放入其中。如果该类有很多资源(或一些 OO 极客称之为协作者),请考虑以下两件事之一:

做一个参数类

public class SimpleParams {
    Resource r1;
    Resource r2;
    // Imagine there are setters and getters here but I'm too lazy 
    // to write it out. you can make it the parameter class 
    // "immutable" if you don't have setters and only set the 
    // resources through the SimpleParams constructor
}

Simple 中的构造函数只需要拆分SimpleParams参数:

public Simple(SimpleParams params) {
    this(params.getR1(), params.getR2());
}

…或创建SimpleParams一个属性:

public Simple(Resource r1, Resource r2) {
    this(new SimpleParams(r1, r2));
}

public Simple(SimpleParams params) {
    this.params = params;
}

做一个工厂类

制作一个为您初始化资源的工厂类,如果初始化资源有点困难,这是有利的:

public interface ResourceFactory {
    public Resource createR1();
    public Resource createR2();
}

然后以与参数类相同的方式完成构造函数:

public Simple(ResourceFactory factory) {
    this(factory.createR1(), factory.createR2());
} 

将两者结合起来

是的...您可以根据当时对您来说更容易的方式混合和匹配两种方式。Simple考虑到它们以相同方式使用的类,参数类和简单工厂类几乎是一回事。

于 2010-04-13T19:02:37.283 回答
74

我认为最佳实践是通过使用相关参数默认值调用重载构造函数来引用单个主构造函数。this()这样做的原因是它使对象的构造状态更加清晰-实际上您可以将主构造函数视为唯一真正的构造函数,其他构造函数只是委托给它。

这方面的一个例子可能是JTable- 主构造函数采用TableModel(加上列和选择模型),而其他构造函数调用这个主构造函数。

对于超类已经具有重载构造函数的子类,我倾向于假设将任何父类的构造函数视为主要构造函数是合理的,并且认为没有单个主要构造函数是完全合法的。例如,在扩展时Exception,我经常提供 3 个构造函数,一个只取String消息,一个取Throwable原因,另一个取两者。这些构造函数中的每一个都super直接调用。

于 2009-07-25T14:16:20.743 回答
7

如果您有一个非常复杂的类,其中有很多选项,其中只有一些组合是有效的,请考虑使用 Builder。在代码方面和逻辑上都工作得很好。

Builder 是一个嵌套类,其方法仅用于设置字段,然后 ComplexClass 构造函数仅将此类 Builder 作为参数。


编辑: ComplexClass 构造函数可以确保 Builder 中的状态有效。如果只在 ComplexClass 上使用 setter,这将很难做到。

于 2009-07-25T16:52:03.243 回答
2

这实际上取决于类的类型,因为并非所有类都是平等的。

作为一般准则,我建议 2 个选项:

  • 对于值和不可变类(异常、整数、DTO 等),请使用上面答案中建议的单个主构造函数
  • 对于其他所有内容(会话 bean、服务、可变对象、JPA 和 JAXB 实体等),仅使用默认构造函数,所有属性都具有合理的默认值,因此无需额外配置即可使用
于 2009-07-26T09:41:21.527 回答
0

构造函数重载类似于方法重载。可以重载构造函数以不同方式创建对象。

编译器根据构造函数中存在的参数数量和其他参数(例如传递参数的顺序)来区分构造函数。

有关 java 构造函数的更多详细信息,请访问https://tecloger.com/constructor-in-java/

于 2020-03-30T18:43:08.383 回答
0

好吧,这是重载构造函数的示例。

public class Employee
{
   private String name;
   private int age;
   
   public Employee()
   {
      System.out.println("We are inside Employee() constructor");
   }

   public Employee(String name)
   {
      System.out.println("We are inside Employee(String name) constructor");
      this.name = name;
   }

   public Employee(String name, int age)
   {
      System.out.println("We are inside Employee(String name, int age) constructor");
      this.name = name;
      this.age = age;
   }

   public Employee(int age)
   {
      System.out.println("We are inside Employee(int age) constructor");
      this.age = age; 
   }

   public String getName()
   {
      return name;
   }
   
   public void setName(String name)
   {
      this.name = name;
   }

   public int getAge()
   {
      return age;
   }
   
   public void setAge(int age)
   {
      this.age = age;
   }
}

在上面的示例中,您可以看到重载的构造函数。构造函数的名称相同,但每个构造函数具有不同的参数。

这里有一些资源可以更清楚地说明 Java 中的构造函数重载,

构造函数

于 2018-01-13T11:22:46.000 回答