反射注解总结

news/2024/5/19 2:43:56 标签: java, 反射

目录

    • 反射
      • 概念
      • 应用场景
      • 反射常用API
      • 获取字节码对象的三种方式
      • 通过字节码对象获取其他对象
      • 获取类中方法的几种方式
      • 反射普通方法调用
      • 反射私有方法调用
      • 反射私有构造方法调用
      • Field用法
      • 总结
    • 注解
      • 注解引入
      • 系统内置注解
      • 元注解
      • 自定义注解
      • 自定义注解的属性类型
      • 使用注解
      • 注解功能拓展

反射

概念

反射java提供的一种机制,可以在类的运行时期动态的获取类中所有的信息(任意字段、构造方法,普通成员方法。。。。)

应用场景

缺点:会破坏封装性,损失性能。 尽量少用反射

安卓应用场景:安卓中一些私有的类通常是系统相关的比如调用系统硬件设备等类,设备管理器。开发需要,就只能通过反射去调用这些私有的方法

Java应用场景:解耦的。在开发中,做一个项目是很多人一起开发,a(用户登录注册相关) b(列表,加入购物车) c(订单结算) 三个程序员共同开发

反射常用API

1.java.lang.Class
2.java.lang.reflect.Constructor
3.java.lang.reflect.Method
4.java.lang.reflect.Field

获取字节码对象的三种方式

java">        //获取字节码对象的第一种方式:    类名.class*/
		Class clazz = User.class;
		//获取字节码对象的第二种方式:    Class.forName();   解耦合了  jdbc
	    Class clazz1 = Class.forName("cn.itsource.reflect.User");
		//获取字节码对象的第三种方式      对象.getClass()		 
		Class clazz2 = new User().getClass();

通过字节码对象获取其他对象

java">		//用字节码对象调用相关方法获取Field,Constructor,Method所有对象。(加s代表所有)
        Class clazz = User.class;
		Method[] ms = clazz.getMethods();
		Field[] fs = clazz.getFields();
		Constructor[] cs = clazz.getConstructors();

获取类中方法的几种方式

java">		Class clazz = User.class;
		Method[] ms = clazz.getMethods();    		//获取本类公有的方法和父类继承过来的方法
        Method[] ms2 = c2.getDeclaredMethods();   	//获取本类公有和私有的所有方法	
		//获取指定的方法   (不加s代表指定)(没有参数类型就不写)
        Method m = clazz.getMethod("method",int.class);  		//获取本类和父类指定公有方法
		Method m2 = clazz.getDeclaredMethod("method",int.class);//获取本类指定可以是私有方法

反射普通方法调用

java">		Class<User> clazz = User.class;
		//获取指定的方法,("方法名",参数类型.class)
		Method m = clazz.getMethod("method",int.class);
		User user = new User();
		//返回值表示调用方法本身的返回内容
		// obj :表示方法所属的对象 ,args:表示方法的实际参数。
		Object r = m.invoke(user, 10);
		System.out.println(r);

反射私有方法调用

private编译时期有效,反射是在运行时期

java">		Class clazz = User.class;
		Method m = clazz.getDeclaredMethod("methodPrivate");		//2.获取指定的方法
		m.setAccessible(true);										//暴力反射。破坏了封装,设置可以访问。
		//通过反射获取类的对象。但是private构造创建对象无效。需要先用反射去暴力获取私有构造方法再造对象
		Object newInstance = clazz.newInstance();	//底层反射。或者还用User user = new User();
		m.invoke(newInstance);

反射私有构造方法调用

java">		//获取Runtime构造器对象
		Constructor<Runtime> c = Runtime.class.getDeclaredConstructor();
		//设置可以访问
		c.setAccessible(true);
		//invoke --> newInstance 通过反射创建Runtime类对象
		Runtime newInstance = c.newInstance();
		System.out.println(newInstance);

		//通过单例模式创建对象
		Runtime runtime = Runtime.getRuntime();
		System.out.println(newInstance);

Field用法

java">		Field f = User.class.getDeclaredField("name");
		//设置可以访问
		f.setAccessible(true);
		User user = new User();
		f.set(user, "jack");
		System.out.println(f.get(user));
		System.out.println(user.getName());

总结

1.找到字节码对象
2.通过字节码对象找到具体对象(Method,Constructor,File)。
3.找具体要反射的方法
4.要反射的方法是私有的需要设置可以访问,setAccessible
5.调用,invoke,newInstance,set

注解

注解引入

使用注解语法:@注解名字
注解(annotation):用来标记代码的,简单理解就是一种标记,给代码看的.
注释:给程序员看的,用来说明解释代码.
作用:1.可以用来检验是否符合规定。2.使代码看起来简洁.清晰

系统内置注解

@Override - 检查该方法是否是重写方法。如果发现其父类,或者是引用的接口中并没有该方法时,会报编译错误。

java">	@Override
	public String toString() {
		// TODO Auto-generated method stub
		return super.toString();
	}

@Deprecated - 标记过时方法。如果使用该方法,会报编译警告。
有了这个标记的方法,表示该方法已经过时,但是还可以调用,不推荐使用它,因为有了新的方法去替代它。
jdk更新换代,会替换到以前过时的一些功能,升级了,旧的也不会删掉

java">	@Deprecated
	public static void test(){}

@SuppressWarnings - 指示编译器去忽略注解中声明的警告。

java">    //抑制黄色波浪线的警告.
    @SuppressWarnings({ "rawtypes", "unused" })
    ArrayList arrayList = new ArrayList();

从 Java 7 开始,额外添加了 3 个注解:
@SafeVarargs - Java 7 开始支持,忽略任何使用参数为泛型变量的方法或构造函数调用产生的警告。
@FunctionalInterface - Java 8 开始支持,标识一个匿名函数或函数式接口。
@Repeatable - Java 8 开始支持,标识某注解可以在同一个声明上使用多次

元注解

元注解:在自定义注解的时候,用来标记注解的注解。

@Documented 如果使用的注解中包含这个元注解,那么我们在生成文档api的时候,会有这个注解的描述
@Target 表示标记自定义注解可以用在什么地方
@Retention 标记自定义注解的生命周期 source class runtime
@Inherited 标记注解可以被继承.

自定义注解

java">/**
 * @author Administrator
 * @see 参考xxxx
 * @since 从jdk1.8
 * @version 1.0
 */
@Documented
public @interface 注解名字{
    
}

自定义注解的属性类型

java">/**
 * @author Administrator
 *自定义注解语法:
 * public @interface 注解名字{
 *    类型 属性名();
 *    //类型:8种,String,数组,枚举,其他注解类型.
 *    类型 属性名() default 值;
 * }
 */
@Documented
@Target(value={ElementType.TYPE,ElementType.PARAMETER})
@Inherited
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
    int a() ;
	String b() ;
	int[] c() ;
	TT  d();
}
java">@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Target {

    ElementType[] value();
}
java">public enum ElementType {
    /** Class, interface (including annotation type), or enum declaration */
    TYPE,

    /** Field declaration (includes enum constants) */
    FIELD,

    /** Method declaration */
    METHOD,

    /** Formal parameter declaration */
    PARAMETER,

    /** Constructor declaration */
    CONSTRUCTOR,

    /** Local variable declaration */
    LOCAL_VARIABLE,

    /** Annotation type declaration */
    ANNOTATION_TYPE,

    /** Package declaration */
    PACKAGE,

    /**Type parameter declaration */
    TYPE_PARAMETER,

    /**Use of a type */
    TYPE_USE
}

使用注解

java">@Documented
@Target(value={ElementType.TYPE,ElementType.PARAMETER})
@Inherited
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
	int a() default 1;
	String b() default "abc";
	String[] value() ;
//	TT  d();
}

1.如果一个注解中只有一个属性需要赋值,属性名字叫value,那么可以省略value,直接给对应类型的值.
2.如果属性是一个数组,赋值的时候,只有一个值,可以省略花括号{}

java">@MyAnnotation(value={"发发发"},a=2)
public class MyAnnotationTest2 {
	@TT
	public static void test(){
		System.out.println("test......");
	}
}

注解功能拓展

1.找到类的字节码对象
2.找到有哪些方法
3.通过方法对象找到哪个方法上有注解
4.执行某方法

java">public class DemoTT {

	public static void main(String[] args) throws Exception {
		//获取类上的注解
	/*	Annotation[] as = MyAnnotationTest2.class.getAnnotations();
		for (Annotation annotation : as) {
			System.out.println(annotation);
		}														*/
        
		System.out.println("-------------");
		//获取指定类的所有方法.
		Method[] ms = MyAnnotationTest2.class.getDeclaredMethods();
		for (Method m : ms) {
			//获取方法上面的TT注解对象
			TT tt = m.getAnnotation(TT.class);
			//判断有TT注解对象的方法
			if (tt instanceof TT) {
				//调用有TT注解对象的方法.
				m.invoke(new MyAnnotationTest2());
			}
		}
	}
}
java">@MyAnnotation(value={"发发发"},a=1)
public class MyAnnotationTest2 {
	@TT
	public static void test(){
		System.out.println("test......");
	}
	@TT
	public static void test2(){
		System.out.println("test2......");
	}
	public static void test3(){
		System.out.println("test3......");
	}
}

http://www.niftyadmin.cn/n/274223.html

相关文章

网络安全真的没法入行吗?

网络安全的前景如何&#xff0c;其实大家都知道&#xff0c;但是入行很大程度还是兴趣。 “兴趣是最好的老师”这句话并不泛泛&#xff0c;但捕捉和保护孩子兴趣的那个人更为重要。作为一个学习者的心思很多时候稍纵即逝&#xff0c;也不稳定。能把一种兴趣稳定下来并变成了解…

STM32物联网实战开发(2)——回调函数

在第一篇博客中提到了全新的程序框架&#xff0c;我们会大量的使用回调函数&#xff0c;其中包括枚举类型、结构体、函数指针的应用。 回调函数&#xff1a;就是一个通过函数指针调用的函数。如果你把函数的地址传递给中间函数的形参&#xff0c;中间函数通过函数指针调用其所…

2023/04/24 ~ 25 刷题记录

A - Sort the Subarray 大致题义&#xff1a;Monocarp有一个包含n个整数的数组a。他决定选择两个整数l和r&#xff0c;使1< 2rn&#xff0c;然后对子数组进行排序。子数组a[1 ..]R]是数组a中包含元素a1, al1, al2&#xff0c;…的部分。&#xff0c; ar-1, ar)按非降序排列。…

DNS 查询原理详解

DNS&#xff08;Domain Name System&#xff09;是互联网上的一种命名系统&#xff0c;它将域名转换为IP地址。在进行DNS查询时&#xff0c;先要明确需要查询的主机名&#xff0c;然后向本地DNS服务器发出查询请求。 1. 本地DNS服务器查询 当用户在浏览器中输入一个URL或者点…

双指针技巧总结

一、双指针技巧——情景1 通常&#xff0c;我们只需要一个指针进行迭代&#xff0c;即从数组中的第一个元素开始&#xff0c;最后一个元素结束。然而&#xff0c;有时我们会使用两个指针进行迭代。 双指针的典型场景 (1)从两端向中间迭代数组。 (2)一个指针从头部开始&#…

玩转ChatGPT提示词 持续更新·······

导语&#xff1a; 众所周知&#xff0c;在AI的世界里&#xff0c;提示词就是和AI沟通语言的桥梁&#xff0c;提示关键词常用于AI对话及AI绘画等相关场景&#xff0c;通过准确的使用关键词&#xff0c;你就能更好的让AI辅助自己的工作&#xff0c;其中的成分重要性不言而喻&…

【Python每日十题菜鸟版--第四天】

菜鸟网实例 &#x1f349;前言&#x1f349;1.列表常用方法列表的添加列表的删除列表的改和查格式转换推导式总结一波 2.计算n个输的立方和3.列表指定个数翻转4.列表头尾两个数对调5.列表指定元素对调6.翻转列表方法一&#xff1a;切片使用reverse方法其他方法 &#x1f349; 7…

阿里测试8年,肝到P8只剩他了····

在阿里工作了8年&#xff0c;工作压力大&#xff0c;节奏快&#xff0c;但是从技术上确实得到了成长&#xff0c;尤其是当你维护与大促相关的系统的时候&#xff0c;熬到P7也费了不少心思&#xff0c;小编也是个爱学习的人&#xff0c;把这几年的工作经验整理成了一份完整的笔记…