Java Newbie Problem: Private Access Package

Pack.java imports pack.TestPack; but he cannot access him. I do not understand why it cannot access the class, despite the import.

Error

Pack.java:7: TestPack() is not public in pack.TestPack; cannot be accessed from outside package System.out.println(new TestPack().getHello()); ^ 1 error 

Pack.java

 import pack.TestPack; import java.io.*; public class Pack { public static void main(String[] args){ System.out.println(new TestPack().getHello()); } } 

Testpack.java

 package pack; import java.util.*; import java.io.*; public class TestPack { private String hello="if you see me, you ar inside class TestPack"; public String getHello(){return hello;} TestPack(){} } 
+4
source share
3 answers

You must make the TestPack constructor public.

 public class TestPack { private String hello="if you see me, you ar inside class TestPack"; public String getHello(){return hello;} public TestPack(){} } 

The fact is that, despite the fact that the visibility of TestPack is public, its constructor visibility without package parameters (this is visibility if you do not specify it explicitly).

package visibility means that classes in one package can see this. Because TestPack and Pack are not in the same package, the package cannot call the TestPack constructor.

+4
source

In how you use the getHello function, you can start thinking using static methods

 public class TestPack { private static String hello="if you see me, you ar inside class TestPack"; public static String getHello(){return hello;} private TestPack(){} } 

then you just do:

 public class Pack { public static void main(String[] args){ System.out.println(TestPack.getHello()); } } 
0
source

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; /*package*/ class WidgetHidden implements Widget { public WidgetHidden(String configOptionA, String configOptionB){ // ... } public WidgetHidden(){ // ... } public void doWidgetWork(String work)[ // ... } } 

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โ€.

0
source

Source: https://habr.com/ru/post/1308632/


All Articles