开发者

Protected in Interfaces

开发者 https://www.devze.com 2023-02-18 07:04 出处:网络
Why are all methods in an interface definition implicitly public? Why does it not allow a protected met开发者_StackOverflow中文版hod?Because an interface is supposed to mean \"what you can see from ou

Why are all methods in an interface definition implicitly public? Why does it not allow a protected met开发者_StackOverflow中文版hod?


Because an interface is supposed to mean "what you can see from outside the class". It would not make sense to add non-public methods.


Although the often quoted reason is that "interfaces define public APIs", I think that is an over-simplification. (And it "smells" of circular logic too.)

It would not be meaningless to have interfaces that have a mixture of access modifiers; e.g. partly public and partly restricted to other classes in the same package as the interface. In fact, in some cases this could be down-right useful, IMO.

Actually, I think that the part of reasoning behind making members of an interface implicitly public is that it makes the Java language simpler:

  • Implicitly public interface members are simpler for programmers to deal with. How many times have you seen code (classes) where the method access modifiers were chosen seemingly at random? A lot of "ordinary" programmers have difficulty understanding how best to manage Java abstraction boundaries1. Adding public/protected/package-private to interfaces makes it even harder for them.

  • Implicitly public interface members simplify the language specification ... and hence the task for Java compiler writers, and the folks who implement the Reflection APIs.

The line of thinking that the "interfaces define public APIs" is arguably a consequence (or characteristic) of the simplifying language design decision ... not the other way around. But in reality, the two lines of thought probably developed in parallel in the minds of the Java designers.

At any rate, the official response to the RFE in JDK-8179193 makes it clear that the Java design team decided2 that allowing protected on interfaces adds complexity for little real benefit. Kudos to @skomisa for finding the evidence.

The evidence in the RFE settles the issue. That is the official reason why that has not been added.


1 - Of course, top-gun programmers have no difficulty with these things, and may welcome a richer palette of access control features. But, what happens when their code is handed over to someone else to maintain?

2 - You may disagree with their decision or their stated reasoning but that is moot.


I have to say that this question has been re-opened by the introduction of default methods in Java 8. The project that I am working on right now is, similar to the base nature of an interface, meant to abstract intention from implementation.

There are several cases in which I could drastically simplify my code with a "default protected" method. It turns out that that doesn't actually work, as interfaces still stick to Java 7 logic. A normal protected method doesn't especially make any sense, for the reasons mentioned above; but if a default public method requires a low-level resource that will not likely change and can be provided by a protected method, it seems to me that having "default protected" work would not only maintain cleaner code, it would protect future users from accidental abuses.

(This tragically does not change the fact that I still need to over-complicate my code with otherwise unnecessary abstracts; but I do intend to put a feature request in at Oracle.)


Several answers here employ circular reasoning to explain why interface methods can't be protected: it's because they have to be public, so obviously they can't be protected!

That explains nothing, but fortunately someone raised an enhancement request for protected methods in interfaces as a JDK bug a couple of years ago, which sheds some light on the issue:

Protected methods in interfaces: share across packages

Since modifiers are a bit limited in Java, a way to share methods across packages is restricted to public methods. Sometimes it is dangerous to make a method public, but it needs to be because of the lack of proper modifiers. My solution overcomes this limitation.

The java language specification doesn't currently allow the protected modifier for interface methods. We can take advantage of this fact and use protected for interface methods for this new feature.

If an interface method is marked protected and the interface is implemented by a class in another package, the method would not need to be public, but could also be private or at least package protected. The method is visible, what ever the class declares it to be and additionally visible in the source package of the interface (and sub packages?).

This way we could share certain methods across well known packages.

And this is the response to that enhancement request, which was closed with status Won't fix:

This proposal attempts to solve a problem in a way that adds complexity and special cases for little actual gain. A typical way to solve this problem is to have a private class that implements a public interface. The implementation methods are public, but are within a private class, so they remain private.

An alternative available starting in Java 9 is to make classes and methods public, but within a module that has a qualified-export to specific "friend" modules instead of being exported to the general public.

So the authoritative takeaways from that bug report are:

  • The current situation is not going to change; interfaces are unlikely to ever support protected methods.
  • The justification for not supporting protected methods in interfaces is that it "adds complexity and special cases for little actual gain".
  • Since Java 9 there is an alternative approach for providing package level access to methods. Use the Java Platform Module System (JPMS) to "make classes and methods public, but within a module that has a qualified-export to specific "friend" modules instead of being exported to the general public".


Because interfaces define public APIs. Anything that's protected is an internal detail which does not belong in an interface.

You can use abstract classes with protected abstract methods, but interfaces are restricted to public methods and public static final fields.


I strongly feel that interfaces should allow protected methods; who said that interfaces have to be visible to everyone in the whole world? As to your point that it might confuse "ordinary" (read:incompetent) programmers: So much of OOP is about properly structuring objects, classes, packages etc., if a programmer has a hard time with doing all that properly, he has a much bigger problem. Java was built for that type of thing.


Perhaps, because it is an interface, i.e. it is there to tell clients what they can do with instances, rather than to tell them what they can not do.


Since an implementing class must implements ALL the methods declared in your interface, what would happen if your implementing class was in a different package ?


Declaring internal subinterfaces is a good practice, but you can not declare your internal methods as protected in an interface in Java, technically.

Of course, you can create another interface for internal use which extends the public interface:

package yourpackage;

public interface PublicInterface {

    public void doThing1();

    public void doThing2();

    public void doThing3();

}

package yourpackage;

interface InternalInterface extends PublicInterface {

    void doAnyInternalThing1();

    void doAnyInternalThing2();

}

You may use the InternalInterface interface inside the package, but you should accept any subtype of PublicInterface (in public methods):

package yourpackage;

public class SomeClass {

    public void someMethod(PublicInterface param) {
        if (param instanceof InternalInterface) {
            // run the optimized code
        } else {
            // run the general code
        }
    }

}

Outside the package users can use PublicInterface without problems.

Usually programmers create abstract classes in similar situations. However, in this case we lose the benefits of multiple inheritance.


Interface If you want to use something like you described go on with abstract classes or nested interfaces.

An exerpt from the Code Style about interface variables, but still apply to methods though:

Interface variables are implicitly public because interfaces are intended to provide an Application Programming Interface (API) that is fully accessible to Java programmers to reference and implement in their own applications. Since an interface may be used in Java packages that are different from their own, public visibility ensures that program code can access the variable.


The only scenario where it would make sense is when you want to restrict visibility to the same package. All the other uses of protected are not applicable. Specifically, protected methods are often used to provide access to some details of lower level implementations for descendants. But declaring that in an interface doesn't make sense, as there's no lower level implementation to expose.

And even the package scenario is not really what interfaces are about.

To achieve what you probably want, you need two interfaces, one for internal use and one that you expose in the public API. (With the internal one possibly, but not necessarily extending the public one.) Or, as others pointed out, an abstract superclass.


Non-public members are generally used by public members. For example, AbstractList.removeRange(int, int) is used by AbstractList.clear(), and overriding it will improve the performance of clear.

If protected methods are allowed in interfaces, it means that most public default implementations will rely on these methods. If a subclass does not need default implementations and override all public methods, then all non-public methods will no longer be useful. And if they are abstract, we will still have to override them, which makes subclasses complicated.


Protected methods are always accessible by sub-class only if subclass extends the base class.

In case of interface, subclass never extends the interface. It implements the interface.

Protected methods are accessible via extend and not with implement.


Interfaces are meant to expose methods to the outer world. Thus these methods are public by nature. However, if you want to introduce abstraction within the same family of classes it is possible by creating another level of abstraction between your interface and implementation class, i.e. an abstract class. An example is demonstrated below.

public interface MyInterface {
    public void publicMethod(); // needs to be public
}

public abstract class MyAbstractClass implements MyInterface {
    @Override
    public void publicMethod() {
        protectedMethod(); // you can call protected method here
        // do other stuff
    }
    protected abstract void protectedMethod(); // can be protected
}

public class MyClass extends MyAbstractClass {
    @Override
    protected void protectedMethod() {
        // implement protected method here, without exposing it as public
    }
}


I know this is very late/old and I am sure that by now you have a lot more experience than me, so if this helps anyone, cheers, ...

I've found a way that keeps things comfortably cohesive, that prevents the usage of objects when dealing with protected's in-package.

In hindsight this seems ridiculously easy, but the fact of the matter is that the goal of whatever is you want to achieve with a piece of code, becomes 10 times more difficult if you spend any amount of time to try to accommodate it to standards and/or adjusts for code reusability.

The reality is that the order, will unfold as you go..

But I made a chart cause it has helped me in something that, depending on the problem can easily mind-bend me.

Protected in Interfaces

public interface CommonPublics {
    void publicInAll();
}
public static abstract class CommonProtecteds implements CommonPublics {
    protected abstract void protectedInAll();
}
public interface MyObjectPublics {
    void myObjectPublic();
}
public static class MyObject extends CommonProtecteds implements MyObjectPublics {

    @Override
    public void publicInAll() {

    }

    @Override
    protected void protectedInAll() {

    }

    @Override
    public void myObjectPublic() {

    }
}

Now when you need to deal with protecteds within the same package, instead of dealing with MyObject, you can deal with CommonProtecteds instead.

Now you could in theory bring whatever logic that handles protected's inside the abstract and that's up to you, but if for whatever reason you are dealing with concurrency, is better to keep everything as tight and as close to the synchronized body as possible. so whatever the protected is required to deal with that may be required inside different locked locations is better placed in the object that will handle it.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号