java17密封类

密封类是Java 17正式支持的一个新特性,、

  • 它让Java中类的继承可以更加细粒度的进行控制。

密封类

在以往的Java类继承中,Java类的继承控制非常有限,

  • 仅能通过final关键字和访问控制符来控制类的继承。例如final类无法被继承;
  • 包私有类仅仅只能在该包下进行继承。

这显然是不够的。

  • 如果一个功能只允许出现在PhonePad上,不允许出现在Computer上。
  • 如果不对该功能的继承实现进行限制,开发人员将很容易滥用该功能的实现类,错误地重用一些代码。这就是密封类产生的原因。

密封类的声明

密封类不仅仅可以是类,也可以是接口。文章中的密封类为统称

  • 密封类(接口)可以明确哪些类和接口可以对其扩展或实现。

  • 你可以通过sealed 修饰符 来表明某个类是密封类。但是下面是一个错误的密封类声明:

**
 * 这是一个错误的示范
 */
public sealed interface SealedService {
   
    void doSomething();
}

密封类(接口)在声明的时候必须明确可继承(实现)的范围,所以上面的写法是错误的。

  • 必须用permits子句指定允许扩展密封类的类,
  • 而且permits关键字位于extends或者implements之后。

简而言之,密封类明确了哪些其他类(或接口)可以扩展它们。

下面是正确的写法:

/**
 * 这是一个正确的示范,明确了可继承的子类为{@link SealedServiceImpl}
 * 该密封类接口同时实现了{@link SuperService} 。继承了 super,且允许 sealed实现
 */
public sealed interface SealedService extends SuperService permits SealedServiceImpl {
    void doSomething();
}

/**
 * 密封类子类。定义为了 最终类
 */
public final class SealedServiceImpl implements SealedService {
    @Override
    public void doSomething() {
        System.out.println("这是一个密封类子类");
    }
}
sealed 
英 /siːld/  美 /siːld/  全球(美国)  
简明 柯林斯 例句 例句、百科在这里  百科
adj. 密封的;未知的
v. 封闭;盖印(seal 的过去分词)

密封类子类的类型

在上面示例中,密封类(接口)的实现类用了final关键字标记,当然密封类的实现类还可以是密封类:

/**
 * 密封类子类
 */
public sealed class SealedServiceImpl implements SealedService permits SonService {
    @Override
    public void doSomething() {
        System.out.println("这是一个密封类子类");
    }
}


public final class SonService extends SealedServiceImpl {
}

那么难道密封类(接口)的子类只能是final类或者密封类,就不能再扩展了?

  • 答案是否定的,
  • 只需要使用关键字non-sealed显式声明密封类的继承实现为非密封类就可以继续扩展了。
public non-sealed class SealedServiceImpl implements SealedService {
    @Override
    public void doSomething() {
    }

    /**
     * 用{@code non-sealed}声明非密封类,就可以继续扩展了
     */
    static class NonSealedExtend extends SealedServiceImpl {

    }

}

总结一下,密封类的子类要么是final Class;要么是sealed Class;要么是non-sealed Class

permits 声明的类必须是直接子类

密封类permits关键字声明的子类必须是直接实现类,为了证明这一点我们这样写:

**
 * 错误的示范 。 sealedService 继承 super ,允许 sealedServiceImpl 实现
 * 但是 在允许 sonService不行。son不是 sealedService的 直接实现类
 */
public sealed interface SealedService extends SuperService permits SealedServiceImpl, SonService {
    void doSomething();
}

// SealedServiceImpl implements SealedService,是直接 实现类,在 允许 sonService 可以
public sealed class SealedServiceImpl implements SealedService permits SonService {
    @Override
    public void doSomething() {
        System.out.println("这是一个密封类子类");
    }
}

//sonService 是 impl的 子类
public final class SonService extends SealedServiceImpl {
}

我使用SonService间接实现了SealedService,结果报错,报错信息要求必须是直接的继承关系。

img

从上图可以看出SonService并非直接实现SealedService,这样会打破密封类的规则,所以无法编译通过。

密封类中permits关键字声明的子类必须是直接子类,不可间接实现。

密封类不支持匿名类和函数式接口

由于密封类必须明确继承实现关系,所以它不支持匿名类。

/**
 * 密封类无法使用匿名类
 *
 * @return the sealed service
 */
public SealedService sealedService(){
    // 提示 Anonymous classes must not extend sealed classes
    return new SealedService() {
        @Override
        public void doSomething() {
            
        }
    };
}

同样也不支持函数式接口:

/**
 * 错误的示范
 */
@FunctionalInterface
public sealed interface SealedService permits SealedServiceImpl {
    void doSomething();
}

总结

密封类已经在Java 17中正式转正,这也是Java 17的非常重要的特性之一。对于需要细粒度控制继承关系的场景来说是非常有用的。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值