30

I know that an interface must be public. However, I don't want that.

I want my implemented methods to only be accessible from their own package, so I want my implemented methods to be protected.

The problem is I can't make the interface or the implemented methods protected.

What is a work around? Is there a design pattern that pertains to this problem?

From the Java guide, an abstract class wouldn't do the job either.

N.N.
  • 8,336
  • 12
  • 54
  • 94
jbu
  • 15,831
  • 29
  • 82
  • 105
  • What's wrong with abstract classes ( apart from making you subclass ? ) – OscarRyz Jan 08 '09 at 02:23
  • 1
    "If an abstract class contains only abstract method declarations, it should be declared as an interface instead." I didn't question the reasoning behind this, but I guess I should. – jbu Jan 08 '09 at 02:25
  • 1
    The Java Guide was *guiding* you by giving good advice. It's not a rule. – Rob Kennedy Jan 08 '09 at 02:28
  • Most of the times yes, but this is one of the times when you don't necessarily – OscarRyz Jan 08 '09 at 02:28
  • 1
    Its not must for an interface to be public. Someone kindly, edit the question to make the thing clear. Thanks. – Adeel Ansari Jan 08 '09 at 08:36
  • If you don't want to expose your interface implementation to other classes then make a private inner class which implements the interface in question. – pag3faul7 Sep 08 '17 at 09:38

12 Answers12

26

read this.

"The public access specifier indicates that the interface can be used by any class in any package. 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."

Is that what you want?

duffymo
  • 305,152
  • 44
  • 369
  • 561
  • 41
    I think there's a little bit of confusion in the question between the visibility of the interface itself, and the visibility of the interface methods. You can make the interface non-public, but the methods will always be public. – Jon Skeet Jan 08 '09 at 06:25
  • 5
    @Jon : What is the reason/idea behind **"the methods will always be public"** ? – M-D Aug 25 '13 at 03:08
  • @M-D: I don't know, to be honest. – Jon Skeet Aug 25 '13 at 06:40
  • @M-D, There's no particular reason for that, it's most likely simply decided that way (http://stackoverflow.com/a/5377300/632951 ), just like [how static abstract got ruled out arbitrarily](http://stackoverflow.com/q/370962/632951). – Pacerier Sep 10 '14 at 19:26
11

You class can use package protection and still implement an interface:

class Foo implements Runnable 
{
    public void run()
    {
    }
}

If you want some methods to be protected / package and others not, it sounds like your classes have more than one responsibility, and should be split into multiple.

Edit after reading comments to this and other responses:

If your are somehow thinking that the visibility of a method affects the ability to invoke that method, think again. Without going to extremes, you cannot prevent someone from using reflection to identify your class' methods and invoke them. However, this is a non-issue: unless someone is trying to crack your code, they're not going to invoke random methods.

Instead, think of private / protected methods as defining a contract for subclasses, and use interfaces to define the contract with the outside world.

Oh, and to the person who decided my example should use K&R bracing: if it's specified in the Terms of Service, sure. Otherwise, can't you find anything better to do with your time?

kdgregory
  • 38,754
  • 10
  • 77
  • 102
  • Good point! +1 while the interface is public, the implementation could be "default" access modifier. It seems to me this is the right answer! :) – OscarRyz Jan 08 '09 at 02:32
  • I do not understand this answer. Since run is public, it can be called from any package, right? I don't want my implemented method to be called from other packages. – jbu Jan 08 '09 at 02:36
  • but the class you're calling it from is only visible in the package. you're calling run on a particular instance, which isn't public. – duffymo Jan 08 '09 at 02:37
  • Hmm, this isn't really safe. If your package allows a Foo to escape, anyone can reference it as a Runnable and invoke the run method. – erickson Jan 08 '09 at 08:58
  • true, but if letting objects "escape" is an issue with your application, then you need to revisit the design – kdgregory Jan 08 '09 at 12:30
  • 2
    @jbu -- if this answer is indeed what you're looking for, you should accept it... – ericsoco Dec 22 '11 at 00:09
  • @kdgregory I love your last bit to this post (I mean this in all sincerity) I cannot stand people who are over-zealous with their edits and "moderating". – Matthew Apr 25 '20 at 00:38
8

When I have butted up against this I use a package accessible inner or nested class to implement the interface, pushing the implemented method out of the public class.

Usually it's because I have a class with a specific public API which must implement something else to get it's job done (quite often because the something else was a callback disguised as an interface <grin>) - this happens a lot with things like Comparable. I don't want the public API polluted with the (forced public) interface implementation.

Hope this helps.

Also, if you truly want the methods accessed only by the package, you don't want the protected scope specifier, you want the default (omitted) scope specifier. Using protected will, of course, allow subclasses to see the methods.

BTW, I think that the reason interface methods are inferred to be public is because it is very much the exception to have an interface which is only implemented by classes in the same package; they are very much most often invoked by something in another package, which means they need to be public.

Lawrence Dol
  • 63,018
  • 25
  • 139
  • 189
4

This question is based on a wrong statement:

I know that an interface must be public

Not really, you can have interfaces with default access modifier.

The problem is I can't make the interface or the implemented methods protected

Here it is:

C:\oreyes\cosas\java\interfaces>type a\*.java
a\Inter.java
package a;

interface Inter {
    public void face();
}

a\Face.java
package a;

class Face implements Inter {
    public void face() {
        System.out.println( "face" );
    }
}


C:\oreyes\cosas\java\interfaces>type b\*.java
b\Test.java

package b;
import a.Inter;
import a.Face;

public class Test {
    public static void main( String [] args ) {
        Inter inter = new Face();
        inter.face();
    }
}

C:\oreyes\cosas\java\interfaces>javac -d . a\*.java b\Test.java
b\Test.java:2: a.Inter is not public in a; cannot be accessed from outside package
import a.Inter;
        ^
b\Test.java:3: a.Face is not public in a; cannot be accessed from outside package
import a.Face;
        ^
b\Test.java:7: cannot find symbol
symbol  : class Inter
location: class b.Test
        Inter inter = new Face();
        ^
b\Test.java:7: cannot find symbol
symbol  : class Face
location: class b.Test
        Inter inter = new Face();
                          ^
4 errors

C:\oreyes\cosas\java\interfaces>

Hence, achieving what you wanted, prevent interface and class usage outside of the package.

OscarRyz
  • 196,001
  • 113
  • 385
  • 569
  • On, "you can have interfaces with default access modifier"... Nope, all interface methods are inferred public; in fact, specifying a visibility scope is irrelevant and ignored. – Lawrence Dol Jun 05 '15 at 19:37
  • @LawrenceDol And I never said otherwise, in the example even the method is marked as public explicitly, but the interface is not public, so its method cannot be accessed the package, hence making them effectively package protected. – OscarRyz Jun 08 '15 at 19:06
  • Ah, sorry, I misread what you'd written. I wrongly supposed it to be "you can have interface [methods] with default access modifier". – Lawrence Dol Jun 09 '15 at 22:16
3

Here's how it could be done using abstract classes.

The only inconvenient is that it makes you "subclass".

As per the java guide, you should follow that advice "most" of the times, but I think in this situation it will be ok.

public abstract class Ab { 
    protected abstract void method();
    abstract void otherMethod();
    public static void main( String [] args ) { 
        Ab a = new AbImpl();
        a.method();
        a.otherMethod();
    }
}
class AbImpl extends Ab {
    protected void method(){
        System.out.println( "method invoked from: " + this.getClass().getName() );
    }
    void otherMethod(){ 
        System.out.println("This time \"default\" access from: " + this.getClass().getName()  );
    }
}
OscarRyz
  • 196,001
  • 113
  • 385
  • 569
1

Here's another solution, inspired by the C++ Pimpl idiom.

If you want to implement an interface, but don't want that implementation to be public, you can create a composed object of an anonymous inner class that implements the interface.

Here's an example. Let's say you have this interface:

public interface Iface {
    public void doSomething();
}

You create an object of the Iface type, and put your implementation in there:

public class IfaceUser {
    private int someValue;
    // Here's our implementor
    private Iface impl = new Iface() {
        public void doSomething() {
            someValue++;
        }
    };
}

Whenever you need to invoke doSomething(), you invoke it on your composed impl object.

Karl Giesing
  • 1,654
  • 3
  • 16
  • 24
  • I like this solution, although I think it makes the code look messy, it addresses the problem in the most extendable way. – sparkonhdfs Jun 15 '16 at 18:55
1

I just came across this trying to build a protected method with the intention of it only being used in a test case. I wanted to delete test data that I had stuffed into a DB table. In any case I was inspired by @Karl Giesing's post. Unfortunately it did not work. I did figure a way to make it work using a protected inner class.

The interface:

package foo;
interface SomeProtectedFoo {
    int doSomeFoo();
}

Then the inner class defined as protected in public class:

package foo;
public class MyFoo implements SomePublicFoo {
    // public stuff
    protected class ProtectedFoo implements SomeProtectedFoo {
        public int doSomeFoo() { ... }
    }
    protected ProtectedFoo pFoo;
    protected ProtectedFoo gimmeFoo() {
        return new ProtectedFoo();
    }
}

You can then access the protected method only from other classes in the same package, as my test code was as show:

package foo;
public class FooTest {
    MyFoo myFoo = new MyFoo();
    void doProtectedFoo() {
        myFoo.pFoo = myFoo.gimmeFoo();
        myFoo.pFoo.doSomeFoo();
    }
}

A little late for the original poster, but hey, I just found it. :D

Community
  • 1
  • 1
siliconsmiley
  • 339
  • 2
  • 10
0

With an interface you want to define methods that can be exposed by a variety of implementing classes. Having an interface with protected methods just wouldn't serve that purpose.

I am guessing your problem can be solved by redesigning your class hierarchy.

Jonas Eicher
  • 1,413
  • 12
  • 18
0

One way to get around this is (depending on the situation) to just make an anonymous inner class that implements the interface that has protected or private scope. For example:

public class Foo {
    interface Callback {
        void hiddenMethod();
    }

    public Foo(Callback callback) {
    }
}

Then in the user of Foo:

public class Bar {
    private Foo.Callback callback = new Foo.Callback() { 
        @Override public void hiddenMethod() { ... }
    };
    private Foo foo = new Foo(callback);
}

This saves you from having the following:

public class Bar implements Foo.Callback {
    private Foo foo = new Foo(this);

    // uh-oh! the method is public!
    @Override public void hiddenMethod() { ... }
}
Jin
  • 6,055
  • 2
  • 39
  • 72
0

You can go with encapsulation instead of inheritance.

That is, create your class (which won't inherit anything) and in it, have an instance of the object you want to extend.

Then you can expose only what you want.

The obvious disadvantage of this is that you must explicitly pass-through methods for everything you want exposed. And it won't be a subclass...

Michael Haren
  • 105,752
  • 40
  • 168
  • 205
0

I would just create an abstract class. There is no harm in it.

Hash
  • 821
  • 7
  • 19
0

I think u can use it now with Java 9 release. From the openJdk notes for Java 9,

Support for private methods in interfaces was briefly in consideration for inclusion in Java SE 8 as part of the effort to add support for Lambda Expressions, but was withdrawn to enable better focus on higher priority tasks for Java SE 8. It is now proposed that support for private interface methods be undertaken thereby enabling non abstract methods of an interface to share code between them.

refer https://bugs.openjdk.java.net/browse/JDK-8071453