简介
很多人都用过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/
最艰深的解读,最粗浅的干货,最简洁的教程,泛滥你不晓得的小技巧等你来发现!
欢送关注我的公众号:「程序那些事」,懂技术,更懂你!
发表回复