zoukankan      html  css  js  c++  java
  • Java_枚举

    Overview

    • 枚举类型

    • 枚举常量在类型安全性和便捷性都很有保证,如果出现类型问题,编译器会提醒我们改进

    • Day day = Day.MONDAY;

    枚举实现原理

    • 在使用关键字enum创建枚举类型并编译后,编译器会为我们生成一个相关的类,这个类继承了java.lang.Enum

    • 反编译的一个枚举类:

       enum Day {
           MONDAY, TUESDAY, WEDNESDAY,
           THURSDAY, FRIDAY, SATURDAY, SUNDAY
       }
       //反编译Day.class
       final class Day extends Enum
       {
           //编译器为我们添加的静态的values()方法
           public static Day[] values()
          {
               return (Day[])$VALUES.clone();
          }
           //编译器为我们添加的静态的valueOf()方法,注意间接调用了Enum也类的valueOf方法
           public static Day valueOf(String s)
          {
               return (Day)Enum.valueOf(com/zejian/enumdemo/Day, s);
          }
           //私有构造函数
           private Day(String s, int i)
          {
               super(s, i);
          }
            //前面定义的7种枚举实例
           public static final Day MONDAY;
           public static final Day TUESDAY;
           public static final Day WEDNESDAY;
           public static final Day THURSDAY;
           public static final Day FRIDAY;
           public static final Day SATURDAY;
           public static final Day SUNDAY;
           private static final Day $VALUES[];
       
           static
          {    
               //实例化枚举实例
               MONDAY = new Day("MONDAY", 0);
               TUESDAY = new Day("TUESDAY", 1);
               WEDNESDAY = new Day("WEDNESDAY", 2);
               THURSDAY = new Day("THURSDAY", 3);
               FRIDAY = new Day("FRIDAY", 4);
               SATURDAY = new Day("SATURDAY", 5);
               SUNDAY = new Day("SUNDAY", 6);
               $VALUES = (new Day[] {
                   MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY
              });
          }
       }
      • final类型

      • 继承自java,lang.Enum

      • 前面使用关键字enum定义的每个枚举常量都是实在的Day实例对象

      • 在编辑后,枚举类型的将会转换为一个实实在在的继承自Enum的类,而之前定义的常量也都会转换为对应的实例对象;同时编译器还会再创建两个对象:values()valueOf()

    枚举的常见方法

    Enum抽象类的常见方法

    返回类型方法名称方法说明
    int compareTo(E o) 比较此枚举与指定对象的顺序
    boolean equals(Object other) 当指定对象等于此枚举常量时,返回 true。
    Class getDeclaringClass() 返回与此枚举常量的枚举类型相对应的 Class 对象
    String name() 返回此枚举常量的名称,在其枚举声明中对其进行声明
    int ordinal() 返回枚举常量的序数(它在枚举声明中的位置,其中初始常量序数为零)
    String toString() 返回枚举常量的名称,它包含在声明中
    static<T extends Enum<T>> T static valueOf(Class enumType, String name) 返回带指定名称的指定枚举类型的枚举常量
    • compareTo(E o)方法则是比较枚举的大小,注意其内部实现是根据每个枚举的ordinal值大小进行比较的

    • name()方法与toString()几乎是等同的,都是输出变量的字符串形式

    • valueOf(Class enumType, String name)方法则是根据枚举类的Class对象和枚举名称获取枚举常量

    • 演示上述方法:

       package cn.demo1;
       
       public class EnumDemo {
        public static void main(String[] args) {
        Day[] days = new Day[]{
        Day.MONDAY, Day.TUESDAY, Day.WEDNESDAY,
        Day.THURSDAY, Day.FRIDAY, Day.SATURDAY,
        Day.SUNDAY
        };
       
        System.out.println("/// ordinal() ///////////////////");
        for (int i = 0; i < days.length; i++) {
        System.out.println("days[" + i + "].ordinal(): " + days[i].ordinal());
        }
       
        System.out.println(" /// compareTo() ///////////////////");
        System.out.println("days[0].compareTo(days[1]): " + days[0].compareTo(days[1]));
        System.out.println("days[0].compareTo(days[2]): " + days[0].compareTo(days[2]));
       
        System.out.println(" /// getDeclaringClass() ///////////////////");
        Class<?> clazz = days[0].getDeclaringClass();
        System.out.println("class: " + clazz);
       
        System.out.println(" /// name() ///////////////////");
        System.out.println("days[0].name()" + days[0].name());
        System.out.println("days[1].name()" + days[1].name());
        System.out.println("days[2].name()" + days[2].name());
        System.out.println("days[3].name()" + days[3].name());
       
        System.out.println(" /// toString() ///////////////////");
        System.out.println("days[0].name()" + days[0].toString());
        System.out.println("days[1].name()" + days[1].toString());
        System.out.println("days[2].name()" + days[2].toString());
        System.out.println("days[3].name()" + days[3].toString());
       
        System.out.println(" /// valueOf() ///////////////////");
        Day d1 = Enum.valueOf(Day.class, "MONDAY");
        Day d2 = Enum.valueOf(Day.class, "TUESDAY");
        System.out.println("d1: " + d1);
        System.out.println("d2: " + d2);
       
        }
       }
       
       enum Day {
        MONDAY, TUESDAY, WEDNESDAY,
           THURSDAY, FRIDAY, SATURDAY, SUNDAY
       }
       /// ordinal() ///////////////////
       days[0].ordinal(): 0
       days[1].ordinal(): 1
       days[2].ordinal(): 2
       days[3].ordinal(): 3
       days[4].ordinal(): 4
       days[5].ordinal(): 5
       days[6].ordinal(): 6
       
       /// compareTo() ///////////////////
       days[0].compareTo(days[1]): -1
       days[0].compareTo(days[2]): -2
       
       /// getDeclaringClass() ///////////////////
       class: class cn.demo1.Day
       
       /// name() ///////////////////
       days[0].name()MONDAY
       days[1].name()TUESDAY
       days[2].name()WEDNESDAY
       days[3].name()THURSDAY
       
       /// toString() ///////////////////
       days[0].name()MONDAY
       days[1].name()TUESDAY
       days[2].name()WEDNESDAY
       days[3].name()THURSDAY
       
       /// valueOf() ///////////////////
       d1: MONDAY
       d2: TUESDAY
    • Enum类的主要源码

       //实现了Comparable
       public abstract class Enum<E extends Enum<E>>
               implements Comparable<E>, Serializable {
       
           private final String name; //枚举字符串名称
       
           public final String name() {
               return name;
          }
       
           private final int ordinal;//枚举顺序值
       
           public final int ordinal() {
               return ordinal;
          }
       
           //枚举的构造方法,只能由编译器调用
           protected Enum(String name, int ordinal) {
               this.name = name;
               this.ordinal = ordinal;
          }
       
           public String toString() {
               return name;
          }
       
           public final boolean equals(Object other) {
               return this==other;
          }
       
           //比较的是ordinal值
           public final int compareTo(E o) {
               Enum<?> other = (Enum<?>)o;
               Enum<E> self = this;
               if (self.getClass() != other.getClass() && // optimization
                   self.getDeclaringClass() != other.getDeclaringClass())
                   throw new ClassCastException();
               return self.ordinal - other.ordinal;//根据ordinal值比较大小
          }
       
           @SuppressWarnings("unchecked")
           public final Class<E> getDeclaringClass() {
               //获取class对象引用,getClass()是Object的方法
               Class<?> clazz = getClass();
               //获取父类Class对象引用
               Class<?> zuper = clazz.getSuperclass();
               return (zuper == Enum.class) ? (Class<E>)clazz : (Class<E>)zuper;
          }
       
       
           public static <T extends Enum<T>> T valueOf(Class<T> enumType, String name) {
               //enumType.enumConstantDirectory()获取到的是一个map集合,key值就是name值,value则是枚举变量值  
               //enumConstantDirectory是class对象内部的方法,根据class对象获取一个map集合的值      
               T result = enumType.enumConstantDirectory().get(name);
               if (result != null)
                   return result;
               if (name == null)
                   throw new NullPointerException("Name is null");
               throw new IllegalArgumentException(
                   "No enum constant " + enumType.getCanonicalName() + "." + name);
          }
       
           //.....省略其他没用的方法
       }

       

    编译器生成的Values方法与ValueOf方法

    • 演示代码:

       Day[] days = Day.values();
       System.out.println("days: " + Arrays.toString(days));
       Day day = Day.valueOf("MONDAY");
       System.out.println("day: " + day);
       days: [MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY]
       day: MONDAY

       

    • values()方法的作用就是获取枚举类中的所有变量,并作为数组返回

    • valueOf(String name)方法与Enum类中的valueOf(Class<T> enumType, String name)方法的作用类似,根据名称获取枚举变量,只不过编译器生成的valueOf方法更简洁些,只需传递一个参数

    • 注意到,由于values()方法是由编译器插入到枚举类中的static方法,所以如果我们将枚举实例向上转型为Enum,那么values()方法将无法被调用,因为Enum类中并没有values()方法,valueOf()方法也是同样的道理,注意是一个参数的

    枚举与Class对象

    • Class对象中存在如下方法:

      • 返回类型方法名称方法说明
        T[] getEnumConstants() 返回该枚举类型的所有元素,如果Class对象不是枚举类型,则返回null。
        boolean isEnum() 当且仅当该类声明为源代码中的枚举时返回 true
      • 所以可以通过Class对象来获取所有的枚举实例变量

         Day[] days = Day.values();
         Enum e = Day.MONDAY;
         Class<?> clazz = e.getDeclaringClass();
         if (clazz.isEnum()) {
          Day[]  days2 = (Day[]) clazz.getEnumConstants();
          System.out.println("days: " + Arrays.toString(days2));
         }

    枚举的进阶用法

    • enum定义的枚举类,除了不能使用继承,可以把enum类当成常规类;可以向enum类中添加方法和变量,或者main方法

      • 因为Java是单继承,而枚举类会自动继承Enum抽象类;

    enum类添加方法与自定义构造函数

     package cn.demo1;
     
     public enum Day {
      MONDAY("星期一"), TUESDAY("星期二"), WEDNESDAY("星期三"), THURSDAY("星期四"), FRIDAY("星期五"), SATURDAY("星期六"), SUNDAY("星期日");
     
      private String desc;
     
      private Day(String desc) {
      this.desc = desc;
      }
     
      private String getDesc() {
      return desc;
      }
     
      public static void main(String[] args) {
      for (Day day: Day.values()) {
      System.out.println("name: " + day.name() + " desc: " + day.getDesc());
      }
      }
     
     /*
      * Console Output:
     name: MONDAY desc: 星期一
     name: TUESDAY desc: 星期二
     name: WEDNESDAY desc: 星期三
     name: THURSDAY desc: 星期四
     name: FRIDAY desc: 星期五
     name: SATURDAY desc: 星期六
     name: SUNDAY desc: 星期日
      */
     }
    • 若在enum类中定义方法,则必须在声明完枚举实例后使用分号分开

    覆盖enum类方法

    • 父类Enum中定义的方法只有toString()没有使用final修饰

    enum类中定义抽象方法

    • enum类定义抽象方法,然后每个枚举实例都实现该方法;

     package cn.demo1;
     
     public enum EnumDemo2 {
      FIRST {
      @Override
      public String getInfo() {
      return "HAHA";
      }
      },
      SECOND {
      @Override
      public String getInfo() {
      return "XIXI";
      }
      };
     
      public abstract String getInfo();
     
      public static void main(String[] args) {
      System.out.println(EnumDemo2.FIRST.getInfo());
      System.out.println(EnumDemo2.SECOND.getInfo());
      }
     
     /*
      * Console Output:
     HAHA
     XIXI
      */
     }

    enum类实现接口

     package cn.demo1;
     
     interface food {
      void eat();
     }
     
     interface sport {
      void run();
     }
     
     public enum EnumDemo3 implements food, sport {
      FOOD,
      SPORT
      ;
     
      @Override
      public void run() {
      // TODO Auto-generated method stub
     
      }
     
      @Override
      public void eat() {
      // TODO Auto-generated method stub
     
      }
     
     }
    • enuminterface结合对数据进行分类

       package cn.demo2;
       
       /* 对数据进行分类 */
       public interface Food {
        enum Appetizer implements Food {
        SALAD, SOUP, SPRING_ROLLS;
       
        @Override
        public String getName() {
        return this.name() + " " + this.getDeclaringClass();
        }
        }
       
        enum MainCourse implements Food {
        LASAGNE, BURRITO, PAD_THAI, LENTILS, HUMMOUS, VINDALOO;
       
        @Override
        public String getName() {
        return this.name() + " " + this.getDeclaringClass();
        }
        }
       
        enum Dessert implements Food {
        TIRAMISU, GELATO, BLACK_FOREST_CAKE, FRUIT, CREME_CARAMEL;
       
        @Override
        public String getName() {
        return this.name() + " " + this.getDeclaringClass();
        }
        }
       
        enum Coffee implements Food {
        BLACK_COFFEE, DECAF_COFFEE, ESPRESSO, LATTE, CAPPUCCINO, TEA, HERB_TEA;
       
        @Override
        public String getName() {
        return this.name() + " " + this.getDeclaringClass();
        }
        }
       
        String getName();
       }
       package cn.demo2;
       
       import cn.demo2.Food.Appetizer;
       
       public class TypeOfFodd {
       
        public static void main(String[] args) {
        Food food = Appetizer.SALAD;
        eat(food);
        }
       
        public static void eat(Food food) {
        System.out.println("eat " + food.toString().toLowerCase());
        System.out.println(food.getName());
        }
       }
    • 例子:菜单

       package cn.demo3;
       
       public enum Meal {
        APPETIZER(Food.Appetizer.class),
        MAINCOURSE(Food.MainCourse.class),
        DESSERT(Food.Dessert.class),
        COFFEE(Food.Coffee.class)
        ;
       
        private Food[] values;
       
        private Meal(Class<? extends Food> kind) {
        values = kind.getEnumConstants();
        }
       
        public Food[] getValues() {
        return values;
        }
       
        public interface Food {
        enum Appetizer implements Food {
        SALAD, SOUP, SPRING_ROLLS;
        }
       
        enum MainCourse implements Food {
        LASAGNE, BURRITO, PAD_THAI, LENTILS, HUMMOUS, VINDALOO;
        }
       
        enum Dessert implements Food {
        TIRAMISU, GELATO, BLACK_FOREST_CAKE, FRUIT, CREME_CARAMEL;
        }
       
        enum Coffee implements Food {
        BLACK_COFFEE, DECAF_COFFEE, ESPRESSO, LATTE, CAPPUCCINO, TEA, HERB_TEA;
        }
        }
       
       }

    switch

    • switch的条件参数类型:整型、字符型、枚举型、字符串(1.7以后)

     package cn.demo3;
     
     enum Color {
      GREEN, RED, BLUE
     }
     
     public class EnumDemo4 {
      public static void printName(Color color) {
      switch (color) {
      case BLUE:
      System.out.println("蓝色");
      break;
      case RED:
      System.out.println("红色");
      break;
      case GREEN:
      System.out.println("绿色");
      break;
      }
      }
     
      public static void main(String[] args) {
      printName(Color.BLUE);
      printName(Color.GREEN);
      }
     
     /*
      * Console Output:
     蓝色
     绿色
      */
     }

    单例模式

    • 单例模式:确保某个类只有一个实例,自行实例化并向整个系统提供这个实例

    • 线程池、缓存、日志对象、对话框对象常被设计成单例

    • 选择单例模式是为了避免出现不一致的状态

    饿汉式单例模式

    • 无法做到延迟创建对象

    • 如果该单例类涉及资源较多,创建比较消耗时间,则希望它能够尽可能地延迟加载,从而减小初始化的负载

     package cn.demo4;
     
     public class SingletonHungry {
      private static SingletonHungry instance = new SingletonHungry();
     
      private SingletonHungry() {
      }
     
      public static SingletonHungry getInstance() {
      return instance;
      }
     }

    懒汉单例模式

    • 如果该单例类涉及资源较多,创建比较消耗时间,则希望它能够尽可能地延迟加载,从而减小初始化的负载

     package cn.demo4;
     
     public class SingletonLazy {
      private static volatile SingletonLazy instance;
     
      private SingletonLazy() {
     
      }
     
      public static synchronized SingletonLazy getInstance() {
      if (instance == null) {
      instance  = new SingletonLazy();
      }
     
      return instance;
      }
     }
    • 懒汉单例模式能够在多线程中很好地工作,避免同步问题,同时也具备Lazy loading机制

    • 但效率不高,为了提升效率,代码改进如下:

    package cn.demo4;
    
    /* 双重检查锁 */
    public class SingletonLazy {
    	private static volatile SingletonLazy instance;
    	
    	private SingletonLazy() {
    	}
    	
    	public static SingletonLazy getInstance() {
    		if (instance == null) {
    			synchronized (SingletonLazy.class) {
    				if (instance == null) {
    					instance = new SingletonLazy();
    				}
    			}
    		}
    		
    		return instance;
    	}
    }
    • 毕竟在单例中new的情况非常少

    • volatile关键字

      • 第一层语义 => 可见性

        • 在一个线程中对该变量的修改会马上由工作内存(Work Memory)写回主内存(Main Memory),故其它线程会马上读取到已修改的值

          • 工作内存 => 高速缓存 => 线程独享

          • 主内存 => 主存 => 线程共享

      • 第二次语义 => 禁止指令重排序优化

        • 我们写的代码(尤其是多线程代码),由于编译器优化,在实际执行的时候可能与我们编写的顺序不同

        • 编译器只保证程序执行结果与源代码相同,却不保证实际指令的顺序与源代码相同

        • 单线程中指令重排优化不会有什么问题,但是多线程中可能引发严重问题

    静态内部类单例模式

    package cn.demo4;
    
    public class SingletonInner {
    	private static class Holder {
    		private static SingletonInner singleton = new SingletonInner();
    	}
    	
    	private SingletonInner() {}
    	
    	public static SingletonInner getSingleton() {
    		return Holder.singleton;
    	}
    }
    • 可以避免静态实例在SingletonInner类的加载阶段就创建对象; 静态变量初始化是在SingletonInner类初始化时触发的

    • 由于静态内部类只会被加载一次,所以这种写法是线程安全的

    序列化的解决方案

    package demo;
    
    public class Singleton implements java.io.Serializable {
        public static Singleton INSTANCE = new Singleton();
        
        private static volatile boolean flag = true;
        
        private Singleton() {
            if (flag) {
                flag = false;
            } else {
                throw new RuntimeException("The instance already exists!");
            }
        }
    }

    枚举单例

    package cn.demo4;
    
    public enum SingletonEnum {
    	INSTANCE;
    	
    	private String name;
    	public String getName() {
    		return name;
    	}
    	public void setName(String name) {
    		this.name = name;
    	}
    }

    EnumMap

    基本用法

     package cn.demo5;
     
     import java.util.ArrayList;
     import java.util.EnumMap;
     import java.util.HashMap;
     import java.util.List;
     import java.util.Map;
     
     public class EnumMapDemo {
      public static void main(String[] args) {
      List<Clothes> list = new ArrayList<>();
      list.add(new Clothes("C001", Color.BLUE));
      list.add(new Clothes("C002", Color.RED));
      list.add(new Clothes("C003", Color.GREEN));
      list.add(new Clothes("C004", Color.YELLOW));
      list.add(new Clothes("C005", Color.YELLOW));
      list.add(new Clothes("C006", Color.RED));
      list.add(new Clothes("C007", Color.RED));
     
      // 方案一
      Map<String, Integer> map = new HashMap<>();
      for (Clothes clothes: list) {
      String colorName = clothes.getColor().name();
      Integer count = map.get(colorName);
      if (count != null) {
      map.put(colorName, count + 1);
      } else {
      map.put(colorName, 1);
      }
      }
      System.out.println(map.toString());
     
      // 方案二
      Map<Color, Integer> enumMap = new EnumMap<>(Color.class);
      for (Clothes clothes: list) {
      Color color = clothes.getColor();
      Integer count = enumMap.get(color);
      if (count != null) {
      enumMap.put(color, count + 1);
      } else {
      enumMap.put(color, 1);
      }
      }
      System.out.println(enumMap.toString());
      }
     }
     
     enum Color {
      BLUE,
      YELLOW,
      RED,
      GREEN;
     }
    • EnumMap是枚举专属的集合

    • key必须为Enum类型,不能为null

    • 避免了获取name的步骤

    • EnumMap效率更高,其内部是用数组实现,所以是一段连续的内存空间,根据程序局部性原理,效率会非常高

    • 构造函数:

      • EnumMap(Class<K> keyType) => 创建一个有指定键类型的空枚举映射

      • EnumMap(EnumMap<K, ? entends V> m) => 创建一个键类型与指定枚举映射相同的枚举类型,最初包含相同的映射关系(如果有的话)

      • EnumMap(Map<K, ? extends V> m) => 创建一个枚举映射,从指定映射对齐初始化

    • 和普通的HashMap不同,需要向它传递一个类型信息 => 即Class对象

      • 通过这个参数EnumMap就可以根据类型信息初始化其内部数据结构

      • 另外两个只是初始化时传入一个Map集合

    Map<Color, Integer> enumMap = new EnumMap<>(Color.class);
    
    Map<Color, Integer> enumMap2 = new EnumMap<>(enumMap);
    
    Map<Color, Integer> hashMap = new HashMap<>();
    hashMap.put(Color.GREEN, 2);
    hashMap.put(Color.YELLOW, 1);
    Map<Color, Integer> enumMap3 = new EnumMap<>(hashMap);

    EnumMap实现原理

    内部存储结构

    • 数据结构和构造函数:

       public class EnumMap<K extends Enum<K>, V> extends AbstractMap<K, V>
           implements java.io.Serializable, Cloneable
       {
           //Class对象引用
           private final Class<K> keyType;
       
           //存储Key值的数组
           private transient K[] keyUniverse;
       
           //存储Value值的数组
           private transient Object[] vals;
       
           //map的size
           private transient int size = 0;
       
           //空map
           private static final Enum<?>[] ZERO_LENGTH_ENUM_ARRAY = new Enum<?>[0];
       
           //构造函数
           public EnumMap(Class<K> keyType) {
               this.keyType = keyType;
               keyUniverse = getKeyUniverse(keyType);
               vals = new Object[keyUniverse.length];
          }
       }
    • 内部有两个数组,长度相同

      • 一个表示所有可能的键(枚举值)

      • 一个表示对应的值

    • 不允许key为null,但允许value为null

    • 键都有一个对应的索引,根据索引直接访问和操作其键数组和值数组,由于操作都是数组,因此效率很高。

    put的实现

    public V put(K key, V value) {
    	typeCheck(key);//检测key的类型
    	//获取存放value值得数组下标
    	int index = key.ordinal();
    	//获取旧值
    	Object oldValue = vals[index];
    	//设置value值
    	vals[index] = maskNull(value);
    	if (oldValue == null)
    		size++;
    	return unmaskNull(oldValue);//返回旧值
    }
    private void typeCheck(K key) {
       Class<?> keyClass = key.getClass();//获取类型信息
       if (keyClass != keyType && keyClass.getSuperclass() != keyType)
           throw new ClassCastException(keyClass + " != " + keyType);
    }
    • 通过int index = key.ordinal()的方式获取到该枚举实例的顺序值,利用此值作为下标,把值存储在vals数组对应下标的元素中即vals[index]

    • maskNull方法和unmaskNull方法正是用于null的包装和解包装的

      //代表NULL值得空对象实例
      private static final Object NULL = new Object() {
      	public int hashCode() {
      		return 0;
      	}
      
      	public String toString() {
      		return "java.util.EnumMap.NULL";
      	}
      };
      
      private Object maskNull(Object value) {
      	//如果值为空,返回NULL对象,否则返回value
      	return (value == null ? NULL : value);
      }
      
      @SuppressWarnings("unchecked")
      private V unmaskNull(Object value) {
      	//将NULL对象转换为null值
      	return (V)(value == NULL ? null : value);
      }

    get的实现

    public V get(Object key) {
    	return (isValidKey(key) ? unmaskNull(vals[((Enum<?>) key).ordinal()]) : null);
    }
    
    // 对Key值的有效性和类型信息进行判断
    private boolean isValidKey(Object key) {
    	if (key == null)
    		return false;
    
    	// Cheaper than instanceof Enum followed by getDeclaringClass
    	Class<?> keyClass = key.getClass();
    	return keyClass == keyType || keyClass.getSuperclass() == keyType;
    }

    remove的实现

    public V remove(Object key) {
    	//判断key值是否有效
    	if (!isValidKey(key))
    		return null;
    	//直接获取索引
    	int index = ((Enum<?>)key).ordinal();
    
    	Object oldValue = vals[index];
    	//对应下标元素值设置为null
    	vals[index] = null;
    	if (oldValue != null)
    		size--;//减size
    	return unmaskNull(oldValue);
    }

    查找的实现

    // 判断是否包含某value
    public boolean containsValue(Object value) {
        value = maskNull(value);
        //遍历数组实现
        for (Object val : vals)
            if (value.equals(val))
                return true;
    
        return false;
    }
    // 判断是否包含key
    public boolean containsKey(Object key) {
        return isValidKey(key) && vals[((Enum<?>)key).ordinal()] != null;
    }

    EnumSet

    基本用法

    • 创建EnumSet并不能使用new关键字,因为它是个抽象类,而应该使用其提供的静态工厂方法

     // 创建一个具有指定元素类型的空EnumSet。
     EnumSet<E>  noneOf(Class<E> elementType)      
     // 创建一个指定元素类型并包含所有枚举值的EnumSet
     <E extends Enum<E>> EnumSet<E> allOf(Class<E> elementType)
     // 创建一个包括枚举值中指定范围元素的EnumSet
     <E extends Enum<E>> EnumSet<E> range(E from, E to)
     // 初始集合包括指定集合的补集
     <E extends Enum<E>> EnumSet<E> complementOf(EnumSet<E> s)
     // 创建一个包括参数中所有元素的EnumSet
     <E extends Enum<E>> EnumSet<E> of(E e)
     <E extends Enum<E>> EnumSet<E> of(E e1, E e2)
     <E extends Enum<E>> EnumSet<E> of(E e1, E e2, E e3)
     <E extends Enum<E>> EnumSet<E> of(E e1, E e2, E e3, E e4)
     <E extends Enum<E>> EnumSet<E> of(E e1, E e2, E e3, E e4, E e5)
     <E extends Enum<E>> EnumSet<E> of(E first, E... rest)
     //创建一个包含参数容器中的所有元素的EnumSet
     <E extends Enum<E>> EnumSet<E> copyOf(EnumSet<E> s)
     <E extends Enum<E>> EnumSet<E> copyOf(Collection<E> c)
     package cn.demo5;
     
     import java.util.ArrayList;
     import java.util.EnumSet;
     import java.util.List;
     
     public class EnumSetDemo {
      public static void main(String[] arges) {
      /* 空集合 */
      EnumSet<Color> enumSet = EnumSet.noneOf(Color.class);
     
      System.out.println("1. 空集合:" + enumSet.toString());
      enumSet.add(Color.GREEN);
      enumSet.add(Color.RED);
      enumSet.add(Color.YELLOW);
      System.out.println("   添加元素后:" + enumSet.toString());
      System.out.println("////////////////////////////////////// ");
     
      EnumSet<Color> enumSet1 = EnumSet.allOf(Color.class);
      System.out.println("2. addOf直接填充:" + enumSet1.toString());
      System.out.println("////////////////////////////////////// ");
     
      EnumSet<Color> enumSet2 = EnumSet.range(Color.BLUE, Color.RED);
      System.out.println("3. 指定初始化范围:" + enumSet2.toString());
      System.out.println("////////////////////////////////////// ");
     
      EnumSet<Color> enumSet3 = EnumSet.complementOf(enumSet2);
      System.out.println("4. 指定补集:" + enumSet3.toString());
      System.out.println("////////////////////////////////////// ");
     
      EnumSet<Color> enumSet4 = EnumSet.of(Color.BLUE);
      EnumSet<Color> enumSet5 = EnumSet.of(Color.BLUE, Color.RED);
      System.out.println("5. 初始化时直接指定元素,Color.BLUE:" + enumSet4.toString());
      System.out.println("   初始化时直接指定元素,Color.BLUE和Color.RED:" + enumSet5.toString());
      System.out.println("////////////////////////////////////// ");
     
      EnumSet<Color> enumSet6 = EnumSet.copyOf(enumSet5);
      System.out.println("6. EnumSet的copyOf:" + enumSet6);
      System.out.println("////////////////////////////////////// ");
     
      List<Color> list = new ArrayList<>();
      list.add(Color.BLUE);
      list.add(Color.BLUE);
      list.add(Color.RED);
      list.add(Color.GREEN);
      EnumSet<Color> enumSet7 = EnumSet.copyOf(list);
      System.out.println("7. List的copyOf:" + enumSet7);
      }
     }
     1. 空集合:[]
        添加元素后:[YELLOW, RED, GREEN]
     //////////////////////////////////////
     
     2. addOf直接填充:[BLUE, YELLOW, RED, GREEN]
     //////////////////////////////////////
     
     3. 指定初始化范围:[BLUE, YELLOW, RED]
     //////////////////////////////////////
     
     4. 指定补集:[GREEN]
     //////////////////////////////////////
     
     5. 初始化时直接指定元素,Color.BLUE:[BLUE]
        初始化时直接指定元素,Color.BLUE和Color.RED:[BLUE, RED]
     //////////////////////////////////////
     
     6. EnumSet的copyOf:[BLUE, RED]
     //////////////////////////////////////
     
     7. List的copyOf:[BLUE, RED, GREEN]
    • 所有在参数数据不多的情况下,强烈*不建议*使用传递参数为可变参数的of方法,即EnumSet of(E first, E... rest),因为效率比较低

  • 相关阅读:
    TCP 连接状态
    可视化垃圾回收算法
    flume-ng+Kafka+Storm+HDFS 实时系统搭建
    WeX5 IDE 手机移动开发+JAVA +大数据
    云计算高级运维工程师
    CentOS 5.8 上安装 systemtap-2.6
    SYSTEMTAP -ORACLE
    Apple激活日期查询
    Div 浮动到另一个div之上
    Python模块常用的几种安装方式
  • 原文地址:https://www.cnblogs.com/daheww/p/10654338.html
Copyright © 2011-2022 走看看