36

In the Java tutorial "Defining an Interface", it says

If you do not specify that the interface is public, your interface will be accessible only to classes defined in the same package as the interface.

However, this

interface PPInterface {
    void foo();
    void bar();
}

class NewClass implements PPInterface {
    void foo() {}
    void bar() {}
}

generates compiler errors in NewClass because I am 'attempting to assign weaker access privileges; was public'. So the documentation is wrong, or I did something wrong, or I misinterpreted the documentation?

I suppose I don't have to use an interface-- I like it because it keeps things nicely organized.

Ray Fix
  • 5,575
  • 3
  • 28
  • 30
Pete
  • 16,534
  • 9
  • 40
  • 54

3 Answers3

71

It's the interface itself that can be package-private, not the methods in it. You can define an interface that can only be used (by name) within the package it's defined in, but its methods are public like all interface methods. If a class implements that interface, the methods it defines must be public. The key thing here is that it's the interface type that isn't visible outside the package, not the methods. The docs are not incorrect, because using the methods defined in the interface is not the same as using the interface itself.

Also be aware that when defining an interface, not adding public before a method definition doesn't change anything since the methods are all implicitly public.

If the class(es) that you have implementing the interface are themselves package-private, the publicness of the interface methods is obviously not an issue. You could also, of course, use an abstract class instead of an interface if the single-inheritance issue doesn't get in your way:

abstract class Whatever {
  abstract void foo();
  abstract void bar();
}
ColinD
  • 108,630
  • 30
  • 201
  • 202
  • 8
    Ugh, are we yet again forced to hack around with abstract classes due to access-restriction limitations of Java's `interface` http://stackoverflow.com/questions/5376970/protected-in-interfaces/5377300#5377300 – Pacerier Sep 10 '14 at 19:37
  • "it's the interface type that isn't visible outside the package, not the methods." How can I access public methods of an invisible Type? I still do not understand what the purpose of public methods are in a package - private class (or interface..). – Koray Tugay Nov 22 '16 at 16:48
  • @KorayTugay: Interface methods are always `public`, whether that has a practical effect or not. But if, for example, you have a package-private type that implements some public interface or extends some public type, `public` methods on that class/interface that override methods from the public type are usable from outside the package. – ColinD Nov 22 '16 at 17:33
  • 4
    I consider this one of the greatest annoyances of Java. I want to define an interface that allows unchecked access to members of a collection. However, when a public class implements this interface, I don't want others outside the package to be able to call these unchecked methods. My only option is to use a single-inheritance abstract class or a wrapper class. I don't like either option, to be honest. – HesNotTheStig Jun 14 '17 at 13:46
6

I think (though I could be wrong about this) that the weaker access privileges being discussed here are for the foo() and bar() methods in NewClass. All interface methods are implicitly public, but in NewClass you've left them package-private, which is a weaker guarantee than public. Changing NewClass to read

class NewClass implements PPInterface{
    public void foo() {}
    public void bar() {}
}

probably will fix this.

templatetypedef
  • 362,284
  • 104
  • 897
  • 1,065
  • Indeed... but I don't want to fix it.. I want them to be package-private. The docs were pretty clear that you could do this, so the docs are wrong? Or does it mean that only objects in the package can implement the interface, but the methods are still public? (I guess that's the answer) – Pete Jan 26 '11 at 05:36
  • 3
    @Pete- I think there are two separate issues here. By leaving the interface package-private, the only classes that can reference the interface must be in the same package. However, the methods defined by that interface are implicitly public, and so any class that does implement the interface must also have those particular functions marked private. So no, the docs are not incorrect - there's just two separate visibility levels in play. – templatetypedef Jan 26 '11 at 05:38
  • @templatetypedef "must also have those particular functions marked private". You mean marked *public*, right? – stillanoob Mar 07 '19 at 07:52
0

what worked for me to get around the single-inheritance problem:

Instead of A extends B implements C

I have abstract D (package protected interface in C) extends B

and then A extends D

Works fine. Clean, too, tbh.

Blaze
  • 1,530
  • 2
  • 15
  • 24