public methods in package-private classes
Asked Answered
P

9

51

Does it make a difference to mark methods as public in package-private classes?

class SomePackagePrivateClass
{
    void foo();          // package private method

    public void bar();   // public method
}

Is there any practical difference in visibility between foo and bar here?

Paulettapaulette answered 10/3, 2011 at 13:49 Comment(0)
H
23

If the class is not going to be extended by another, more visible subclass*, the only difference is clarity of intent. Declaring all methods package private makes it more difficult for future readers to determine which of the methods are meant to be called by other classes in the same package.

*which would not make much sense as a design solution to me, but technically is possible nevertheless.

Holster answered 10/3, 2011 at 13:52 Comment(2)
"Declaring all methods private" should be read "Declaring all methods package-private", and "the enclosing class" as "other classes", I guess, but otherwise +1Typhus
@Puce, correct, I misread the question slightly. Now fixed, thanks :-)Crews
H
58

Example using inheritance:

A.java

package pkg1;

class A {
  void foo() {};
  public void bar() {};
}

B.java

package pkg1;

public class B extends A {

}

C.java

package pkg2;

import pkg1.*;

public class C {
  public void doSomething() {
   B b = new B();
   b.bar(); //ok
   b.foo(); //won't work, since foo() is not visible outside of package 'pkg1'

   A a = new A(); //won't work since A is not visible outside of package 'pkg1'
   a.bar(); //won't work, since a cannot be created
  }
}
Hulking answered 10/3, 2011 at 14:15 Comment(0)
H
23

If the class is not going to be extended by another, more visible subclass*, the only difference is clarity of intent. Declaring all methods package private makes it more difficult for future readers to determine which of the methods are meant to be called by other classes in the same package.

*which would not make much sense as a design solution to me, but technically is possible nevertheless.

Holster answered 10/3, 2011 at 13:52 Comment(2)
"Declaring all methods private" should be read "Declaring all methods package-private", and "the enclosing class" as "other classes", I guess, but otherwise +1Typhus
@Puce, correct, I misread the question slightly. Now fixed, thanks :-)Crews
M
10

Another case where the method has to be public is when you are creating a package private implementation of some public class or interface. Since you are not allowed to reduce the visibility of overridden methods, these have to be public.

Maladminister answered 10/3, 2011 at 14:39 Comment(0)
T
6

It makes very little difference, unless the class is extended by a public (or protected nested) class.

As a matter of consistency, I'd go for public. It should be rare for methods to be anything other than public or private.

There are a number of examples of public methods in the package private java.lang.AbstractStringBuilder class. For instance length() is public in AbstractStringBuilder and is exposed in the public class StringBuilder (overridden in StringBuffer to add synchronisation).

Truthful answered 10/3, 2011 at 13:50 Comment(3)
does extending a private class make sense.?Quetzalcoatl
Extending a package private class can make sense, e.g. when the class provides some internal base which is shared by different implementations in the package (there are some Open Source projects which are doing this).Hulking
AbstractStringBuilder (?) is extended by StringBuffer and StringBuilder (it's in the API docs, but that's probably a bug/misfeature in JavaDoc).Truthful
S
6

Well... i had this doubt also (that's why i searched for this thread). This might be a good question.

But ...

After a second thought, things are really simpler than we thought.

A package-private method, is a package-private method.

Seems nonsense? But ...

A package-private method, even if its class is inherited, it is still a package-private method.

Does it make more sense now? For a more verbose explanation:

A package-private method, even if its class is inherited by a more visible subclass, it is still a package-private method.

If the subclass is of the same package, those package-private methods are also inherited, but they are still package-private.

If the subclass is of the different package (of here, we need the parent class to be public, with some package-private methods), those package-private methods are not inherited (because they are not visible at all).

A point to note, which may be the cause of this doubt, that a package-private method in a public class is not visible outside its package also.


The above explains about the package-private method. And the case of the public-method is just the same.

When a package-private class is inherited by a pubic subclass (of the same package, this is a must), its public methods are inherited as public methods, and thus they become public methods in a pubic class.

In the OP example, as foo() and bar() are both in a package-private class, their visibilities are limited to package-private at this moment, until further codes are added (e.g. inheritance).

Hope this is clear (and simple) enough.

P.S. the Java access control table

Sequestration answered 14/5, 2013 at 18:8 Comment(0)
M
6

Yes. public methods in a package-private class can be useful (although they are rare). Illustrative example from the java library (and taken from the classic book "effective java"):

Have you ever seen the java.util.JumboEnumSet, java.util.RegularEnumSet?? Probably not, because they are private, and are not mentioned in the documentation.

Have you ever used them?? Probably yes. They are returned by the static method of java.util.EnumSet.noneOf(...). Although you can't construct them yourself, you can use their public methods when they are returned from this method.

The good thing about that is that you don't know which one you are using, or even that they exist. Java decides which one is more efficient depending on the arguments, and might use a different on in a newer version. You only access their functionality by referring to them through their common interface (which is a good practice anyway!!)

Metallize answered 22/12, 2016 at 11:25 Comment(0)
M
0

One good utilization for that is when you want to restrict your class to your package but still want to use proxy-generated stuff, such as the @Transactional right above the following a method.

@Service
class SomeService {

   @Transactional
   public void someTxStuff() {
     /// very complicated code here
   }
}

If someTxStuff were package-private, @Transactional annotation wouldn't have any effect.

Mejias answered 14/1, 2021 at 2:33 Comment(0)
A
0

There is a difference when you make reflective access to the method: jdk.internal.reflect.Reflection.verifyMemberAccess() will decline access to the method when you try to call it from a class which is not in the same package as your package-private class even if it is a method which is an overridden method of a public class/interface. Consider following example:

package pkg1;
public interface PublicInterface {
    int i();
}
package pkg2;
import pkg1.PublicInterface;
class PackagePrivateImpl implements PublicInterface {
    @Override public int i() {
        return 42;
    }
}
package pkg2;
import pkg1.PublicInterface;
public class ImplFactory {
    public static PublicInterface impl() {
        return new PackagePrivateImpl();
    }
}
package pkg1;
import java.lang.reflect.Method;
import pkg2.ImplFactory;
public class ReflectiveFail {
    public static void main(String... args) throws Exception {
        PublicInterface impl = ImplFactory.impl();
        System.out.println(impl.i()); // 42
        Method interfaceMethod = PublicInterface.class.getMethod("i");
        System.out.println(interfaceMethod.invoke(impl)); // 42
        Method implMethod = impl.getClass().getMethod("i");
        System.out.println(implMethod.invoke(impl)); // IllegalAcessException
    }
}

The last call to implMethod.invoke() will throw an IllegalAccessException with the following message:

Exception in thread "main" java.lang.IllegalAccessException: class pkg1.ReflectiveFail cannot access a member of class pkg2.PackagePrivateImpl with modifiers "public"
Aube answered 18/7, 2022 at 14:37 Comment(0)
Q
-1

foo has default package visibility where as bar has public visibility

Quetzalcoatl answered 10/3, 2011 at 13:51 Comment(4)
But bar doesn't really have public visibility because it is in a class that has default access ("package private").Truthful
public void bar the modifier used here is public so i guess it has public visibility.please correct me if im wrongQuetzalcoatl
public void bar() has public visibility, but as Tom said, practically you don't have public access to the class and thus no real public access to the method (since you don't even see the class). When inheritance is involved things become different though, just as Tom pointed out in his answer.Hulking
@Thomas,I will highly thankful to you if you can give me a working CODE example.im quite confused now.Quetzalcoatl

© 2022 - 2024 — McMap. All rights reserved.