注解与反射

注解

注解(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 执行该函数
            }
        }
    }

}

posted @ 2025-10-25 11:14  QZ不是crazy  阅读(9)  评论(0)    收藏  举报