tags:

views:

97

answers:

3

Pack.java imports pack.TestPack; but it cannot access it. I cannot 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(){}
}
+3  A: 

You should make TestPack's 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 thing is, even though TestPack visibility is public, its parameterless constructor visibility is package (which is the visibility when you don't specify one explicitly).

package visibility means that classes in the same package will be able to see it. Since TestPack and Pack are not in the same package, Pack can't call TestPack's constructor.

Pablo Santa Cruz
yes but the goal was with private, I can get it work that way but it is not what i want. I want to limit the scope with private.
HH
You want to limit which scope? Constructor's? Class'? If you want a private constructor, you won't be able to instantiate the class outside itself. Usually, the only scenario where you'd like a private constructor is a Factory class.
Pablo Santa Cruz
"the same package" means "to have 'import pkg_name' at the start of the file or does it also require the same directory?
HH
is "public" limited directionally?
HH
@HH "the same package" means that both classes are defined in the same package, i.e. the first line of code is "package ...;" where ... is the same for both definitions.
ig0774
KEY: "The thing is, even though TestPack visibility is public, its parameterless constructor visibility is package". How is the package defined?
HH
@Pablo: how can I modify the visibility of package? Or may you clarify the sentence, please.
HH
@HH: You need to make your constructor public, if you want to instantiate that Class' instances from another package.So, instead of:TestPack() { }Do a:public TestPack() {}That way, you will be able to instantiate TestPack's instances from Pack class.
Pablo Santa Cruz
@HH - packages don't *have* visibility. Or to put it another way, all packages are always visible everywhere. @Pablo is talking about "package private" visibility; i.e. the visibility that (say) a constructor has when you don't declare it as `private`, `protected` or `public`.
Stephen C
@HH - just to complement, the package a class belongs is defined by the `package` line like the first line in TestPack.java (`package pack;`). If there is no such line, the class is in the "default package".
Carlos Heuberger
+1  A: 

In the way you are using getHello function, you may 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 will do:

public class Pack
{
        public static void main(String[] args){
                System.out.println(TestPack.getHello());
        }
}
noinflection
You need hello to be defined as static as well for that to work.
ig0774
A: 

I suggest that you don't make the class public but make the constructor public and have folks use a public interface that your class implements. It is a good idea to start the API to your package to be public interfaces (and perhaps some public abstract classes) and hide your implementation classes by not marking them as public so that you can change these over time. You can then provide a public factory methods in your package which instantiate your package private class and return them as the interface types. Here is an interface which is public:

package stackoverflow;
public interface Widget {
    public void doWidgetWork(String work);
}

Here is the implementation which is "package private". The compiler wont let code outside of the same package import nor 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)[
      // ... 
    }
}

notice there that the second occurrence of the word /package/ is a comment (it is not legal in java to use that word there) but many programmers use such a comment in that position to show people that it was not an accident that the class is not public; it signifies that the developer really intended that the class is deliberately "package private". To let people instantiate the class from outside of your package you provide a static factory class (else an instance factory class):

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 internal classes (the ones you hide as package private). Over time you can change your factory classes to return new classes or rename or delete the WidgetHidden class.

Many frameworks indicate which classes other developers should not use by putting them into a package with the name "internal" in it. The public interfaces would be in the main package (e.g. "com.stackoverflow.widget") and the hidden classes into your internal package which only exposes public factory classes (e.g. "com.stackoverflow.widget.internal").

A variation on the theme is to not use a static method on the factory class; make it a regular method. The alternatives are called "static factories" or "instance factories" depending on whether the method is static or not. Not making the method static seems like more work for people using your package as they first have to instantiate your factory object before using it to create Widget. Where is helpful is when people might want to set some defaults for all widgets on the constructor of the factory then use the none static newInstance methods to specify anything beyond the defaults:

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 );
    }
}

It is possible to get around package private protection using reflection to find and invoke the constructor. A really nice feature of the Spring framework it that it will instantiate classes that are not public even when there is no factory class (although it is more polite to provide factory classes which Spring is happy to use also). 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 that example I used the no arguments constructor but clearly you can find and invoke the two string constructor using the same approach. Clearly such code gets around 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 the package private object should be aware that the class WidgetHidden is not part of the public API of the framework they are using so it likely to be deleted or changed without prior notice by the developer who wrote the package you are using. Renaming it to be WidgetInternal and putting it into an "internal" package make it every more the case you are telling people "do not uses". The JVM has optional security setting which prevent people from doing such tricks; but the person running the JVM has to configure it externally to dis-allow such tricks which is only useful when you want to run someone else code you don't trust and prevent it from pulling such tricks.

The book Effective Java by Josha Block 2nd Edition has a lot of discussion and examples and details of the pitfalls when trying to write a good API. It has a lot of detail to explain why you should always look to hide as many classes as you can with lots of other good "tricks of the trade".

simbo1905