java 获取所有带指定注解的类名_SXT DAY023 反射和注解

1. 反射机制介绍_Class对象获取

反射机制是 Java 的动态性之一

动态语言:在程序运行时,可以改变程序的结构或变量的 类型。

反射机制的常见作用

  1. 动态的加载类、动态的获取类的信息(属性,方法,构造 器)
  2. 动态构造对象
  3. 动态调用类和对象的任意方法、构造器
  4. 动态调用和处理属性
  5. 获取泛型信息
  6. 处理注解

java.lang.Class类 :表示正在运行的Java应用程序中的类和接口

获取Class对象的方式

  1. Class.forName(全限定类名);全限定类名==>包名+类名
  2. 类名.class
  3. 对象名.getClass()

练习代码

public class Test {
	public static void main(String[] args) {
		//获取Class对象
		try {
			//方法1:Class.forName("包名+类名")
			Class clazz=Class.forName("com.sxt.reflect.User");
			//方法2:类名.clazz
//			Class clazz=User.class;
			//方法3:通过调用 对象名.getClass()方法获取该类的Class信息
//			User user=new User();
//			Class clazz=user.getClass();
			String name=clazz.getName();  //获取类或接口的名称
			System.out.println("名称:"+name);
			String simpleName=clazz.getSimpleName();
			System.out.println("简单类名:"+simpleName);
			//获取声明的属性信息
			System.out.println("*****************属性信息******************");
			Field[] fields=clazz.getDeclaredFields(); //Field类封装了属性信息
			for (Field field : fields) {
				int fieldModifier=field.getModifiers();//获取修饰符  0:默认 1:private 2:public 4:protected
				Class fieldType=field.getType();//获取类型
				String fieldName=field.getName();//获取名称
				System.out.println(fieldModifier+"----"+fieldType+"----"+fieldName);	
			}
			//获取构造方法
			System.out.println("**************构造方法****************");
			Constructor[] constructors=clazz.getDeclaredConstructors(); //获取构造器
			for (Constructor constructor : constructors) {
				int cModifier=constructor.getModifiers(); //获取构造器的修饰符
				String cName=constructor.getName();
				Class[] cs=constructor.getParameterTypes();
				System.out.println(cModifier+"---"+cName+"---"+Arrays.toString(cs));		
			}
			//获取方法信息
			System.out.println("***************方法信息***************");
			Method[] methods=clazz.getDeclaredMethods();
			for (Method method : methods) {
				int mModifier=method.getModifiers();
				Class returnType=method.getReturnType(); //获取返回值类型
				String mName=method.getName(); //获取方法名
				Class[] cs=method.getParameterTypes();
				System.out.println(mModifier+"---"+returnType+"---"+mName+"---"+Arrays.toString(cs));
			}
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}

}

运行结果

e2eaa93c27f1b9e782a3b17071b1b132.png

2 反射机制动态操作方法_属性_构造器

获取类的名字的方法

  • String getName() 获得全限定类名 包名+类名
  • String getSimpleName() 获得简单类名

获得类的属性的方法

  • Field getField(String fieldName) 得到公共的属性 对象
  • Field getDeclareField(String fieldName) 得到指定名称的 属性对象
  • Field []c.getDeclaredFields() 得到所有的属性 对象

获得类的方法

  • Method[] getDeclaredMethods() 得到所有声明的公共的方法对象
  • Method[] c.getMethods() 得到父类及本类中的公共的方法对象
  • Method getDeclaredMethod(String methodName, Class …type) 得到指定名称的 本类中公共的方法
  • Method getMethod(String methodName, Class type) 得到本类或父类中的公共的方法对象

获得构造方法

  • Constructor[] getDeclaredConstructors() 得到所有声明的公共的构造方法的对象
  • Constructor[] getConstructors() 得到公共的构造方法对象
  • Constructor getDeclaredConstructor(Class...type) 得到指定参数的公共的构造方法对象

练习代码

public class Test {
	public static void main(String[] args) throws Exception {
		String path="com.sxt.demo.User";
		//1.获取类的名称
		Class c=Class.forName(path);
		System.out.println("类的全名称:"+c.getName());
		System.out.println("类的名称:"+c.getSimpleName());
		
		//获取父类的Class对象
		Class cSuper=c.getSuperclass();
		System.out.println(cSuper.getName());
		System.out.println(cSuper.getSimpleName());
		
		//3.获取类的属性信息
//		Field f=c.getField("userId"); //  报错 只能获取公开的属性
//		System.out.println(f);
		Field[] fields=c.getFields();  //只能获取公开的属性
		System.out.println(fields.length);
		
		Field[] fields2=c.getDeclaredFields();
		System.out.println(fields2.length);
		
		for (Field field : fields2) {
//			System.out.println(field);  //调用了toString()方法
			System.out.println(field.getModifiers()+"t"+field.getType()+"t"+field.getName());
		}
		
		//3.获取类的方法信息
		Method[] methods=c.getDeclaredMethods();  //本类中的公共的方法对象
		System.out.println(methods.length);
		for (Method method : methods) {
//			System.out.println(method);
			System.out.println("访问权限:"+method.getModifiers());
			System.out.println("返回值类型:"+method.getReturnType());
			System.out.println("方法的名称:"+method.getName());
			//获取方法的参数
			Class[] cPara=method.getParameterTypes();
			for (Class c1 : cPara) {
				System.out.println(c1.getTypeName()+"t");
			}
			System.out.println("--------------------------");
		}
		System.out.println("========================");
		
		//4.获取类的构造器
		Constructor[] cons=c.getConstructors();
		for (Constructor constructor : cons) {
			System.out.println(constructor);
		}
		System.out.println("====================================");
		//根据参数获取指定的构造方法
		Constructor con=c.getConstructor(null);
		System.out.println(con);
		System.out.println("====================================");
		Constructor con2=c.getConstructor(int.class,String.class,String.class);
		System.out.println(con2);
		
			
	}
}

运行结果

620fd2bd84455dcdba38a2f6e75e16c0.png

练习代码

public class Test2 {
	public static void main(String[] args) {
		Class clazz;
		try {
			//如何动态创建对象
			clazz = Class.forName("com.sxt.reflect.User");
			Object object=clazz.newInstance();//通过反射动态创建对象
			System.out.println(object);
			System.out.println("------------访问属性---------------");
			Field userId=clazz.getDeclaredField("userId"); //获取指定的属性信息
			userId.setAccessible(true);
			userId.set(object, 1);//回调指定属性的赋值---->user.userId=1
			Object value=userId.get(object);//回调指定属性的getter方法进行赋值
			System.out.println("userId="+value);
			System.out.println("----------------回调方法---------------------");
			Method setUserName=clazz.getDeclaredMethod("setUserName", String.class);
			setUserName.invoke(object, "zhangsan"); //user.setUserName("zhangsan")
			Method getUserName=clazz.getDeclaredMethod("getUserName");//获取getUserName方法
			Object returnValue=getUserName.invoke(object); //user.getUserName()
			System.out.println(returnValue);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}

}

运行结果

6ae9d003e6e60f805b8d0f9f67da0ba1.png

3 提高反射效率

通过 setAccessible 提高性能

a) setAccessible 启用和禁用访问安全检查的开关,值为 true 则指示反射的对象在使用时应该取消 Java 语言访 问检查,值为 false 则指示反射的对象不实施 Java 语 言访问检查,并不是为 true 就能访问为 false 就不能访问

b) 禁止安全检查,可以提高反射的运行速度

练习代码

public class Test3 {
	//方法的直接调用
	public static void test(){
		Object obj=new Object();
		long startTime=System.currentTimeMillis();
		for(int i=0;i<1000000000L;i++){
			obj.hashCode();
		}
		long endTime=System.currentTimeMillis();
		System.out.println("直接调用 用时:"+(endTime-startTime));
	}
	//未优化 使用反射机制回调
	public static void test2() throws Exception{
		Object obj=new Object();
		Class clazz=obj.getClass();
		Method method=clazz.getDeclaredMethod("hashCode");
		long startTime=System.currentTimeMillis();
		for(int i=0;i<1000000000L;i++){
			method.invoke(obj);
		}
		long endTime=System.currentTimeMillis();
		System.out.println("未优化 使用反射机制回调 用时:"+(endTime-startTime));
	}
	//优化 使用反射机制回调
	public static void test3() throws Exception{
		Object obj=new Object();
		Class clazz=obj.getClass();
		Method method=clazz.getDeclaredMethod("hashCode");
		long startTime=System.currentTimeMillis();
		method.setAccessible(true);
		for(int i=0;i<1000000000L;i++){
			method.invoke(obj);
		}
		long endTime=System.currentTimeMillis();
		System.out.println("优化 使用反射机制回调 用时:"+(endTime-startTime));
	}
	
	public static void main(String[] args) throws Exception {
		test();
		test2();
		test3();
	}

}

运行结果

949589a047e7138d4cca93d69330b74f.png

4 反射操作泛型

Java 中的泛型仅仅是给编译器 javac 使用的,确保数据的安全性和免去强制类型转换的麻烦,但是一旦编译完成,所 有与泛型有关的类型全部擦除。

使用泛型直接读取泛型,是读取不到的,因为反射是操作 加载以后的类的。

Java新增的数据类型有

  • ParameterizedType: 表 示 一 种 参 数 化 的 类 型 ,比 如 Collection<String>,可以获取 String 信息
  • GenericArrayType:泛型数组类型
  • TypeVariable:各种类型变量的公共父接口
  • WildcardType:代表一种通配符类型表达式, 比如? extends Number,? super Integer (Wildcard 是一个单词,就是通配符)

练习代码

public class TestGeneric {
	public void test01(Map<String,User>map,List<User>list,String s){
		System.out.println("TestGeneric.test01");
	}
	public Map<Integer,User> test02(){
		System.out.println("TestGeneric.test01");
		return null;
	}
	public void test03(){
		System.out.println("TestGeneric.test01");
	}
	
	public static void main(String[] args) throws Exception {
		//获取test01方法的泛型参数信息NoSuchMethodException
		Class c=TestGeneric.class;
		Method test01=c.getDeclaredMethod("test01", Map.class,List.class,String.class);
		//获取带泛型参数的类型
		Type[] types=test01.getGenericParameterTypes();
		System.out.println(types.length);
		for (Type type : types) {
			if(type instanceof ParameterizedType){
				ParameterizedType parameterizedType=(ParameterizedType) type;//ParameterizedType表示一个参数化类型
				Type[] genricType=parameterizedType.getActualTypeArguments();//返回一个表示此类型的实际类型参数的数组Type对象
				//遍历每一个泛型参数中的泛型的类型
				for (Type genType : genricType) {
					System.out.println("泛型类型:"+genType);
				}
				System.out.println("-------------------");
			}
		}
		System.out.println("-------------------------");
		//获取test01方法返回值的泛型信息
		Method test02=c.getDeclaredMethod("test02", null);
		Type returnType=test02.getGenericReturnType();
		//判断是否带有泛型
		if(returnType instanceof ParameterizedType){
			Type[] types2=((ParameterizedType)returnType).getActualTypeArguments();
			for (Type type : types2) {
				System.out.println("返回值的泛值类型:"+type);
			}
		}
		System.out.println("----------------------------");
		Method test03=c.getMethod("test03", null);
		Type returnType3=test03.getGenericReturnType();
		System.out.println(returnType3 instanceof ParameterizedType);
	}
}

运行结果

254c2c9d00624d2864b29aee0b5b2f7c.png

5 注解

注解的作用

不是程序本身,可以对程序作出解释。(这一点跟注释没 什么区别)

可以被其他程序(比如:编译器等)读取。(注解信息处理流程,是注解和注释的重大区别,如果没有注解信息处理流 程,则注解毫无意义)

注解的格式:注解是以”@注释名”在代码中存在,还可以添加一些参数 值,例如@SuppressWarnings(value=”unchecked”)。

注解可以附加在 package,class,method,field 等上面,相当于给它们添加了额外的辅助信息,我们可以通过反射机制编程 实现对这些元素的访问。

内置的注解

  1. @Override :标识方法是重写的方法
  2. @Deprecated :标识的方法不建议使用
  3. @SuppressWarnings:用来抑制编译时的警告信息
  • @SuppressWarinings 需要提供参数才能正常使用,这些参数 都是已经定义好的,我们只需要选择就可以了。
  • @SuppressWarnings("unchecked") @SuppressWarnings(value={"unchecked","deprecation"})

70d7040dbf2b3f52d4ef76580f47ac2b.png
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值