netty系列之:我有一个可扩展的Enum你要不要看一下?

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

简介

很多人都用过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/

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

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

相关文章
|
3月前
|
Java Unix Linux
【Netty技术专题】「原理分析系列」Netty强大特性之Native transports扩展开发实战
当涉及到网络通信和高性能的Java应用程序时,Netty是一个强大的框架。它提供了许多功能和组件,其中之一是JNI传输。JNI传输是Netty的一个特性,它为特定平台提供了高效的网络传输。 在本文中,我们将深入探讨Netty提供的特定平台的JNI传输功能,分析其优势和适用场景。我们将介绍每个特定平台的JNI传输,并讨论其性能、可靠性和可扩展性。通过了解这些特定平台的JNI传输,您将能够更好地选择和配置适合您应用程序需求的网络传输方式,以实现最佳的性能和可靠性。
107 7
【Netty技术专题】「原理分析系列」Netty强大特性之Native transports扩展开发实战
|
存储 JSON 编解码
06、Netty学习笔记—(聊天业务优化:扩展序列化算法)
06、Netty学习笔记—(聊天业务优化:扩展序列化算法)
06、Netty学习笔记—(聊天业务优化:扩展序列化算法)
|
存储 缓存 NoSQL
跟着源码学IM(十一):一套基于Netty的分布式高可用IM详细设计与实现(有源码)
本文将要分享的是如何从零实现一套基于Netty框架的分布式高可用IM系统,它将支持长连接网关管理、单聊、群聊、聊天记录查询、离线消息存储、消息推送、心跳、分布式唯一ID、红包、消息同步等功能,并且还支持集群部署。
13372 1
|
3月前
|
消息中间件 Oracle Dubbo
Netty 源码共读(一)如何阅读JDK下sun包的源码
Netty 源码共读(一)如何阅读JDK下sun包的源码
83 1
|
3月前
|
编解码 前端开发 网络协议
Netty Review - ObjectEncoder对象和ObjectDecoder对象解码器的使用与源码解读
Netty Review - ObjectEncoder对象和ObjectDecoder对象解码器的使用与源码解读
88 0
|
3月前
|
编解码 安全 前端开发
Netty Review - StringEncoder字符串编码器和StringDecoder 解码器的使用与源码解读
Netty Review - StringEncoder字符串编码器和StringDecoder 解码器的使用与源码解读
126 0
|
8月前
|
NoSQL Java Redis
跟着源码学IM(十二):基于Netty打造一款高性能的IM即时通讯程序
关于Netty网络框架的内容,前面已经讲了两个章节,但总归来说难以真正掌握,毕竟只是对其中一个个组件进行讲解,很难让诸位将其串起来形成一条线,所以本章中则会结合实战案例,对Netty进行更深层次的学习与掌握,实战案例也并不难,一个非常朴素的IM聊天程序。 原本打算做个多人斗地主练习程序,但那需要织入过多的业务逻辑,因此一方面会带来不必要的理解难度,让案例更为复杂化,另一方面代码量也会偏多,所以最终依旧选择实现基本的IM聊天程序,既简单,又能加深对Netty的理解。
133 1
|
10月前
|
分布式计算 网络协议 前端开发
【Netty底层数据交互源码】
【Netty底层数据交互源码】
|
10月前
|
Java 容器
【深入研究NIO与Netty线程模型的源码】
【深入研究NIO与Netty线程模型的源码】
|
编解码 弹性计算 缓存
Netty源码和Reactor模型
Netty源码和Reactor模型
84 0