I suggest you not publish the class, but make it a public constructor, and people use the open interface that your class implements. It is a good idea to run the API for your package, to be a public interface (and possibly some public abstract classes), and to hide your implementation classes without marking them as public so that you can change them over time. You can then provide public factory methods in your package that instantiate the private class of your package and return them as interface types. Here is the open interface:
package stackoverflow; public interface Widget { public void doWidgetWork(String work); }
Here is an implementation that is "closed to the package." The compiler does not allow the use of code outside of the same package import and does not use this class at all:
package stackoverflow; class WidgetHidden implements Widget { public WidgetHidden(String configOptionA, String configOptionB){
Please note that the second occurrence of the word / package / is a comment (it does not have the right to use this word java), but many programmers use this comment in this position to show people that it is not an accident that the class is not public; this means that the developer really assumed that the class was intentionally "closed by the package." So that people can instantiate the class outside of your package, you provide a static factory class (another factory instance):
package stackoverflow; public class WidgetFactory { public static Widget newInstance( String configOptionA, String configOptionB) { return new Widget( String configOptionA, String configOptionB); } }
The whole point of the factory class is that it hides your inner classes (the ones you hide as private packages). Over time, you can change the factory classes to return new classes or rename or delete the WidgetHidden class.
Many frameworks indicate which classes of other developers should not be used by putting them in a package called "internal" in it. Public interfaces will reside in the main package (for example, "com.stackoverflow.widget") and hidden classes in an internal package that provides only public factory classes (for example, "com.stackoverflow.widget.internal").
Variant of the topic - do not use the static method in the factory class; make it the usual method. Alternatives are called "static factories" or "instance factories" depending on whether the method is static or not. Not making a static method seems more useful to people using your package, as they first need to instantiate your factory object before using it to create a widget. Where useful when people might want to set some default values โโfor all widgets in the factory constructor, and then use non-static newInstance methods to specify anything other than the default values:
public class WidgetInstanceFactory { private String defaultOptionA = null; public WidgetInstanceFactory( String defaultOptionA ) { this.defaultOptionA = defaultOptionA; } public Widget newInstance( String optionB ) { return new WidgetHidden( this.defaultOptionA, optionB ); } }
You can bypass confidential package protection by using reflection to find and invoke the constructor. A really nice feature of the Spring structure is that it will instantiate classes that are not publicly available, even if there is no factory class (although it is more polite to provide factory classes that Spring is happy to use as well). The following code will work:
package stackoverflow.other; class TestInstantiate { private Widget myWidget = null; public TestInstantiate(){ this.myWidget = instantiatePackagePrivateClass("stackoverflow.WidgetHidden"); } private Widget instantiatePackagePrivateClass(String className) throws ClassNotFoundException, NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException { @SuppressWarnings("unchecked") Class<FileUploadSequence> clazz = (Class<Widget>) Class.forName(className); Constructor<Widget> constructor = clazz.getConstructor(new Class[]{}); constructor.setAccessible(true); Widget widget = (Widget) constructor.newInstance((Object[])null); return widget; } }
In this example, I used the no arguments constructor, but you can explicitly find and call two string constructors using the same approach. Obviously, such code comes close to the intention of the programmer who wrote WidgetHidden; they wanted to hide it, as they are likely to change it. Anyone who uses such a back door to manipulate a package private object should be aware that the WidgetHidden class is not part of the public API of the structure used, so it can be removed or modified without prior notice by the developer who wrote the package you are using. Renaming it to WidgetInternal and including it in an โinternalโ package makes it more specific if you say that people do not. JVM has an additional security setting that prohibits people from doing such tricks; but the person working under the JVM must configure it from the outside to prevent such tricks that are useful only when you want to run someone else's code that you do not trust, and not allow him to extract such tricks.
The Josha Block 2nd Edition Effective Java book has many discussions and examples and details about the pitfalls when trying to write a good API. He has many details to explain why you should always hide as many classes as you can, with many other good โtrading tricksโ.