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

问题描述:

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

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

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; 
} 
+2

检查:http://stackoverflow.com/a/11360712/1544069 – ritesh

+1

你为什么不接受一个答案?他们都花时间回复你的帖子,所以你至少可以做回报。来吧;) – Andy

+1

当然,我的歉意。请留意并感谢整个社区的帮助,同时感谢您的关注。 – JavaDeveloper

能否一类具有公共和私有构造?

是的,这是可能的。

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

这取决于具体情况。无论你想让其他课程初始化你的对象的状态与否。在这里,我认为你已经创建了类CopyTree来返回一个私有类的树副本。所以TreeNode类将被封装,因此它会让您选择使用私有构造函数捕获习惯用法。

对于下面列出的方案,什么是更好的解决方案?

在我看来,private构造函数capture成语是更好的解决方案。

欲了解更多信息:

您可以搜索private constructor capture idiom

的例子在Java Puzzlers溶液53给出:

谜题53:做你的事

现在轮到你编写一些代码。假设你有这个事情,其唯一的构造函数库类接受一个int参数:

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

事实例提供没有办​​法得到它的构造函数参数的值。因为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:做你的事

你可以尝试调用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中捕获,并且可以在超类构造函数返回后存储在最终字段参数中。

使用Private 构造函数,可以防止类被其调用者明确实例化。

凡私有构造函数是有用的,只包含静态实用方法包含

  • 类唯一不变
  • 类型安全枚举
  • 单身
  • 在那里他们被证明是

    • 类缺点(不限于以下几点,名单可能会增加)

      • 没有公开或受保护建筑商的类别不能被 分类。
      • 它们不容易与其他静态方法区分开来。

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

    public class MyClass { 
    private MyClass(){ 
    
    } 
    public MyClass(int i){ 
    
    } 
    } 
    

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