zoukankan      html  css  js  c++  java
  • java集合-EnumMap与EnumSet

    一:java枚举简介

    1:基本概念:

    • 用enum定义枚举类默认继承了java.lang.Enum类而不是继承了Object类。其中java.lang.Enum类实现了java.lang.Serializable和java.lang.Comparable两个接口
    • 枚举类的构造函数只能使用private访问修饰符,如果省略了其构造器的访问控制符,则默认使用private修饰
    • 枚举类的所有实例必须在枚举类中显式列出,否则这个枚举类将永远都不能产生实例。列出这些实例时,系统会自动添加public static final修饰,无需程序员显式添加。
      2:基本用法:
      用法一:常量
      之前我们使用常量都是定义为public static final XXX,现在我们可以用它
    public enum Color {  
      RED, GREEN, BLANK, YELLOW  
    } 
    

    用法二:switch

    enum Signal {  
        GREEN, YELLOW, RED  
    }  
    public class TrafficLight {  
        Signal color = Signal.RED;  
        public void change() {  
            switch (color) {  
            case RED:  
                color = Signal.GREEN;  
                break;  
            case YELLOW:  
                color = Signal.RED;  
                break;  
            case GREEN:  
                color = Signal.YELLOW;  
                break;  
            }  
        }  
    }  
    

    用法三:向枚举中添加新方法

    public enum Color {  
        RED("红色", 1), GREEN("绿色", 2), BLANK("白色", 3), YELLO("黄色", 4);  
        // 成员变量  
        private String name;  
        private int index;  
        // 构造方法  
        private Color(String name, int index) {  
            this.name = name;  
            this.index = index;  
        }  
        // 普通方法  
        public static String getName(int index) {  
            for (Color c : Color.values()) {  
                if (c.getIndex() == index) {  
                    return c.name;  
                }  
            }  
            return null;  
        }  
        // get set 方法  
        public String getName() {  
            return name;  
        }  
        public void setName(String name) {  
            this.name = name;  
        }  
        public int getIndex() {  
            return index;  
        }  
        public void setIndex(int index) {  
            this.index = index;  
        }  
    }  
    
    
    

    测试端:

    public class EnumTest {
    
    	public static void main(String[] args) {
    		// TODO Auto-generated method stub
    		
    		System.out.println(Color.GREEN.getName());
    		System.out.println(Color.GREEN.getIndex());
    		System.out.println(Color.GREEN.toString());
    		
    
    	}
    
    }
    

    用法四:覆盖枚举的方法

    public enum Color {  
        RED("红色", 1), GREEN("绿色", 2), BLANK("白色", 3), YELLO("黄色", 4);  
        // 成员变量  
        private String name;  
        private int index;  
        // 构造方法  
        private Color(String name, int index) {  
            this.name = name;  
            this.index = index;  
        }  
        //覆盖方法  
        @Override  
        public String toString() {  
            return this.index+"_"+this.name;  
        }  
    }  
    
    

    用法五:实现接口
    所有的枚举都继承自java.lang.Enum类。由于Java 不支持多继承,所以枚举对象不能再继承其他类。

    public interface Behaviour {  
        void print();  
        String getInfo();  
    }  
    public enum Color implements Behaviour{  
        RED("红色", 1), GREEN("绿色", 2), BLANK("白色", 3), YELLO("黄色", 4);  
        // 成员变量  
        private String name;  
        private int index;  
        // 构造方法  
        private Color(String name, int index) {  
            this.name = name;  
            this.index = index;  
        }  
    //接口方法  
        @Override  
        public String getInfo() {  
            return this.name;  
        }  
        //接口方法  
        @Override  
        public void print() {  
            System.out.println(this.index+":"+this.name);  
        }  
    }  
    

    用法六:使用接口组织枚举

    public interface Food {
    	enum Coffee implements Food{  
            BLACK_COFFEE,DECAF_COFFEE,LATTE,CAPPUCCINO  
        }  
        enum Dessert implements Food{  
            FRUIT, CAKE, GELATO  
        } 
    
    }
    
    

    EnumMap基本用法

    public class EnumMap<K extends Enum<K>, V> extends AbstractMap<K, V>
        implements java.io.Serializable, Cloneable
    

    从上述定义可以看出,EnumMap的Key,必须事Enum 类型,而Value可以是任意类型。看下边初始化格式:

    EnumMap<Color, String> enumMap = new EnumMap<Color, String>(Color.class);
    

    实例如下:

    import java.util.EnumMap;
    import java.util.Iterator;
    import java.util.Map.Entry;
    
    public class EnumTest {
    
    	public static void main(String[] args) {
    		// TODO Auto-generated method stub
    		
    		EnumMap<Color, String> enumMap=new EnumMap<>(Color.class);
    		enumMap.put(Color.BLANK, "黑夜就是我的面纱");
    		enumMap.put(Color.GREEN, "我就给你绿帽子");
    		enumMap.put(Color.RED, "红旗我的样子");
    		enumMap.put(Color.BLANK, "黑夜没月亮");
    		Iterator<Entry<Color, String>> iterator=enumMap.entrySet().iterator();
    		while(iterator.hasNext())
    		{
    			System.out.println(iterator.next());
    		}
    		
    
    	}
    
    }
    
    

    运行结果:

    RED=红旗我的样子
    GREEN=我就给你绿帽子
    BLANK=黑夜没月亮
    

    从实例我们发现,可以通过这种方式给枚举赋上特殊的值。

    EnumSet基本用法

    • EnumSet 是一个与枚举类型一起使用的专用 Set 实现。枚举set中所有元素都必须来自单个枚举类型(即必须是同类型,且该类型是Enum的子类)。枚举类型在创建 set 时显式或隐式地指定。枚举 set 在内部表示为位向量。 此表示形式非常紧凑且高效。此类的空间和时间性能应该很好,足以用作传统上基于 int 的“位标志”的替换形式,具有高品质、类型安全的优势。

    • Enumset是个虚类,我们只能通过它提供的静态方法来返回Enumset的实现类的实例。返回EnumSet的两种不同的实现:如果EnumSet大小小于64,就返回RegularEnumSet实例(当然它继承自EnumSet),这个EnumSet实际上至用了一个long来存储这个EnumSet。如果 EnumSet大小大于等于64,则返回JumboEnumSet实例,它使用一个long[]来存储。这样做的好处很明显: 大多数情况下返回的RegularEnumSet效率比JumboEnumSet高很多。
      源码:

    public static <E extends Enum<E>> EnumSet<E> noneOf(Class<E> elementType) {
            Enum<?>[] universe = getUniverse(elementType);
            if (universe == null)
                throw new ClassCastException(elementType + " not an enum");
    
            if (universe.length <= 64)
                return new RegularEnumSet<>(elementType, universe);
            else
                return new JumboEnumSet<>(elementType, universe);
        }
    

    上文说RegularEnumSet方法效率高很多,那为什么呢 ,我们看看RegularEnumSet的源码:
    枚举存储:

    private long elements = 0L;
    

    add方法:

    public boolean add(E e) {
            typeCheck(e);
    
            long oldElements = elements;
            elements |= (1L << ((Enum<?>)e).ordinal());
            return elements != oldElements;
        }
    

    细心的读者发现,小于64位时,仅仅是对一个长整型数据进行操作,效率当然要快许多。
    我们再看看JumboEnumSet类实现:
    枚举值存储:

    private long elements[];
    
     public boolean add(E e) {
            typeCheck(e);
    
            int eOrdinal = e.ordinal();
            int eWordNum = eOrdinal >>> 6;
    
            long oldElements = elements[eWordNum];
            elements[eWordNum] |= (1L << eOrdinal);
            boolean result = (elements[eWordNum] != oldElements);
            if (result)
                size++;
            return result;
        }
    

    从源码看出,JumboEnumSet使用long数组存储数据,添加操作也是操作数组,效率当然要慢点。
    实例:

    import java.util.EnumSet;
    import java.util.Iterator;
    
    public class EnumSetTest {
    
    	public static void main(String[] args) {
    		// TODO Auto-generated method stub
            EnumSet<Color> enumSet=EnumSet.allOf(Color.class);
            Iterator<Color> iterator=enumSet.iterator();
            while (iterator.hasNext()) {
    			System.out.println(iterator.next());
    			
    		}
    	}
    
    }
    

    运行结果:

    RED
    GREEN
    BLANK
    YELLO
    

    综合实例(线程状态)

    public enum ThreadStates {
    	START,
    	RUNNING,
    	WAITING,
    	DEAD;
    }
    
    import java.io.Closeable;
    import java.io.IOException;
    
    /**
     * This Enum example shows all the things we can do with Enum types
     * @author pankaj
     *
     */
    public enum ThreadStatesEnum implements Closeable{
    	START(1){
    		@Override
    		public String toString(){
    			return "START implementation. Priority="+getPriority();
    		}
    
    		@Override
    		public String getDetail() {
    			return "START";
    		}
    	},
    	RUNNING(2){
    		@Override
    		public String getDetail() {
    			return "RUNNING";
    		}
    	},
    	WAITING(3){
    		@Override
    		public String getDetail() {
    			return "WAITING";
    		}
    	},
    	DEAD(4){
    		@Override
    		public String getDetail() {
    			return "DEAD";
    		}
    	};
    	
    	private int priority;
    	
    	public abstract String getDetail();
    	//Enum constructors should always be private.
    	private ThreadStatesEnum(int i){
    		priority = i;
    	}
    	
    	//Enum can have methods
    	public int getPriority(){
    		return this.priority;
    	}
    	
    	public void setPriority(int p){
    		this.priority = p;
    	}
    	
    	//Enum can override functions
    	@Override
    	public String toString(){
    		return "Default ThreadStatesConstructors implementation. Priority="+getPriority();
    	}
    
    	@Override
    	public void close() throws IOException {
    		System.out.println("Close of Enum");
    	}
    }
    

    测试端:

    import java.io.IOException;
    import java.util.EnumMap;
    import java.util.EnumSet;
    import java.util.Set;
    
    public class JavaEnumExamples {
    
    	public static void main(String[] args) throws IOException {
    				
    		usingEnumMethods();
    		
    		usingEnumValueOf();
    		
    		usingEnumValues();
    		
    		usingEnumInSwitch(ThreadStatesEnum.START);
    		usingEnumInSwitch(ThreadStatesEnum.DEAD);
    		
    		usingEnumMap();
    		
    		usingEnumSet();
    		
    	}
    
    	private static void usingEnumSet() {
    		EnumSet<ThreadStatesEnum> enumSet = EnumSet.allOf(ThreadStatesEnum.class);
    		for(ThreadStatesEnum tsenum : enumSet){
    			System.out.println("Using EnumSet, priority = "+tsenum.getPriority());
    		}
    	}
    
    	private static void usingEnumMap() {
    		EnumMap<ThreadStates, String> enumMap = new EnumMap<ThreadStates,String>(ThreadStates.class);
    		enumMap.put(ThreadStates.START, "Thread is started");
    		enumMap.put(ThreadStates.RUNNING, "Thread is running");
    		enumMap.put(ThreadStates.WAITING, "Thread is waiting");
    		enumMap.put(ThreadStates.DEAD, "Thread is dead");
    		
    		Set<ThreadStates> keySet = enumMap.keySet();
    		for(ThreadStates key : keySet){
    			System.out.println("key="+key.toString()+":: value="+enumMap.get(key));
    		}
    		
    	}
    
    	private static void usingEnumInSwitch(ThreadStatesEnum th) {
    		switch (th){
    		case START:
    			System.out.println("START thread");
    			break;
    		case WAITING:
    			System.out.println("WAITING thread");
    			break;
    		case RUNNING:
    			System.out.println("RUNNING thread");
    			break;
    		case DEAD:
    			System.out.println("DEAD thread");
    		}
    	}
    
    	private static void usingEnumValues() {
    		ThreadStatesEnum[] thArray = ThreadStatesEnum.values();
    		
    		for(ThreadStatesEnum th : thArray){
    			System.out.println(th.toString() + "::priority="+th.getPriority());
    		}
    	}
    
    	private static void usingEnumValueOf() {
    		ThreadStatesEnum th = Enum.valueOf(ThreadStatesEnum.class, "START");
    		System.out.println("th priority="+th.getPriority());
    	}
    
    	private static void usingEnumMethods() throws IOException {
    		ThreadStatesEnum thc = ThreadStatesEnum.DEAD;
    		System.out.println("priority is:"+thc.getPriority());
    		
    		thc = ThreadStatesEnum.DEAD;
    		System.out.println("Using overriden method."+thc.toString());
    		
    		thc = ThreadStatesEnum.START;
    		System.out.println("Using overriden method."+thc.toString());
    		thc.setPriority(10);
    		System.out.println("Enum Constant variable changed priority value="+thc.getPriority());
    		thc.close();
    	}
    
    }
    

    运行结果:

    priority is:4
    Using overriden method.Default ThreadStatesConstructors implementation. Priority=4
    Using overriden method.START implementation. Priority=1
    Enum Constant variable changed priority value=10
    Close of Enum
    th priority=10
    START implementation. Priority=10::priority=10
    Default ThreadStatesConstructors implementation. Priority=2::priority=2
    Default ThreadStatesConstructors implementation. Priority=3::priority=3
    Default ThreadStatesConstructors implementation. Priority=4::priority=4
    START thread
    DEAD thread
    key=START:: value=Thread is started
    key=RUNNING:: value=Thread is running
    key=WAITING:: value=Thread is waiting
    key=DEAD:: value=Thread is dead
    Using EnumSet, priority = 10
    Using EnumSet, priority = 2
    Using EnumSet, priority = 3
    Using EnumSet, priority = 4
    
  • 相关阅读:
    error C4996: Function call with parameters that may be unsafe
    C mysql (C API Commands out of sync; you can't run this command now)
    messagpack的使用
    关于openssl的编译与使用
    openssl & openssh
    解决SOCKET通信 ERROR_INSUFFICIENT_BUFFER错误
    C++ mysql 乱码
    [置顶] docker1.12--docker命令行帮助文档
    [置顶] kubernetes资源类型--secret和Service Account
    [置顶] kubernetes资源类型--Volume
  • 原文地址:https://www.cnblogs.com/csuwater/p/5405735.html
Copyright © 2011-2022 走看看