乐趣区

关于java:netty系列之我有一个可扩展的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/

最艰深的解读,最粗浅的干货,最简洁的教程,泛滥你不晓得的小技巧等你来发现!

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

退出移动版