簡體   English   中英

一個類可以同時具有公共和私有構造函數嗎?

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM