Sealed classes and interfaces restrict which other classes or interfaces may extend or implement them.
For background information about sealed classes and interfaces, see JEP 409.
One of the primary purposes of inheritance is code reuse: When you want to create a new class and there is already a class that includes some of the code that you want, you can derive your new class from the existing class. In doing this, you can reuse the fields and methods of the existing class without having to write (and debug) them yourself.
However, what if you want to model the various possibilities that exist in a domain by defining its entities and determining how these entities should relate to each other? For example, you're working on a graphics library. You want to determine how your library should handle common geometric primitives like circles and squares. You've created a Shape
class that these geometric primitives can extend. However, you're not interested in allowing any arbitrary class to extend Shape
; you don't want clients of your library declaring any further primitives. By sealing a class, you can specify which classes are permitted to extend it and prevent any other arbitrary class from doing so.
Declaring Sealed Classes
To seal a class, add the sealed
modifier to its declaration. Then, after any extends
and implements
clauses, add the permits
clause. This clause specifies the classes that may extend the sealed class.
//Define the following three permitted subclasses, Circle, Square, and Rectangle, in the same module or in the same
sealed class Shape
permits Circle, Square, Rectangle {
}
final class Circle extends Shape {
public float radius;
}
non-sealed class Square extends Shape {
public double side;
}
sealed class Rectangle extends Shape permits FilledRectangle {
public double length, width;
}
final class FilledRectangle extends Rectangle {
public int red, green, blue;
}
Constraints on Permitted Subclasses
Permitted subclasses have the following constraints:
They must be accessible by the sealed class at compile time.
For example, to compile
Shape.java
, the compiler must be able to access all of the permitted classes ofShape
:Circle.java
,Square.java
, andRectangle.java
. In addition, becauseRectangle
is a sealed class, the compiler also needs access toFilledRectangle.java
.They must directly extend the sealed class.
They must have exactly one of the following modifiers to describe how it continues the sealing initiated by its superclass:
final
: Cannot be extended furthersealed
: Can only be extended by its permitted subclassesnon-sealed
: Can be extended by unknown subclasses; a sealed class cannot prevent its permitted subclasses from doing this
For example, the permitted subclasses of
Shape
demonstrate each of these three modifiers:Circle
isfinal
whileRectangle
is sealed andSquare
isnon-sealed
.They must be in the same module as the sealed class (if the sealed class is in a named module) or in the same package (if the sealed class is in the unnamed module, as in the
Shape.java
example).For example, in the following declaration of
sample.Shape
, its permitted subclasses are all in different packages. This example will compile only ifShape
and all of its permitted subclasses are in the same named module.
permits sample.Circle,
sample.Rectangle,
sample.Square { }
No comments:
Post a Comment