Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can a class have both public and private constructor?

I came across a scenario, where I need a public and a private constructor. A private constructor is needed to set the private field whose type is a private inner class. Is this encoraged or discouraged ? Else what is a better solution for a scenario listed below ?

Please read the comment, which supports my question more meaningfully. Thanks,

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;
}
like image 323
JavaDeveloper Avatar asked Jul 08 '13 05:07

JavaDeveloper


People also ask

Can a class have private and public constructor?

Therefore I can only confirm your finding: yes, the private constructor can coexist with the public one, and yes, it seems like a better solution since more initialization is done before receiving the reference to the new object.

Can we have public and private constructor in Java?

Private constructors in Java are accessed only from within the class. You cannot access a private constructor from any other class. If the object is yet not initialised, then you can write a public function to call the private instructor.

Why we may need both public and private constructor?

It depends on usage. A constructor is needed when you create an instance, so, if you use the type in the same assembly, an instance can be created with internal constructor. A public one is needed when you need to create an instance in some other assembly.

Should a class constructor be public or private?

There is no rule that constructor to be public . Generally we define it public just because we would like to instantiate it from other classes too . Private constructor means,"i dont let anyone create my instance except me ". So normally you would do this when you like to have a singleton pattern.


1 Answers

Can a class have both public and private constructor?

Yes, it is possible.

A private constructor is needed to set the private field whose type is a private inner class. Is this encouraged or discouraged ?

It depends on the situation. Whether you want other class to initialize the state of your object or not. Here I think you have created class CopyTree to return the Copy of Tree which is a private class. So TreeNode class would be encapsulated, hence it leaves you with option of using private constructor capture idiom.

what is a better solution for a scenario listed below ?

In my view private constructor capture idiom is the better solution.

For more information:

you could search for private constructor capture idiom.

An example is given in Solution 53 of Java Puzzlers:

Puzzle 53: Do Your Thing

Now it's your turn to write some code. Suppose that you have a library class called Thing whose sole constructor takes an int parameter:

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

A Thing instance provides no way to get the value of its constructor parameter. Because Thing is a library class, you have no access to its internals, and you can't modify it. Suppose that you want to write a subclass called MyThing, with a constructor that computes the parameter to the superclass constructor by invoking the method SomeOtherClass.func(). The value returned by this method changes unpredictably from call to call. Finally, suppose that you want to store the value that was passed to the superclass constructor in a final instance field of the subclass for future use. This is the code that you'd naturally write:

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

Unfortunately, it isn't legal. If you try to compile it, you'll get an error message that looks something like this:

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

How can you rewrite MyThing to achieve the desired effect? The MyThing() constructor must be thread-safe: Multiple threads may invoke it concurrently.

Solution 53: Do Your Thing

You could try to stash the result of the invocation SomeOtherClass.func() in a static field prior to invoking the Thing constructor. This solution is workable but awkward. In order to achieve thread-safety, you must synchronize access to the stashed value, which requires unimaginable contortions. Some of these contortions can be avoided by using a thread-local static field (java.util.ThreadLocal), but a much better solution exists. The preferred solution is inherently thread-safe as well as elegant. It involves the use of second, private constructor in MyThing:

public class MyThing extends Thing {
    private final int arg;

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

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

This solution uses an alternate constructor invocation. This feature allows one constructor in a class to chain to another constructor in the same class. In this case, MyThing() chains to private constructor MyThing(int), which performs the required instance initialization. Within the private constructor, the value of expression SomeOtherClass.func() has been captured in the parameter i and can be stored in the final field param after the superclass constructor returns.

like image 53
ritesh Avatar answered Oct 06 '22 00:10

ritesh