注解与反射
注解
注解(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(),判断此类/方法/变量是否存在指定的注解,返回boolen
MyTest4 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 {
@MYTest
public void test1(){
System.out.println("test1");
}
@MYTest
public void test2(){
System.out.println("test2");
}
@MYTest
public void test3(){
System.out.println("test3");
}
@MYTest
public 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 执行该函数
}
}
}
}

浙公网安备 33010602011771号