78 反射——概念、类的各种信息的获取(类名,属性,方法...)

反射的概念

当程序运行时,程序中的每一个类都会被加载到堆内存中。生成且尽每个类仅生成一个Class对象。这个对象保存了整个类的结构信息,包括这个类的所有属性与方法甚至注解。就像一面镜子一样。所以我们称之为反射。

当我们说反射时,说的就是Class类与java.lang.reflect包中的类

每个类对应一个Class对象

java.lang.Class类保存了每一类的唯一一个对象。如下,当我们使用Class.forName()创建两个Class引用时,它们指向同一个对象。

每一个类包括基础数据类型的八大类及String、各基础数据类型对应的数组,枚举、接口、甚至Annotation注解。

public class Test {
	public static void main(String[] args) throws ClassNotFoundException {
		String path = "_20200103_reflection.Test";
		Class c1 = Class.forName(path);
		Class c2 = Class.forName(path);
		System.out.println(c1.hashCode());
		System.out.println(c2.hashCode());
	}
}

//运行结果
705927765
705927765

 

获取Class对象的三种方式

public class Demo01 {
	public static void main(String[] args) throws ClassNotFoundException {
		String path = "_20200103_reflection.User";
		User u = new User();
		//获取Class对象的三种方式:
		//1.Class.forName(包名.类名)
		Class<?> c1 = Class.forName(path);
		//2.已知类,直接:类.class
		Class<?> c2 = _20200103_reflection.User.class;
		//3.已知实例。实例.getClass()
		Class<?> c3 = u.getClass();
		System.out.println(c1);
		System.out.println(c2);
		System.out.println(c3);
	}
}
//运行结果

class _20200103_reflection.User
class _20200103_reflection.User
class _20200103_reflection.User

  

反射的常用方法

以下代码完整代码将在文末贴出。

一个Class对象包含了一个类的结构信息,包括:类名、参数、属性、方法、构造器、注解等等。我们来一一获取它们。

以下运行结果可能与最终代码运行结果有不同,因为我是边写此文边写代码的。 

获取类名

String path = "_20200104_review.User";
//反射获得Class对象
Class<?> clz = Class.forName(path);
//获取类名
System.out.println("类名:"+clz.getName());

  

获取构造方法

  • getConstructors()获取public修饰的构造器数组
  • getDeclaredConstructors()获取所有的构造器数组

//获取构造方法
//获取无参构造
Constructor<?> cons1 = clz.getConstructor(null);
//获取有参构造
Constructor<?> cons2 = clz.getConstructor(int.class,String.class,String.class);

  

获取实例

Object user1 = cons2.newInstance(18,"1002","小明");

  

获取方法

  • getMethods获取包括继承来的所有public方法
  • getDeclaredMethods获取所有该类声明的方法,包括private修饰的
  • 获取指定的方法 getMethod(String methodName,Class parameterClass) ,按指定参数获取方法,参数为:方法名,参数对应的Class对象,如String.class , int.class等等
System.out.println("----获取方法-------");
			//获取所有的public方法,包括继承来的
		Method[] methods = clz.getMethods();
		System.out.println(methods.length);
			//获取所有的声明的方法:包括私有方法,不包括继承来和构造方法
		Method[] methods1 = clz.getDeclaredMethods();
		System.out.println(methods1.length);
			//获取指定的方法:getId方法
		Method method = clz.getDeclaredMethod("getId",null);
		Method method1 = clz.getDeclaredMethod("test02", int.class);
		Method method2 = clz.getDeclaredMethod("test01", Map.class);

  

获取属性

System.out.println("----获取属性-------");
			//获取所有public修饰的属性,不包括继承来的
		Field[] fields = clz.getFields();
		System.out.println(fields.length);
			//获取所有声明的属性,包括私有的
		Field[] fields2 = clz.getDeclaredFields();
		System.out.println(fields2.length);
			//获取指定声明的属性
		Field field = clz.getDeclaredField("name");
		System.out.println(field);
			//获取指定的公开的属性
		Field field2 = clz.getField("id");
		System.out.println(field2);

  

获取属性值

 注意:如果使用 反射属性.get(反射实例) 的方式获取属性值,需要在前面写一句:反射属性.setAccessible(true)

同样地,当使用反射直接调用一个private修饰的方法时,也需要写:反射方法.setAccessible(true);

//读取属性值
//方法一:通过反射属性.get(反射Class对象)
field2.setAccessible(true);
System.out.println(field2.get(user1));
//方法二:通过反射实例向下转型调用类中的getId方法
System.out.println(((User)user1).getId());

  

读取方法的参数类型

//读取参数类型
		System.out.println("----获取参数类型----");
		Class<?>[] parameters = method1.getParameterTypes();
		for(Class p : parameters) {
			System.out.println("参数:"+p);
		}

  

读取方法的返回值类型

//读取返回值类型
		Class<?> returnType = method.getReturnType();
		System.out.println(returnType);

  

读取方法的泛型参数类型与泛型参数的实参的类型

	//获取方法的泛型参数类型
		Type[] genericTypes = method2.getGenericParameterTypes();
		for(Type parameter : genericTypes) {
			System.out.println("泛型参数:"+parameter);
			//获取方法的泛型参数的实参类型
			if(parameter instanceof ParameterizedType) {
				Type[] argumentsType = ((ParameterizedType)parameter).getActualTypeArguments();//parameter表示形参,argument表示实参
				for(Type argumentType : argumentsType) {
					System.out.println("泛型的实参类型为:"+argumentType);
				}
			}
		}

  

读取方法的泛型返回值类型的实参的类型

	//读取泛型返回值类型
		Type returnGenericType = method2.getGenericReturnType();
		System.out.println(returnGenericType);
			//读取泛型返回值类型之实参类型
		if(returnGenericType instanceof ParameterizedType){
			Type[] actualtp = ((ParameterizedType) returnGenericType).getActualTypeArguments();
			for(Type acp : actualtp) {
				System.out.println("返回值泛型参数的实参类型:"+acp);
			}
		}

  

获取注解

 思路:

  • 反射获取Class对象
  • Class对象调用getAnnotations获取注解数组
  • 或调用GetAnnottation(具体注解的Class对象)
System.out.println("---获取类注解---");
		Annotation[] annos = clz.getAnnotations();
		for(Annotation a : annos) {
			System.out.println("类注解的值为:"+a);
		}
		System.out.println("----获取属性注解----");
		for(Field f : fields2) {
			UserField a= f.getAnnotation(UserField.class);
			System.out.println("columnName:"+a.columnName()+" tpe:"+a.type()+" length:"+a.length());
		}

  

扩展内容

ParameterizedType是最常用的关于泛型的一个类,其他还有不常用的如下:

运行结果

类名:_20200104_review.User
----获取方法-------
17
9
----获取属性-------
1
3
private java.lang.String _20200104_review.User.name
public java.lang.String _20200104_review.User.id
1002
1002
----获取参数类型----
参数:int
----获取返回值类型-----
class java.lang.String
----获取泛型参数及参数的实参类型----
泛型参数:java.util.Map<java.lang.String, java.lang.Integer>
泛型的实参类型为:class java.lang.String
泛型的实参类型为:class java.lang.Integer
----读取泛型返回值类型----
java.util.List<java.lang.String>
返回值泛型参数的实参类型:class java.lang.String
---获取类注解---
类注解的值为:@_20200104_review.UserTable(value=user_table)
----获取属性注解----
columnName:age tpe:varchar length:5
columnName:id tpe:int length:10
columnName:name tpe:carchar length:10

  

完整代码

User类

package _20200104_review;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@UserTable("user_table")
public class User extends Person{
	@UserField(columnName="age",type="varchar",length=5)
	private int age;
	@UserField(columnName="id",type="int",length=10)
	public String id;
	@UserField(columnName="name",type="carchar",length=10)
	private String name;
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	public String getId() {
		return id;
	}
	public void setId(String id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public User(int age, String id, String name) {
		super();
		this.age = age;
		this.id = id;
		this.name = name;
	}
	public User() {
		super();
	}
	private List<String> test01(Map<String,Integer> map) {
		System.out.println("我是私有方法test01");
		return null;
	}
	public void test02(int num) {
		System.out.println("我是公有方法test"+num);
	}
	public static void main(String[] args) {
		User u = new User();
	}
}

  

注解类:UserTable

package _20200104_review;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(value = ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface UserTable {
	String value();
}

  

注解类:UserField

  

package _20200104_review;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(value = ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface UserField {
	String columnName();
	String type();
	int length();
}

  

测试类

package _20200104_review;

import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Map;

/**
 * 	读取User类的信息
 * @author TEDU
 *
 */
public class ReflectionTest {
	public static void main(String[] args) throws Exception{
		String path = "_20200104_review.User";
		//反射活得Class对象
		Class<?> clz = Class.forName(path);
		//获取类名
		System.out.println("类名:"+clz.getName());
		//获取构造方法
			//获取无参构造
		Constructor<?> cons1 = clz.getConstructor(null);
			//获取有参构造
		Constructor<?> cons2 = clz.getConstructor(int.class,String.class,String.class);
		//获取实例
		Object user1 = cons2.newInstance(18,"1002","小明");
		//读取方法
		System.out.println("----获取方法-------");
			//获取所有的public方法,包括继承来的
		Method[] methods = clz.getMethods();
		System.out.println(methods.length);
			//获取所有的声明的方法:包括私有方法,不包括继承来和构造方法
		Method[] methods1 = clz.getDeclaredMethods();
		System.out.println(methods1.length);
			//获取指定的方法:getId方法
		Method method = clz.getDeclaredMethod("getId",null);
		Method method1 = clz.getDeclaredMethod("test02", int.class);
		Method method2 = clz.getDeclaredMethod("test01", Map.class);
		//读取属性
		System.out.println("----获取属性-------");
			//获取所有public修饰的属性,不包括继承来的
		Field[] fields = clz.getFields();
		System.out.println(fields.length);
			//获取所有声明的属性,包括私有的
		Field[] fields2 = clz.getDeclaredFields();
		System.out.println(fields2.length);
			//获取指定声明的属性
		Field field = clz.getDeclaredField("name");
		System.out.println(field);
			//获取指定的公开的属性
		Field field2 = clz.getField("id");
		System.out.println(field2);
		//读取属性值
			//方法一:通过反射属性.get(反射Class对象)
		field2.setAccessible(true);
		System.out.println(field2.get(user1));
			//方法二:通过反射实例向下转型调用类中的getId方法
		System.out.println(((User)user1).getId());
		//读取参数类型
		System.out.println("----获取参数类型----");
		Class<?>[] parameters = method1.getParameterTypes();
		for(Class p : parameters) {
			System.out.println("参数:"+p);
		}
		System.out.println("----获取返回值类型-----");
		//读取返回值类型
		Class<?> returnType = method.getReturnType();
		System.out.println(returnType);
		//读取泛型参数及其实参类型
		System.out.println("----获取泛型参数及参数的实参类型----");
			//获取方法的泛型参数类型
		Type[] genericTypes = method2.getGenericParameterTypes();
		for(Type parameter : genericTypes) {
			System.out.println("泛型参数:"+parameter);
			//获取方法的泛型参数的实参类型
			if(parameter instanceof ParameterizedType) {
				Type[] argumentsType = ((ParameterizedType)parameter).getActualTypeArguments();//parameter表示形参,argument表示实参
				for(Type argumentType : argumentsType) {
					System.out.println("泛型的实参类型为:"+argumentType);
				}
			}
		}
		//读取泛型返回值类型
		System.out.println("----读取泛型返回值类型----");
			//读取泛型返回值类型
		Type returnGenericType = method2.getGenericReturnType();
		System.out.println(returnGenericType);
			//读取泛型返回值类型之实参类型
		if(returnGenericType instanceof ParameterizedType){
			Type[] actualtp = ((ParameterizedType) returnGenericType).getActualTypeArguments();
			for(Type acp : actualtp) {
				System.out.println("返回值泛型参数的实参类型:"+acp);
			}
		}
		//读取注解
		System.out.println("---获取类注解---");
		Annotation[] annos = clz.getAnnotations();
		for(Annotation a : annos) {
			System.out.println("类注解的值为:"+a);
		}
		System.out.println("----获取属性注解----");
		for(Field f : fields2) {
			UserField a= f.getAnnotation(UserField.class);
			System.out.println("columnName:"+a.columnName()+" tpe:"+a.type()+" length:"+a.length());
		}
	}
}

  

原文地址:https://www.cnblogs.com/Scorpicat/p/12145061.html