简介

很多人都用过java中的枚举,枚举是JAVA 1.5中引用的一个新的类型,用来表示可以列举的范围,但是可能很少有人知道java中的enum到底是怎么工作的,enum和Enum有什么关系?Enum可不可以扩展?

一起来看看吧。

enum和Enum

JAVA1.5中引入了枚举类,我们通常使用enum关键字来定义一个枚举类:

public enum StatusEnum {
START(1,"start"),
INPROCESS(2,"inprocess"),
END(3,"end"); private int code;
private String desc; StatusEnum(int code, String desc){
this.code=code;
this.desc=desc;
}
}

上面的枚举类中,我们自定义了构造函数,并且定义了3个枚举对象。

接下来看下怎么来使用这个枚举类:

    public static void main(String[] args) {
StatusEnum start = START;
System.out.println(start.name());
System.out.println(start.ordinal());
System.out.println(start.code);
System.out.println(start.desc);
}

可以输出code和desc很好理解,因为这是我们自定义的枚举类中的属性,但是name和ordinal是什么呢?他们是哪里来的呢?

这里就要介绍java.lang.Enum类了,它是JAVA中所有enum枚举类的父类,name()和ordinal()方法就是在这个类中定义的:

public final int ordinal() {
return ordinal;
} public final String name() {
return name;
}

其中ordinal表示的是枚举类中枚举的位置,那么就是枚举类中枚举的名字。在上面的例子中,START的两个值分别是1和START。

我们来看下Enum类的定义:

public abstract class Enum<E extends Enum<E>>
implements Comparable<E>, Serializable

输入它是一个抽象类,但是编译器是不允许你继承这个类的。如果你强行继承,则会抛错:

Classes cannot directly extend 'java.lang.Enum'

所以说,强扭的瓜不甜,大家一定要记住。

事实上,不仅仅Enum类本身不能被继承,上面创建的enum类StatusEnum也是不能被继承的。

这会造成一个什么问题呢?

如果这个enum是包含在一个外部jar包中的时候,你就没法对该enum进行扩展,在某些特定的情况下,这样的限制可能会带来一些不便。

还好,netty也意识到了这个问题,接下来,我们看下netty是怎么解决的。

netty中可扩展的Enum:ConstantPool

netty中的表示常量的类叫做Constant,它有两个属性,分别是ID和name:

public interface Constant<T extends Constant<T>> extends Comparable<T> {

    int id();

    String name();
}

存储这些Constant的就叫做ConstantPool。ConstantPool中有一个ConcurrentMap用来保存具体的Constant。 我们看一下ConstantPool

的工厂类方法valueOf:

public T valueOf(String name) {
return getOrCreate(checkNonEmpty(name, "name"));
}

valueOf方法传入创建的Constant的名字。然后调用getOrCreate方法来创建新的Constant:

    private T getOrCreate(String name) {
T constant = constants.get(name);
if (constant == null) {
final T tempConstant = newConstant(nextId(), name);
constant = constants.putIfAbsent(name, tempConstant);
if (constant == null) {
return tempConstant;
}
} return constant;
}

可以看到getOrCreate就是向constants Map中创建和获取新创建的constant对象。

使用ConstantPool

ConstantPool是一个抽象类,如果我们需要新建一个枚举类池,可以直接继承ConstantPool,然后实现其中的newConstant方法。下面是一个使用的具体例子:

public final class Foo extends AbstractConstant<Foo> {
Foo(int id, String name) {
super(id, name);
}
} public final class MyConstants { private static final ConstantPool<Foo> pool = new ConstantPool<Foo>() {
@Override
protected Foo newConstant(int id, String name) {
return new Foo(id, name);
}
}; public static Foo valueOf(String name) {
return pool.valueOf(name);
} public static final Foo A = valueOf("A");
public static final Foo B = valueOf("B");
} private final class YourConstants {
public static final Foo C = MyConstants.valueOf("C");
public static final Foo D = MyConstants.valueOf("D");
}

在上面的例子中,我们创建的枚举类继承自AbstractConstant,然后自定义了ConstantPool,从pool中可以返回新创建的Foo对象。

实时上,在netty channel中经常使用的ChannelOption就是AbstractConstant的子类,我们简单来看下其中的实现:

public class ChannelOption<T> extends AbstractConstant<ChannelOption<T>> {

    private static final ConstantPool<ChannelOption<Object>> pool = new ConstantPool<ChannelOption<Object>>() {
@Override
protected ChannelOption<Object> newConstant(int id, String name) {
return new ChannelOption<Object>(id, name);
}
};
public static <T> ChannelOption<T> valueOf(String name) {
return (ChannelOption<T>) pool.valueOf(name);
}
public static <T> ChannelOption<T> valueOf(Class<?> firstNameComponent, String secondNameComponent) {
return (ChannelOption<T>) pool.valueOf(firstNameComponent, secondNameComponent);
}
public static boolean exists(String name) {
return pool.exists(name);
}
public static <T> ChannelOption<T> newInstance(String name) {
return (ChannelOption<T>) pool.newInstance(name);
}

可以看到,ChannelOption中定义了ConstantPool,然后通过ConstantPool的valueOf和newInstance方法来创建新的ChannelOption对象。

总结

如果你也想要对枚举类进行扩展,不妨使用Constant和ConstantPool试试。

本文的例子可以参考:learn-netty4

更多内容请参考 http://www.flydean.com/49-netty-extensible-enum/

最通俗的解读,最深刻的干货,最简洁的教程,众多你不知道的小技巧等你来发现!

欢迎关注我的公众号:「程序那些事」,懂技术,更懂你!

netty系列之:我有一个可扩展的Enum你要不要看一下?的更多相关文章

  1. netty系列之:小白福利!手把手教你做一个简单的代理服务器

    目录 简介 代理和反向代理 netty实现代理的原理 实战 总结 简介 爱因斯坦说过:所有的伟大,都产生于简单的细节中.netty为我们提供了如此强大的eventloop.channel通过对这些简单 ...

  2. Netty系列之Netty百万级推送服务设计要点

    1. 背景 1.1. 话题来源 最近很多从事移动互联网和物联网开发的同学给我发邮件或者微博私信我,咨询推送服务相关的问题.问题五花八门,在帮助大家答疑解惑的过程中,我也对问题进行了总结,大概可以归纳为 ...

  3. 【netty】Netty系列之Netty百万级推送服务设计要点

    1. 背景 1.1. 话题来源 最近很多从事移动互联网和物联网开发的同学给我发邮件或者微博私信我,咨询推送服务相关的问题.问题五花八门,在帮助大家答疑解惑的过程中,我也对问题进行了总结,大概可以归纳为 ...

  4. Netty系列(四)TCP拆包和粘包

    Netty系列(四)TCP拆包和粘包 一.拆包和粘包问题 (1) 一个小的Socket Buffer问题 在基于流的传输里比如 TCP/IP,接收到的数据会先被存储到一个 socket 接收缓冲里.不 ...

  5. netty深入学习之中的一个: 入门篇

    netty深入学习之中的一个: 入门篇 本文代码下载: http://download.csdn.net/detail/cheungmine/8497549 1)Netty是什么 Netty是Java ...

  6. Netty系列之Netty百万级推送服务设计要点(转)

    1. 背景 1.1. 话题来源 最近很多从事移动互联网和物联网开发的同学给我发邮件或者微博私信我,咨询推送服务相关的问题.问题五花八门,在帮助大家答疑解惑的过程中,我也对问题进行了总结,大概可以归纳为 ...

  7. 【读后感】Netty 系列之 Netty 高性能之道 - 相比 Mina 怎样 ?

    [读后感]Netty 系列之 Netty 高性能之道 - 相比 Mina 怎样 ? 太阳火神的漂亮人生 (http://blog.csdn.net/opengl_es) 本文遵循"署名-非商 ...

  8. Netty 系列之 Netty 高性能之道 高性能的三个主题 Netty使得开发者能够轻松地接受大量打开的套接字 Java 序列化

    Netty系列之Netty高性能之道 https://www.infoq.cn/article/netty-high-performance 李林锋 2014 年 5 月 29 日 话题:性能调优语言 ...

  9. netty系列之:netty架构概述

    目录 简介 netty架构图 丰富的Buffer数据机构 零拷贝 统一的API 事件驱动 其他优秀的特性 总结 简介 Netty为什么这么优秀,它在JDK本身的NIO基础上又做了什么改进呢?它的架构和 ...

随机推荐

  1. jsp笔记---标签

    <meta>标签 <meta> 标签提供了 HTML 文档的元数据.元数据不会显示在客户端,但是会被浏览器解析. META元素通常用于指定网页的描述,关键词,文件的最后修改时间 ...

  2. tracert命令简述

    1. 路由跟踪在线Tracert工具说明 Tracert(跟踪路由)是路由跟踪实用程序,用于确定 IP 数据报访问目标所采取的路径.Tracert 命令用 IP 生存时间 (TTL) 字段和 ICMP ...

  3. C++五子棋(五)——实现AI落子

    AI思考落子点 在之前我们已经实现计算权值了,现在要想让AI落子,应根据之前的计算结果使棋子落在分值最大点上.当然可能会出现多个分值相同的最大点,这时在其中随机取一个点落下即可. chessData. ...

  4. bootStrap简要和学习笔记

    bootStrap简要和学习笔记前端在学些了html.css.JavaScript三件套后,我们感觉前端变数太多了,需要创造力来设计一些可能经常使用的界面啊.按钮样式啊等,也就有了一些前端的框架,那何 ...

  5. 2021.12.10 P5041 [HAOI2009]求回文串(树状数组求逆序对)

    2021.12.10 P5041 [HAOI2009]求回文串(树状数组求逆序对) https://www.luogu.com.cn/problem/P5041 题意: 给一个字符串 \(S\) ,每 ...

  6. PostgreSQL 数据库备份脚本

    PostgreSQL 数据库备份脚本 #!/bin/bash # PG家目录(/opt/postgresql/pg96/) PG_HOME=${PGHOME} # pg数据库连接信息 PG_HOST= ...

  7. Linux常用命令学习笔记——基于CentOS 7

    前言:最近在linux培训时复习了一下linux系统中一些常用的命令和用法,整理成了笔记,虽然些许零散,但希望对大家有所帮助. 目录 0.帮助指令 1.关机.重启.注销命令 2.文件和目录操作命令 3 ...

  8. Exception in thread "main" java.awt.AWTError: Assistive Technology not found: org.GNOME.Accessibilit

    系统环境 Ubuntu 20.04 focal 问题分析 该异常出现的原因,从谷歌上可以得到答案 one of the more common causes of this exception is ...

  9. 事务的隔离级别与MVCC

    提到数据库,你多半会联想到事务,进而还可能想起曾经背得滚瓜乱熟的ACID,不知道你有没有想过这个问题,事务有原子性.隔离性.一致性和持久性四大特性,为什么偏偏给隔离性设置了级别? 一切还得从事务说起. ...

  10. 源码解析Synchronous Queue 这种特立独行的队列

    摘要:Synchronous Queue 是一种特立独行的队列,其本身是没有容量的,比如调用者放一个数据到队列中,调用者是不能够立马返回的,调用者必须等待别人把我放进去的数据消费掉了,才能够返回. 本 ...