views:

335

answers:

5

I have a package with a

public abstract class Player { /*...*/ }

and these

public abstract class GamePlayer extends Player { /*...*/ }
public abstract class TournamentPlayer extends Player { /*...*/ }
public abstract class StatelessPlayer extends Player { /*...*/ }

Users of the package need Players but in order to use the package without breaking it I require that they never directly extend Player. Instead they should extend one of the subclasses provided.

Question: How should I prevent users from extending Player directly?

I'm looking for a way that makes it obvious that this prohibition is intended.

A: 

Use the default access modifier, also known as "Package private" access. In other words, don't specify an access modifier

abstract class Player { /*...*/ }

The documentation here at Sun's website describes all of the access modifiers in greater detail.

whaley
But then will clients even be able to see the class? Sorry I don't have a javac handy to check myself.
jjujuma
No, they won't - which is why it should only be the constructor which is non-public.
Jon Skeet
hmm, good point...
Alnitak
an alternative might be a public interface, combined with the package-private abstract base class...
Alnitak
eh, Jon Skeet is correct, as I knee-jerk answered that without realizing the class still needs to be publicly available. Alnitak's suggestion is quite good also.
whaley
+7  A: 

Make the constructors in Player have package access only. Then they won't be able to call the constructor or extend it themselves. If you don't already have an explicit constructor in Player, create one (as otherwise the compiler will create a default public parameterless constructor).

(Note that I've only suggested doing this to the constructor. The class itself can be public so that clients can still use it.)

This works because any constructor (other than in java.lang.Object) has to call a superclass constructor (either explicitly or implicitly). If there are no accessible constructors, you can't create the subclass.

Jon Skeet
+1 for the note about the implicit public default constructor
Alnitak
+9  A: 

Make sure the constructors of Player are not public:

public abstract class Player {
    Player() {
        // initialization goes here
    }
}

Then classes can extend Player from within the same package, but should not be able to from outside of the package.

Lee
And not protected either...
Tom Hawtin - tackline
+1  A: 

Um... make the Player class non-public? Just leave out "public", then it will be package-private, i.e. only classes in the same package can extend it.

However, nothing outright prevents people from putting their own classes in that package. I believe it's possible to prevent it by putting it into a signed JAR, then any attempt to load an unsigned (or differently-signed) class in the same package will fail.

Michael Borgwardt
I believe that prevents *use* outside the package as well as, not just inheritance.
Herms
A: 

I'd recommend

  • Create public interfaces for things you want clients to access but not create or subclass
  • Create public classes for things you want clients to access and create or subclass
  • anything else should be non-public

The problem with this approach is that you end up with everything needing to be in a single package, which is bad for organization as the library grows.

To allow use of multiple packages with protection, take a look at OSGi.

OSGi allows you to restrict which packages a bundle (jar) allows other bundles to access, and even set up "friend" bundles that are allowed extra visibility.

Java's package-as-protection-unit model is not sufficient when you really want to protect libraries that get large...

Scott Stanchfield