注解
注解(Annotation) 可以被其他程序(如:编译器)读取
可通过反射机制编程实现对这些元数据的访问
注解都定义在 java.lang.* 下
@Verride //重写的注解
@Deprecated // 已过时的,表示不鼓励程序员使用这样的元素(很危险或有更好的选择)
@SuppressWarnings // 镇压警告@SuppressWarnings("all") // 镇压所有的警告
元注解
元注解作用是负责注解其他注解
@Target // 用于描述注解的使用范围(被描述的注解可用于什么地方)
@Retention //表示需要在什么级别保存该注释信息(SOURCE < CLASS < RUNTIME)
@Document // 说明该注释将被包含在javadoc 中
@Inherited // 说明子类可以继承父类中的该注解
反射(Reflection)
反射:加载类,允许以编程的方式拿出类中各种成分(成员变量、方法、构造器等)
1、 反射第一步:加载类,获取类的字节码:Class 对象
2、 获取类的构造器 : Constructor 对象
3、 获取类的成员变量:Field 对象
4、 获取类的成员方法:Method 对象获取Class 对象的三种方法Class c1 = 类名.class调用Class 提供的方法 : public static Class forName(String package);Object提供的方法: public Class getClass(); Class c3 = 对象.getClass();
获取反射的字节码文件
Class c1 = 类名.class
c1.getName(); // 返回此字节码类的全类名
c1.getSimpleName(); // 返回字节码类的简名字:类名Class c2 = Class.forName("com.whoami.Test");
System.out.print(c1 == c2); // 两种方法拿到的为同一个class 文件Test t = new Test();
Class c3 = t.getClass();
System.out.print(c3 == c2); //三种方法拿到的为同一个class 文件
获取反射的类中构造器
作用:依然是初始化对象返回
Class c = Test.class // 获取类的字节码文件
Constructor[] constructors = c.getConstructors(); // 通过字节码文件获取到类的所有构造器(只能获取public修饰的构造器)c.getDeclaredConstructors(); // 获取类中所有的构造器c.getConstructor(); // 获取单个构造器(只有public 修饰)c.getDeclaredConstructor(); // 获取单个构造器c.getConstructor(String.class,int.class); // 匹配有参构造器
for(Constructor construcotr : constructors){constructor.getName // 获取构造器名字constructor.getParameterCount(); // 获取构造器参数
}
constructor1.newInstance(); // 调用构造器对象表示的构造器,并传入参数,完成初始化
constuctor1.setAccessible(true); // 禁止检查访问权限,即此反射构造器可调用私有属性
获取类的成员变量
作用:依然是赋值、取值
1、 反射第一步:必须是先得到类的Class 对象Class c = Cat.class;
2、 获取类的全部成员变量Field[] fields = c.getDeclaredFields(); // 获取类的全部成员变量c.getFields(); // 获取类的全部成员变量(只获取public 的)Field fName = c.getField("变量名"); // 获取某个成员变量(只能获取public 的) c.getDeclaredField("变量名"); // 获取某个成员变量for (Field field : fields){field.getName() ; // 获取变量名firld.getType(); // 获取变量类型}
1、取值、赋值Class c = Test01.class;Test01 test01 = new Test01();Field fName = c.getDeclaredField("name")
//赋值Test01 test01 = new Test01();fName.setAccessible(true); // 禁止访问控制权限,暴力反射fName.set(test01,"咖啡猫"); // 赋予test对象(即Test01类)成员变量值//取值String name = (String) fNmae.get(test01); // 取出类中的fName的变量名的属性值
获取类的成员方法
作用:依然是执行
Class c = Test01.class;
Method[] methods = c.getDeclaredMethods(); // 获取类的全部成员方法c.getMethods(); // 获取类的全部成员方法(只有public 修饰)c.getMethod("run",param); // 获取某个成员方法(run方法+参数匹配) (只有public 修饰)c.getDeclareMethod("run",param); // 获取某个成员方法(run方法+参数匹配)
Class c = Test01.class;
Test01 test01 = new Test01();
run.setAccessible(true); // 暴力强转
Object result = run.invoke(test01,param); // 触发某个对象中的方法执行(返回值为Object,返回值可指定)
反射的作用
基本作用 :可以得到一个类的全部成分然后操作
可以破坏封装性
最重要的用途:适合做Java 的框架,基本上,主流的框架都会基于反射设计出一些通用的功能
注解
让其他程序根据注解信息来决定怎么执行该程序
自定义注解
public @interface 注解名称{public 属性类型 属性名() default 默认值;
}// 例
public @interface MyTest1{String aaa();boolean bbb() default true;Stringp[] ccc();
}特殊属性名:value如果注解中只有一个value 属性,使用注解时,value名称可以不写
注解的本质是一个接口,Java中的所有注解都是继承了Annotation 接口
@注解(...): 其本质就是一个实现类对象
元注解
修饰注解的注解
@Target // 作用:声明被修饰的注解只能在哪些位置使用@Target(ElementType.TYPE)1. TYPE, 类,接口2. FIELD, 成员变量3. METHOD, 成员方法4. PARAMETER, 方法参数5. CONSTRUCTOR, 构造器6. LOCAL_VARLABLE,局部变量@Retention // 作用:声明注解的保留周期@Retention(RetentionPolicy.RUNTIME)1.SOUCE // 只作用于源码阶段,字节码文件中不存在2.CLASS (默认值) // 保留到字节码文件阶段,运行阶段不存在3.RUNTIM(开发常用) // 一直保留到运行阶段
注解的解析
判断类上、方法上、成员变量上是否存在注解,并把注解里的内容解析出来
指导思想:要解析谁上面的注解,就应该先拿到谁
Class c = Demo.class; // 声明取出class 类的反射字节
Method m = c.getDeclaredMethod("test1") // 从反射的class 对象中获得成员方法
if(m.isAnnotationPresent(MyTest.class)){ // isAnnotationPresent(),判断此类/方法/变量是否存在指定的注解,返回boolenMyTest4 mytest4 = (MyTest4) m.getDeclaredAnnotation(MyTest.class); // 指定注解并取出,返回值为Annotation 类m.getDeclareAnnotations() // 获取当前对象上面的注解mytest4.value();mytest4.aaa();mytest4.bbb();
}
注解的应用场景
package zhujie;import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;public class AnnotationTest3 {@MYTestpublic void test1(){System.out.println("test1");}@MYTestpublic void test2(){System.out.println("test2");}@MYTestpublic void test3(){System.out.println("test3");}@MYTestpublic void test4(){System.out.println("test4");}public static void main(String[] args) throws Exception{AnnotationTest3 annotation = new AnnotationTest3(); // new 对象,用于invoke 执行方法时使用到Class c = AnnotationTest3.class; // 利用反射定义class 对象为当前类Method[] methods=c.getDeclaredMethods(); // 利用当前类的class 对象取出所有的方法for (Method method : methods) { // 对于所有的方法进行循环if(method.isAnnotationPresent(MYTest.class)){ // 对于循环的每一个反射的方法进行判断,判断是否存在MYTest 注解method.invoke(annotation); // 若存在则进行invoke 执行该函数}}}}