【发布时间】:2010-11-14 00:09:48
【问题描述】:
有几个类似的主题,但我找不到一个足够的答案。
我想知道 Java 中构造函数重载的最佳实践是什么。我已经对这个主题有了自己的想法,但我想听听更多的建议。
我指的是简单类中的构造函数重载和继承已经重载的类时的构造函数重载(意味着基类具有重载的构造函数)。
谢谢:)
【问题讨论】:
标签: java constructor overloading constructor-overloading
有几个类似的主题,但我找不到一个足够的答案。
我想知道 Java 中构造函数重载的最佳实践是什么。我已经对这个主题有了自己的想法,但我想听听更多的建议。
我指的是简单类中的构造函数重载和继承已经重载的类时的构造函数重载(意味着基类具有重载的构造函数)。
谢谢:)
【问题讨论】:
标签: java constructor overloading constructor-overloading
虽然没有“官方指南”,但我遵循 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 类的使用方式相同,参数类和简单工厂类几乎是一回事。
【讨论】:
我认为最佳实践是通过使用相关参数默认值调用this() 来让重载构造函数引用的单个主构造函数。这样做的原因是它使对象的构造状态更加清晰 - 实际上你可以将主构造器视为唯一真正的构造器,其他人只是委托给它
这方面的一个例子可能是JTable - 主构造函数采用TableModel(加上列和选择模型),而其他构造函数调用这个主构造函数。
对于子类父类已经有重载的构造函数,我倾向于认为将任何父类的构造函数视为主要的是合理的,并认为它是没有一个主构造函数是完全合法的。例如,在扩展 Exception 时,我经常提供 3 个构造函数,一个只接受 String 消息,一个接受 Throwable 原因,另一个接受两者。这些构造函数中的每一个都直接调用super。
【讨论】:
如果您有一个非常复杂的类,其中有很多选项,其中只有一些组合是有效的,请考虑使用 Builder。在代码方面和逻辑上都工作得很好。
Builder 是一个嵌套类,其方法仅用于设置字段,然后 ComplexClass 构造函数仅将这样的 Builder 作为参数。
编辑:ComplexClass 构造函数可以确保 Builder 中的状态有效。如果您只在 ComplexClass 上使用 setter,这将很难做到。
【讨论】:
这实际上取决于类的类型,因为并非所有类都是平等的。
作为一般准则,我建议 2 个选项:
【讨论】:
构造函数重载类似于方法重载。构造函数可以被重载,以不同的方式创建对象。
编译器根据构造函数中存在的参数数量和其他参数(例如参数传递的顺序)来区分构造函数。
更多java构造函数详情请访问https://tecloger.com/constructor-in-java/
【讨论】:
嗯,这是一个重载构造函数的例子。
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 中的构造函数重载,
【讨论】: