我遇到了一个场景,我需要一个公共构造函数和一个私有构造函数。需要私有构造函数来设置其类型为私有内部类的私有字段。 这是囤积还是气馁?那么对于下面列出的场景,什么是更好的解决方案?
请阅读评论,该评论更有意义地支持我的问题。谢谢,
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;
}
答案 0 :(得分:2)
一个类可以同时拥有公共和私有构造函数吗?
是的,这是可能的。
需要私有构造函数来设置其类型为私有内部类的私有字段。这是鼓励还是气馁?
这取决于具体情况。是否希望其他类初始化对象的状态。在这里,我认为你已经创建了类CopyTree来返回一个私有类的Tree of Tree。所以TreeNode类将被封装,因此它让你可以选择使用私有构造函数捕获习惯用法。
对于下面列出的方案,什么是更好的解决方案?
在我看来,私有构造函数捕获习惯是更好的解决方案。
有关详情:
您可以搜索private constructor capture idiom。
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中。
答案 1 :(得分:0)
可以防止其调用者使用Private实例化一个类 构造
私有构造函数有用,
他们被证明是一个劣势(不限于以下几点。列表可能会增长)
答案 2 :(得分:0)
您只能以下列方式使用私有和公共构造函数。但是你不能同时使用这两个参数构造函数或相同的参数类型。
public class MyClass {
private MyClass(){
}
public MyClass(int i){
}
}
答案 3 :(得分:0)
根据您已注释掉的代码判断,您已经尝试过它并且有效。因此,我只能确认你的发现:是的,私有构造函数可以与公共构造函数共存,是的,它似乎是一个更好的解决方案,因为在接收对新对象的引用之前完成了更多的初始化。