Java 枚举
什么是枚举
概念
enumeration,JDK1.5引入的新特性,在 Java 中被 enum 关键字修饰的类型就是枚举类型。如果枚举不添加任何方法,枚举值默认为从0开始的有序数值。
枚举的作用
统一管理常量
应用场景
错误码、状态机等等
枚举的特性
除了不能继承,基本上可以将其看作一个常规类
Java 注解
什么是注解
注解的作用:
- 不是程序本身,对程序作出解释
- 可以被其他程序读取
注解的格式:
- 注解是以"@注释名"在代码中存在的,还可以添加一些参数值。
使用注解的场景
- 附加在 package,class,method,field 上面,相当于给它们添加了额外的辅助信息,可以通过反射机制实现堆这些元数据的访问
内置注解
@Override:定义在 java.lang.Object 中,此注释只适用于方法,表示一个方法声明打算重写超类中的另一个方法声明。
@Deprecated:定义在 java.lang.Deprecated 中,可以用于修饰方法,属性,类表示不鼓励使用这些元素,通常是因为它们很危险或者有更好的选择。
@SuppressWarnings:定义在 java.lang.SuppressWarnings 中,用于抑制编译时的警告信息。
@SafeVarargs:忽略任何使用参数为泛型变量的方法或者构造函数调用产生的警告
@FunctionalInterface:标识一个匿名函数或者函数式接口
@Repeatable:标识某注解可以在同一个声明上使用多次
注解的本质
就是一个 Annotation 接口的子接口,解释了为何成员变量有括号。
注解的属性类型
注解属性类型可以有以下列出的类型
1.基本数据类型
2.String
3.枚举类型
4.注解类型
5.Class类型
6.以上类型的一维数组类型
注解成员变量赋值
(name = "", name1 = "")
获取注解属性
- 通过反射的方式获取注解的助兴
元注解
- 元注解的作用就是负责注解其他注解,Java 定义了4个标准的 meta-annotation 类型,它们被用来提供对其他 annotation 类型做说明。
- 这些类型和它们所支持的类在 java.lang.annotation 包中可以找到
- Target:用于描述注解的使用范围
- ElementType 作用域
- Retention:表示需要在什么级别保存该注释信息,用于描述注解的生命周期(SOURCE写入源代码 < CLASS编入字节码文件 < RUNTIME运行时保留,通过反射得到)
- RententionPolicy
- Document:说明该注解被包含在 javadoc ,用户文档中
- Inherited:被该注解修饰的注解修饰了一个父类,如果它的子类没有被其他注解修饰,则它的子类也继承父类的注解
- Target:用于描述注解的使用范围
反射机制
反射的作用
从一个对象,获取到其类的所有信息
反射的优点与缺点
- 优点
- 实现动态创建对象和编译
- 缺点
- 影响执行性能
反射的主要 API
java.lang.Class
java.lang.reflect.Method
java.lang.reflect.Field
java.lang.reflect.Constructor
Class 类
Object 类中定义了以下的方法,此方法将被所有子类继承
public final Class getClass();
该方法可以通过对象获取到类的名称。
在 JRE 中都保留一个不变的 Class 类型的对象,无论有多少个对象,这个 Class 类型的对象始终只有一个。
- Class 对象只能由系统建立
- 一个加载的类在 JVM 中只会有一个 Class 实例
- 一个 Class 对象对应一个.class 文件
- 每个类实例会保留自己由那个 Class 实例生成的信息
- 通过 Class 可以完成的得到一个类中所有被加载的结构
- Class 类是 Relection 的根源,想要反射就必须先获得 Class 对象
常用方法
获取 Class 类的实例
- Class a = Cat.class; 已知具体的类,通过 class 属性获取,该方法最为安全可靠,程序性能最高
- Class a = cat.getClass(); 已知某个类的实例,调用实例的 getClass()方法获取 Class 对象
- Class a = Class.forName(); 已知一个类的类全名,且该类在类路径下,可以通过 Class 类的静态方法 forName()获取。
- 基础数据类型可以直接使用 类名.Type 的方式获得 Class 对象
哪些类型可以有 Class 对象
通过反射获取运行时类的完整结构
获取 field、method、constructor、superclass、interface、annotation
- 首先获取 Class 对象
- 通过 class 对象调用对应的属性,以及通过方法名获取方法并调用方法
- 演示代码
Cat cat = new Cat();
Class<? extends Cat> aClass2 = cat.getClass();
Class<Cat> aClass1 = Cat.class;
Class aClass = Class.forName("g.Cat");
Field[] fields1 = aClass.getFields(); //获取公共属性,以及父类公共属性
for(Field f: fields1) {
System.out.println(f);
}
Field[] fields2 = aClass.getDeclaredFields(); //获取本来中所有的属性
for(Field f: fields2) {
System.out.println(f);
}
aClass.getMethod("setName",String.class).invoke(cat, "花花");
System.out.println(cat.getName());
其他获取方式与属性类似 ......
setAccessible
- Method 和 Field、Constructor 对象都有 setAccessible()方法。
- 作用是启动和禁用安全检查开关
- true 是关闭安全检查
反射操作泛型
- Java 采用泛型擦除的机制来引入泛型,Java 中的泛型仅仅是给编译器使用,确保数据的安全性和免去强制类型转换的问题,一旦编译完成,所有与泛型有关的类型全部擦除。
- 为了通过反射操作这些类型,Java 新增了 ParameterizedType、GenericArrayType、TypeVariable 和 WildcardType 几种类型来代表不能被归一到 Class 类中的类型,但是又和原始类型齐名的类型
- ParameterizedType:标识一种参数化类型如 Map<String,Integer>(参数化类型)
- GenericArrayType:标识一种元素类型是参数化类型或者类型变量的数组类型(泛型数组类型)
- TypeVariable:是各种类型变量的公共父接口
- WildcardType:代表一种通配符类型表达式
操作步骤
- 获取参数列表
- 判断参数列表是否为参数化类型
- 将泛型类型强制转化为参数化类型并获取真实类型 演示
public void test1(Map<String, Integer> m, List<Cat> l) {
System.out.println("test1");
}
public List<Cat> test2() {
System.out.println("test2");
return null;
}
public static void main(String[] args) throws IllegalAccessException, InstantiationException, NoSuchMethodException {
Class<Test2> aClass = Test2.class;
Method test1 = aClass.getMethod("test1", Map.class, List.class);
Type[] genericParameterTypes = test1.getGenericParameterTypes();
for (Type genericParameterType : genericParameterTypes) {
System.out.println(genericParameterType);
if (genericParameterType instanceof ParameterizedType) {
Type[] actualTypeArguments = ((ParameterizedType) genericParameterType).getActualTypeArguments();
for (Type actualTypeArgument : actualTypeArguments) {
System.out.println(actualTypeArgument);
}
}
}
Method test2 = aClass.getMethod("test2");
Type genericReturnType = test2.getGenericReturnType();
System.out.println(genericReturnType);
if(genericReturnType instanceof ParameterizedType) {
Type[] actualTypeArguments = ((ParameterizedType) genericReturnType).getActualTypeArguments();
for (Type actualTypeArgument : actualTypeArguments) {
System.out.println(actualTypeArgument);
}
}
}
反射操作注解
演示
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface GField {
String value();
String id();
String length();
}
public class Cat {
@GField(id = "1",value = "小小", length = "2")
private String name;
@GField(id = "2",value = "12", length = "4")
public String age;
@GField(id = "3",value = "小明", length = "6")
public String Master;
}
public static void main(String[] args) throws NoSuchFieldException {
Class<Cat> catClass = Cat.class;
for (Field declaredField : catClass.getDeclaredFields()) {
System.out.println(declaredField.getAnnotation(GField.class).value());
System.out.println(declaredField.getAnnotation(GField.class).id());
System.out.println(declaredField.getAnnotation(GField.class).length());
}
}