6

我遇到了一个场景,我需要一个公共和私有构造函数。需要一个私有构造函数来设置类型为私有内部类的私有字段。这是鼓励还是气馁?对于下面列出的场景,还有什么更好的解决方案?

请阅读评论,它更有意义地支持我的问题。谢谢,

public class CopyTree { 
    private TreeNode root;

    public Copytree() { }

    //  private CopyTree(TreeNode root) { this.root = root; }

    private static class TreeNode {
       TreeNode left;
        TreeNode right;
        Integer element;
        TreeNode(TreeNode left, TreeNode right, Integer element) {
            this.left = left;
            this.right = right;
            this.element = element;
    }
}

public CopyTree copyTree() {
    CopyTree ct = new CopyTree();
    ct.root = copyTree(root);  // <---- QUESTION:  Any cleaner solution ?? 
    // cleaner solution appears to be a private constructor
    // eg: CopyTree ct = new CopyTree(copyTree(root));  But can public and private constructor     coexist together ?
    return ct;
}

private TreeNode copyTree(TreeNode binaryTree) {
    TreeNode copy = null;
    if (binaryTree != null) {
        copy = new TreeNode(null, null, binaryTree.element);
        copy.left =  copyTree(binaryTree.left); 
        copy.right = copyTree(binaryTree.right);
    }
    return copy;
}
4

4 回答 4

2

一个类可以同时具有公共和私有构造函数吗?

是的,有可能。

需要一个私有构造函数来设置类型为私有内部类的私有字段。这是鼓励还是不鼓励?

这取决于实际情况。您是否希望其他类初始化您的对象的状态。在这里,我认为您已经创建了类 CopyTree 来返回作为私有类的 Tree 的副本。因此 TreeNode 类将被封装,因此您可以选择使用私有构造函数捕获习语。

下面列出的场景有什么更好的解决方案?

在我看来,私有构造函数捕获习语是更好的解决方案。

了解更多信息:

您可以搜索私有构造函数捕获习语

Java Puzzlers的解决方案 53 中给出了一个示例:

谜题 53:做你的事

现在轮到你写一些代码了。假设您有一个名为 Thing 的库类,其唯一的构造函数采用 int 参数:

public class Thing {    
    public Thing(int i) { ... }
        ...
    }

Thing 实例无法获取其构造函数参数的值。因为 Thing 是一个库类,您无法访问其内部,也无法修改它。假设您要编写一个名为 MyThing 的子类,其构造函数通过调用 SomeOtherClass.func() 方法计算超类构造函数的参数。此方法返回的值会因调用而发生不可预测的变化。最后,假设您希望将传递给超类构造函数的值存储在子类的最终实例字段中以供将来使用。这是您自然会编写的代码:

public class MyThing extends Thing {
    private final int arg;
    public MyThing() {
        super(arg = SomeOtherClass.func());
        ...
    }
    ...
}

不幸的是,这是不合法的。如果您尝试编译它,您将收到如下所示的错误消息:

MyThing.java:
  can't reference arg before supertype constructor has been called
        super(arg = SomeOtherClass.func());
                 ^

如何重写 MyThing 以达到预期的效果?MyThing() 构造函数必须是线程安全的:多个线程可以同时调用它。

解决方案 53:做你的事

在调用 Thing 构造函数之前,您可以尝试将调用 SomeOtherClass.func() 的结果存储在静态字段中。这个解决方案可行但很尴尬。为了实现线程安全,您必须同步对隐藏值的访问,这需要难以想象的扭曲。通过使用线程局部静态字段 (java.util.ThreadLocal) 可以避免其中一些扭曲,但存在更好的解决方案。首选的解决方案本质上是线程安全且优雅的。它涉及在 MyThing 中使用第二个私有构造函数:

public class MyThing extends Thing {
    private final int arg;

    public MyThing() {
        this(SomeOtherClass.func());
    }

    private MyThing(int i) {
        super(i);
        arg = i;
   }
}

此解决方案使用备用构造函数调用。此功能允许类中的一个构造函数链接到同一类中的另一个构造函数。在这种情况下,MyThing() 链接到私有构造函数 MyThing(int),它执行所需的实例初始化。在私有构造函数中,表达式 SomeOtherClass.func() 的值已被捕获在参数 i 中,并且可以在超类构造函数返回后存储在最终字段 param 中。

于 2013-07-08T05:37:11.043 回答
0

可以防止一个类被其调用者使用 Private 构造函数显式实例化。

在私有构造函数有用的地方,

  • 仅包含静态实用程序方法的类
  • 只包含常量的类
  • 类型安全枚举
  • 单身人士

他们被证明是不利的(不限于以下几点。列表可能会增加)

  • 没有公共或受保护构造函数的类不能被子类化。
  • 它们不容易与其他静态方法区分开来。
于 2013-07-08T05:39:27.660 回答
0

您只能通过以下方式使用私有和公共构造函数。但是您不能将两者都用于无参数构造函数或相同的参数类型。

public class MyClass {
private MyClass(){

}
public MyClass(int i){

}
}
于 2013-07-08T05:40:31.973 回答
0

从您注释掉的代码来看,您已经尝试过它并且它有效。因此,我只能确认您的发现:是的,私有构造函数可以与公共构造函数共存,是的,这似乎是一个更好的解决方案,因为在接收对新对象的引用之前完成了更多的初始化。

于 2013-07-08T05:41:40.030 回答