Java构造函数链方向

标签 java constructor method-chaining

我知道有些特殊的类不适用这个一般性问题,但是对于简单的类,当我们有多个构造函数时,一个的参数是另一个的干净子集,调用构造函数是否更好从列表较短的列表中选择较长的列表,反之亦然?为什么?

public class A {
    int x;
    int y;
    int z;

    public A() {
        this(0);
    }
    public A(int x) {
        this (x, 0);
    }
    public A(int x, int y) {
        this(x, y, 0);
    }

    public A(int x, int y, int z) {
        this.x = x;
        this.y = y;
        this.z = z;
        // some setup stuff needed for all A
    }
}

或者

public class A {
    int x;
    int y;
    int z;

    public A(int x, int y, int z) {
        this(x, y);
        this.z = z;
    }

    public A(int x, int y) {
        this(x);
        this.y = y;
    }

    public A(int x) {
        this();
        this.x = x;
    }

    public A() {
        // some setup stuff needed for all A
    }
}

最佳答案

看看第二个变体:

public A(int x, int y, int z) {
    this(x, y);
    this.z = z;
}

public A(int x, int y) {
    this(x);
    this.y = y;
}

public A(int x) {
    this();
    this.x = x;
}

public A() {
    // some setup stuff needed for all A
}

请注意,如果需要 x 的实际值,则无法设置“所有 A 都需要的东西” , y , z .解决这个问题的唯一方法是让默认构造函数使用默认值 x 来完成这项工作。 , y , z然后使用指定的非默认值在调用构造函数中覆盖其结果。如果这些设置工作有明显的副作用,那是不行的,但即使没有副作用,它也可能对性能产生负面影响,考虑到最坏的情况,A(int x, int y, int z)构造函数执行该工作四次。

除此之外,还有(至少)三种情况,即使没有这样的设置工作,您的第二个变体也不起作用:

  1. 已经explained by Codebender , 参数列表不需要是彼此的子集。

    public A(TypeA a) {
        this(a, DEFAULT_B);
    }
    public A(TypeB b) {
        this (DEFAULT_A, b);
    }
    public A(TypeA a, TypeB b) {
        …
    }
    
  2. 字段可能是 final .然后,链中的最后一个构造函数(不调用此类的另一个构造函数)必须初始化所有 final。字段,而委托(delegate)构造函数不允许写入这些 final字段。

    public class A {
        final int x, y, z;
    
        public A() {
            this(0);
        }
        public A(int x) {
            this (x, 0);
        }
        public A(int x, int y) {
            this(x, y, 0);
        }
    
        public A(int x, int y, int z) {
            this.x = x;
            this.y = y;
            this.z = z;
            // optionally, some setup stuff needed for all A
        }
    }
    
  3. 一些字段在父类(super class)中定义,需要通过构造函数进行初始化。类似于 final字段初始化,只有链中的最后一个构造函数可以调用 super构造函数,而其他人不能调用 super构造函数,因此只有知道适当值的构造函数才能成为最后一个。

    public class A extends B{
        int z;// B has x and y
    
        public A() {
            this(0);
        }
        public A(int x) {
            this (x, 0);
        }
        public A(int x, int y) {
            this(x, y, 0);
        }
    
        public A(int x, int y, int z) {
            super(x, y);
            this.z = z;
            // optionally, some setup stuff needed for all A
        }
    }
    

由于在很多情况下第二个变体不起作用,我也不会在工作场景中使用它,因为只要某件事只是一个文体问题,你就应该争取一致性 .

关于Java构造函数链方向,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31593350/

相关文章:

java - Mockito 在测试中没有模拟来自 Controller 的功能

java - 如何测量从 Maven 或 intellij 运行的单元测试的启动时间?

用于图论算法的 Java 库

c# - 有没有办法在 C# 中获取 F# 的构造函数参数是自动不可变私有(private)成员功能?

c++ - 在从模板化中介派生的类中调用非模板基类构造函数

c# - 流利的接口(interface)-确保新实例

java - 泛型、继承和类型删除问题

c++ - 具有 const 成员的类构造

api - Fluent API 与其他 API 有何不同?

Python 等同于 LINQ