A solution to the final classes problem
richard.bair at oracle.com
Mon Sep 3 16:42:48 PDT 2012
There are several good reasons for final classes, and security is one of them. Normal developers aren't nearly devious enough, somebody suggested throwing a security exception if somebody subclassed with a security manager installed -- yet this is EXACTLY one of the failure modes that you cannot prevent if you allow subclassing (a finalizer on a class with an exception thrown during instantiation allows a developer to get access to the object even though it didn't finish initialization). Of course non-final classes can be secure -- just as mutable classes can be used with multiple threads, but it is more difficult to do. The rule is that final classes are better for security and evolving the API in a compatible manner (and prevent a host of other API blunders made by people who subclass, for example, hosing the equals implementation). All rules have exceptions (we don't make all objects immutable even though immutable objects are preferable for a host of reasons including in some cases performance and in many cases threading).
If you are an API designer of a large body of API that is expected to both exist for many years and to evolve over the course of many years with many thousands and tens of thousands of developers, then making things final by default until there is shown some compelling reason for the class to be non-final is incredibly prudent. Most developers have never had the challenge of evolving such an API (or of getting reamed in the news over security exploits, most of which are far from obvious). Its a whole different ballgame. Every change we make to a class that is subclassable *will break somebody*. Guaranteed. When you have enough developers, it is inevitable. Any API you can think of that you'd like to add -- somebody somewhere out there has already beaten you to it, and when you add a method (or other) then you will break somebody.
We were lucky that we made all our getters and setters final. At first it might be limiting. However it is really important to the integrity of the system (and it shows up in that security document I linked to) that somebody doesn't subclass and override a getter / setter to do "unnatural" (in a security context, read "nefarious") things. Is it frustrating to have to add a listener when Swing, for example, allowed you to just override the setter / getter? Sure it is, but it avoids a lot of problems this way (including security issues).
It may seem like a straightjacket (and there are no doubt places where we legitimately should allows classes to be subclassed where we presently don't), but making something final until it has explicitly been designed for inheritance is a lesson that we in the Java team have learned by long experience. So we'll address each case as they come to relax the constraint in places that make sense.
On Sep 2, 2012, at 7:06 PM, Debasish Ray Chawdhuri wrote:
> Most importantly, there is no way a making a FileChooser final would
> impose any security. Because, anyway the code showing the FileChooser
> can use the file chosen anyway it wants. Also, since the FileChooser
> does not run in a separate sandbox, the API used by FileChooser, can
> be directly used by any code to do what it wants. FileChooser is just
> a utility, there is no way the security should be implemented there,
> the security has to be in the JVM itself, and then there would be no
> reason to worry about anything else.
> Debasish Ray Chawdhuri
> [A collection of advanced articles on java]
More information about the openjfx-dev