1 枚举
1.1 实现,而非继承
所有的enum都继承自java.lang.Enum类,由于Java不支持多重继承,所以enum不能再继承其他类。
然后,在创建一个新的enum时,可以同时实现一个或多个接口:
public class EnumTest {
interface Car {
void driver();
}
enum Audi implements Car {
A4 {
@Override
public void driver() {
System.out.println("A4");
}
},
A6 {
@Override
public void driver() {
System.out.println("A6");
}
},
A8 {
@Override
public void driver() {
System.out.println("A8");
}
};
}
@Test
public void test01() {
for (Audi audi : Audi.values()) audi.driver();
}
}
1.2 EnumSet
其存储结构elements 并未直接存枚举本身,而是位标志。long(64位)类型。
1.2.1 位向量
是有一些二进制位组成的向量。可以用很少的内存来存储变量。
例如 a=[01101001],从右边数起,第0、3、5、6位是1,所以就表示0,3,5,6这四个数。所以a表示为{0,3,5,6}。
使用一个大数组,其需要存储0-1000(N)的值,若数组类型类型为int(java中int类型通常占4个字节,一个字节是8位)。则数组定义为int a[N/32+1]。
显然,a[0]可以表示0~31的整数。
1.2.2 源码分析
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);
} //创建一个空的EnumSet
根据传入的枚举类型判断组成长度。
RegularEnumSet
private long elements = 0L; //存储枚举值
public boolean add(E e) {
typeCheck(e);
long oldElements = elements;
elements |= (1L << ((Enum<?>)e).ordinal());
return elements != oldElements;
} //往set添加枚举
public boolean remove(Object e) {
if (e == null)
return false;
Class<?> eClass = e.getClass();
if (eClass != elementType && eClass.getSuperclass() != elementType)
return false;
long oldElements = elements;
elements &= ~(1L << ((Enum<?>)e).ordinal());
return elements != oldElements;
} //从set中删除枚举
public boolean contains(Object e) {
if (e == null)
return false;
Class<?> eClass = e.getClass();
if (eClass != elementType && eClass.getSuperclass() != elementType)
return false;
return (elements & (1L << ((Enum<?>)e).ordinal())) != 0;
} //在set中是否存在该枚举
public int size() {
return Long.bitCount(elements);
} //set中包含的枚举数量 Long.bitCount方法返回有多少个1
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;
} //添加枚举
1.3 EnumMap
是一种特殊的Map,它要求其中的键(key)必须来自一个enum。
1.4 常量相关的方法
为enum定义一个或多个abstract方法,然后为每个enum实例实现该抽象方法。
public class EnumTest2 {
enum People {
Student {
@Override
void speak() {
System.out.println("学生");
}
},
Teacher {
@Override
void speak() {
System.out.println("老师");
}
};
abstract void speak();
}
}
2 注解
2.1 基本语法
2.1.1 定义注解
@Target(ElementType.METHOD) // 元数据,定义注解将应用于哪里
@Retention(RetentionPolicy.RUNTIME) // 元数据,定义注解在哪个级别可用
public @interface UseCase {
int id(); // 用来表示某些值,当分析注解时,程序可利用这些值
String description() default "没有描述"; //可指定默认值
}
2.1.2 元注解
@Target | 表示该注解可以用于什么地方 |
@Retention | 表示需要在什么级别保存该注解信息 |
@Documented | 将此注解包含在Javadoc中 |
@Inherited | 允许子类继承父类中的注解 |
元注解专职负责注解其他的注解
2.2 编写注解处理器
注解不支持继承。
2.2.1 注解元素
注解元素可以的类型有:所有基本类型(int,float,boolean等)、String、Class、enum、Annotation及这些类型的数组。
对于非基本类型的元素,无论是在源代码中声明时,或是在注解接口中定义默认值时,都不能以null作为其值。
2.2.2 实现处理器
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Constraints {
boolean primaryKey() default false;
boolean allowNull() default true;
boolean unique() default false;
}
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface SQLString {
int value() default 0;
String name() default "";
Constraints constraints() default @Constraints;
}
public class Student {
@SQLString(15)
private String name;
@SQLString(name = "username")
private String username;
@SQLString(constraints = @Constraints(unique = true))
private String address;
public static void main(String[] args) {
Class<Student> studentClass = Student.class;
for (Field field: studentClass.getDeclaredFields()) {
Annotation[] annotations = field.getDeclaredAnnotations();
System.out.print(field.getName() + ":");
for (Annotation annotation: annotations) {
if (annotation instanceof SQLString) {
SQLString sqlString = (SQLString) annotation;
System.out.print("value:" + sqlString.value() + "; ");
System.out.print("name:" + sqlString.name() + "; ");
System.out.print("constraints:" + sqlString.constraints() + "; ");
}
}
System.out.println();
}
}
}
// 输出
//name:value:15; name:; constraints:@study01.Constraints(allowNull=true, unique=false, primaryKey=false);
//username:value:0; name:username; constraints:@study01.Constraints(allowNull=true, unique=false, primaryKey=false);
//address:value:0; name:; constraints:@study01.Constraints(allowNull=true, unique=true, primaryKey=false);