Thursday, 28 July 2022

Java15: sealed classes

Sealed classes and interfaces specify who can extend or implement this class or interface. A sealed class or interface can be extended or implemented only by those classes and interfaces permitted to do so.

 

A class is sealed by applying the sealed modifier to its declaration. For example, the following declaration of Address specifies two permitted subclasses (TemporaryAddress,PermanentAddress).

 

Address.java

package com.sample.app.dto;

public sealed abstract class Address permits TemporaryAddress,PermanentAddress {

	public abstract String getAddress();

}

 

TemporaryAddress.java

package com.sample.app.dto;

public final class TemporaryAddress extends Address{

	@Override
	public String getAddress() {
		return "";
	}

}

 

PermanentAddress.java

package com.sample.app.dto;

public final class PermanentAddress extends Address{

	@Override
	public String getAddress() {
		return "";
	}

}

 

The classes specified by permits must be located near the superclass:

a.   either in the same module (if the superclass is in a named module) or

b.   in the same package (if the superclass is in the unnamed module).

 

There is another alternative way to define a sealed class. When the permitted subclasses are small in size and number, it may be convenient to declare them in the same source file as the sealed class. When they are declared in this way, the sealed class may omit the permits clause, and the Java compiler will infer the permitted subclasses from the declarations in the source file

 

Animal.java

package com.sample.app.dto;

public abstract sealed class Animal {

    public abstract String aboutMe();

    public static Animal tiger() {
        return new Tiger();
    }

    public static Animal lion() {
        return new Lion();
    }
}

final class Tiger extends Animal {

    @Override
    public String aboutMe() {
        return "I am Tiger";
    }

}

final class Lion extends Animal {

    @Override
    public String aboutMe() {
        return "I am Lion";
    }

}

 

In this example, sealed class Animal is inferred to have two permitted subclasses (Lion, Tiger).

 

SealedClassDemo1.java

package com.sample.app;

import com.sample.app.dto.Animal;

public class SealedClassDemo1 {

    public static void main(String[] args) {
        Animal lion = Animal.lion();
        Animal tiger = Animal.tiger();

        System.out.println(lion.aboutMe());
        System.out.println(tiger.aboutMe());

    }

}

 

Output

I am Lion
I am Tiger

 

What happen if a non-permitted class try to extend a sealed class?

Compiler throws an error by saying ‘class is not allowed to extend sealed class: Address’.

 

What are the constraints on permitted classes?

a.   The sealed class and its permitted subclasses must belong to the same module, and, if declared in an unnamed module, the same package.

b.   Every permitted subclass must directly extend the sealed class.

c.    Every permitted subclass must choose a modifier to describe how it continues the sealing initiated by its superclass.

1.   A permitted subclass may be declared final to prevent its part of the class hierarchy from being extended further.

2.   A permitted subclass may be declared sealed to allow its part of the hierarchy to be extended further than envisaged by its sealed superclass, but in a restricted fashion.

3.   A permitted subclass may be declared non-sealed so that its part of the hierarchy reverts to being open for extension by unknown subclasses. (A sealed class cannot prevent its permitted subclasses from doing this.)

 

You can correlate the above points with below example.


 

 

Shape.java

 

package com.sample.app.dto;

public sealed class Shape {

}

/* 1. A permitted subclass may be declared final */
final class Circle extends Shape {
}

/*
 * 2. A permitted subclass may be declared sealed to allow its part of the
 * hierarchy to be extended further than envisaged by its sealed superclass
 */
sealed class Square extends Shape permits FilledSquare {
}

final class FilledSquare extends Square {
}

/*
 * 3. A permitted subclass may be declared non-sealed so that its part of the
 * hierarchy reverts to being open for extension by unknown subclasses.
 */
non-sealed class Rectangle extends Shape {
}

class MyRect extends Rectangle {
}

 

References

https://openjdk.org/jeps/360

  

Previous                                                 Next                                                 Home

No comments:

Post a Comment