80

On more than one occasion I have found myself desiring a variable visibility that is not possible in Java. I wanted certain members to be visible within their own class and within any sub-classes, but not to the rest of the package or to the rest of the world. In other words, I wanted this:

Modifier        Class     Package   Subclass  World
sub-class       Y         N         Y         N

However, the designers of Java only gave me this:

Modifier        Class     Package   Subclass  World
public          Y         Y         Y         Y
protected       Y         Y         Y         N
no modifier     Y         Y         N         N
private         Y         N         N         N

The typical case when I want something like this is when creating an abstract class. Sometimes I find the abstract parent needs access to certain members, but concrete children do as well. I can give them this access by making the members protected, but that opens up accessibility to the rest of the package when I don't really want to.

To be fully clear, I know such a modifier is not possible in Java. My question is why is such a modifier not included in Java? It seems (to me) to be a more natural visibility level than either protected or the default. Is the reason just along the lines of it not being sufficiently important to be included, or is it more related to possible side effects that I haven't considered?

Michael McGowan
  • 6,528
  • 8
  • 42
  • 70
  • 1
    As a workaround for this kind of restriction, you could make the variables private and then use a static inner class to achieve this. – Jeff Foster Mar 14 '11 at 14:49
  • 1
    Perhaps because usually, people create subclasses that live in a different package than the parent? One typical example is extending third party libraries to provide our own implementation. – adarshr Mar 14 '11 at 14:50
  • 1
    @adarshr: that's the precise reason for a sub-class modifier to exist. If all sub-classes where in the same package as the super class, it wouldn't be any different from protected. – aioobe Mar 14 '11 at 14:52
  • 5
    As it happens Java 1.0 had `private protected`. I believe the implementation was buggy. Dropped in 1.1. – Tom Hawtin - tackline Mar 14 '11 at 15:03
  • @Tom, interesting! You have a reference for that? – aioobe Mar 14 '11 at 15:06
  • 5
    I also miss this visibility, for the same reasons as @Michael. It feels kind of "unnecessary" to put my classes in a separate package(abstract superclass and concrete subclasses) just to restrict visibility. Also making such hacky solutions like making super class concrete adding it as a private member variable in subclasses, implementing some interface and so on, it makes the code more complicated than it should. private protected would really make things nicer by bringing encapsulation while inheriting, to the least amount of complexity. – Robert Sep 09 '14 at 12:27

3 Answers3

21

I suppose they want to avoid the added complexity by having a non-linear access hierarchy.

You should have control over your package, so simply don't call these protected methods there.

(By the way, protected is not quite the same as sub-class and package, as non-static protected methods (if not in the same package) can't be called on arbitrary objects of the declaring class, but only on objects of the subclass the code is in. (You can see this on Object.clone(), which can only be called by the class whose object is being cloned.))

Paŭlo Ebermann
  • 73,284
  • 20
  • 146
  • 210
  • I don't understand your comment in parenthesis. protected *is* sub-class visiblity + package visiblity. What do you mean? – ewernli Apr 25 '13 at 06:34
  • 1
    @ewernli `protected` is a bit less. Although every class inherits from `Object` (i.e. `clone()` should be visible everywhere), you can't call `anyObject.clone()` for an arbitrary object. – Paŭlo Ebermann Apr 25 '13 at 19:21
  • 1
    In a similar manner, any instance of class can access the `private` members of another instance of the same class. You would think that because a member is `private`, only that instance should be able to access it, but as @PaŭloEbermann was saying, you would have _full_ control over the class already. If you're accessing `private` members of another instance, it's because _you_ designed it that way. On the same note, if you are developing a package and you access a `protected` member of another class, it's because _you_ are the one developing that package, to which others do not have access. – Michael Plautz Nov 21 '13 at 15:53
  • Old comments/question to comment, but can somebody clarify the statement - "You should have control over your package"? If I have a 3rd party library, then I can always create a package with the same hierarchy and access the protected members if required. Isn't that the case? – Mubin Apr 22 '14 at 14:19
  • @Mubin this is the case, yes (if there isn't a security manager which restricts which class loader can create classes in a package). But you could also create a modified version of your third party library, and by make private members public. Or use reflection. All of these access modifiers are not waterproof at all. – Paŭlo Ebermann Apr 22 '14 at 18:14
9

Being-in-the-same-package is simply considered a closer relationship than being-a-subtype-of.

Why?

You typically control all source code of the package you're developing(*), so you at least have the possibility to avoid making erroneous calls.

You do not control all code that extends your classes. (Anyone can extend your class.) This means that package private access plays a more important role.


*) But hey, I can start any source file with package com.yourpackage; so you don't control all code in your package! Well, yes, but a) you're not really supposed to do that, and b) it can be prevented by sealing the packages.

Pang
  • 9,564
  • 146
  • 81
  • 122
aioobe
  • 413,195
  • 112
  • 811
  • 826
  • I can't decide which relationship I think is closer. My instinct was that *being-a-subtype-of* was a closer relationship (and maybe that's part of the reason I think this type of modifier makes more sense than protected and default). However, some random coder using a JAR library that I created could sub-class one of my classes, whereas I probably know what's going on in my package. Hmmm... – Michael McGowan Mar 14 '11 at 15:23
  • Yep. Precisely I course of thoughts too. And you could even strike *"probably"* in your last sentence if you [seal the package](http://download.oracle.com/javase/tutorial/deployment/jar/sealman.html). – aioobe Mar 14 '11 at 15:27
  • I'm having difficulty imagining a scenario where you would not want a sealed package. – corsiKa Apr 13 '11 at 22:01
3

You should put your class in a package of its own and mark the member (instance variable or method) as protected. This way, no other classes, except the subclasses, can access that member which you marked as protected. You will end up with one class in one package, if you desperately want only subclasses to access that protected member.

Pang
  • 9,564
  • 146
  • 81
  • 122
jumping-jack
  • 237
  • 1
  • 3