[英]Can a class have both public and private constructor?
我遇到了一個需要公共和私有構造函數的場景。 需要一個私有構造函數來設置其類型為私有內部類的私有字段。 這是包庇還是不鼓勵? 對於下面列出的方案,還有什么更好的解決方案?
請閱讀評論,它更有意義地支持了我的問題。 謝謝,
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;
}
一個類可以同時具有公共和私有構造函數嗎?
對的,這是可能的。
需要一個私有構造函數來設置其類型為私有內部類的私有字段。 是鼓勵還是勸阻?
這取決於實際情況。 是否要其他類初始化對象的狀態。 在這里,我認為您已經創建了類CopyTree來返回樹的副本,這是一個私有類。 因此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中捕獲,並且可以在超類構造函數返回后存儲在最終字段參數中。
可以防止使用私有構造函數的調用者顯式實例化一個類。
在私有構造函數有用的地方,
在被證明是不利的地方(不僅限於以下幾點。清單可能會增加)
您只能通過以下方式使用私有和公共構造函數。 但是,不能將兩者都用於沒有參數的構造函數或相同的參數類型。
public class MyClass {
private MyClass(){
}
public MyClass(int i){
}
}
從注釋掉的代碼來看,您已經嘗試過了並且可以正常工作。 因此,我只能確認您的發現:是的,私有構造函數可以與公共的構造函數共存,是的,這似乎是一種更好的解決方案,因為在接收到對新對象的引用之前要進行更多的初始化。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.