Java反射

1、定义

Java的反射技术是java程序的特征之一,它允许运行中的Java程序对自身进行检查,或者说“自审”,并能直接操作程序的内部属性。

使用反射可以获得Java类中各个成员的名称并显示出来。简单的说,反射就是让你可以通过名称来得到对象(类,属性,方法)的技术。

一句话:运行时探究和使用编译时未知的类。

2、反射原理

对象创建过程:比如要创建Dog类的三个对象
        Dog d1 = new Dog();
        Dog d2 = new Dog();
        Dog d3 = new Dog();

在这个过程中,JVM的底层实现过程如下:

1.JVM利用DogClassLoader先将Dog类加载到内存,然后马上产生了一个Class类型的对象,该对象可以看成是一个模型,以后无论创建多少个Dog类的实例都是利用该模型来生成。
所以一个类所对应的Class类型的对象只有一个

2.根据这个模型生成Dog类的三个实例d1、d2、d3。反射正是利用了java的这种加载方式主动完成了对象的创建及使用。

3、使用步骤

遵循三个步骤

第一步是获得你想操作的类的 java.lang.Class 对象
第二步是调用诸如 getDeclaredMethods 的方法
第三步使用 reflection API 来操作这些信息

第一步:获取Class对象

获得Class对象的方式主要有以下三种:
方式一:如果一个类的实例已经得到,你可以使用

【Class c = 对象名.getClass(); 】
//例如
TextField t = new TextField(); 
Class c = t.getClass();	
Class s = c.getSuperclass(); 

方式二:如果你在编译期知道类的名字,你可以使用如下的方法

Class c = JButton.class;   或者 Class c = Integer.TYPE;

方式三:如果类名在编译期不知道, 但是在运行期可以获得, 你可以使用下面的方法

Class c = Class.forName(strg); 
第二步:探究类的信息

一个类通常由三部分组成——属性、普通方法、构造方法。

反射机制中为获取以上三个部分分别提供了常用类及方法。
Filed类:提供有关类或接口的属性信息。
Constructor类:提供关于类的单个构造方法的信息以及对它的访问权限。
Method类:提供关于类或接口上单独某个方法(以及如何访问该方法)的信息。

Filed类
Filed类常用方法:
Field    getField(String name)	获得指定的公共字段
Field[]  getFields()	获得类的所有公共字段
Field    getDeclaredField(String name) 获得指定的字段
Field[]   getDeclaredFields()	获得类声明的所有字段

使用示例代码:

System.out.println("---------------------类-------------------------------");
// 获取类
Class userClass = Class.forName("com.xxx.classroom.User");
System.out.println(userClass);
System.out.println("---------------------属性-------------------------------");
// 获取类中的全部属性数组
Field[] field = userClass.getDeclaredFields();
for (Field field2 : field) {
	// 属性的注解 Modifier
	int i = field2.getModifiers();
	// 数据类型
	AnnotatedType annotatedType = field2.getAnnotatedType();
	// 获取属性名字
	String className = field2.getName();
	System.out.print(i + "  " + annotatedType.getType() + "  " + className);
	System.out.println();
	System.out.println(field2);
}

System.out.println("-----------------隔离线-----------------------");

// 通过属性名字获取属性所有都可以获取
Field fid = userClass.getDeclaredField("id");
System.out.println(fid);

System.out.println("-----------------隔离线-----------------------");

// 获取类中的公共属性数组
Field[] fields = userClass.getFields();
for (Field field2 : fields) {
	System.out.println(field2);
}
System.out.println("-----------------隔离线-----------------------");
// 通过属性名字获取属性可以获取公共属性
Field fidPublic = userClass.getField("userName");
System.out.println(fidPublic);
Constructor类
Constructor类常用方法:
//获得使用特殊的参数类型的公共构造函数
Constructor getConstructor(Class[] params)		
// 获得类的所有公共构造函数
Constructor[] getConstructors()		
//获得使用特定参数类型的构造函数(与访问级别无关)
Constructor getDeclaredConstructor(Class[] params)	
//获得类的所有构造函数(与访问级别无关)
Constructor[] getDeclaredConstructors()

代码示例:

System.out.println("---------------------类-------------------------------");
// 获取类
Class userClass = Class.forName("com.xxx.classroom.User");
System.out.println(userClass);
// 获取类中所有构造方法
Constructor[] constructorAll = userClass.getDeclaredConstructors();
for (Constructor constructor : constructorAll) {
	System.out.println(constructor);
}
System.out.println("-----------------隔离线-----------------------");
// 获取类中所有公共构造方法
Constructor[] constructorArray = userClass.getConstructors();
for (Constructor constructor : constructorArray) {
	System.out.println(constructor);
	// 参数个数
	System.out.println(constructor.getParameterCount());
	// 参数类型
	Class[] claArray = constructor.getParameterTypes();
	for (Class c : claArray) {
		System.out.println(c.getName());
	}
}
Method类
Method类常用方法:
//使用特定的参数类型,获得命名的公共方法
Method getMethod(String name, Class[] params)	
//获得类的所有公共方法
Method[] getMethods()
//使用特定的参数类型,获得类声明的命名的方法
Method getDeclaredMethod(String name, Class[] params)
//获得类声明的所有方法
Method[] getDeclaredMethods()

代码示例:

System.out.println("---------------------类-------------------------------");
// 获取类
Class userClass = Class.forName("com.xxx.classroom.User");
System.out.println(userClass);
System.out.println("---------------------方法-------------------------------");
// 获取类中的全部方法
Method[] methods = userClass.getDeclaredMethods();
for (Method method2 : methods) {
	// 属性的注解 Modifier
	int i = method2.getModifiers();
	// 返回数据类型
	AnnotatedType annotatedType = method2.getAnnotatedReturnType();
	// 获取方法名字
	String className = method2.getName();
	// 获取注解
	Annotation[] a = method2.getDeclaredAnnotations();
	System.out.println("注解个数:" + a.length);
	for (Annotation a2 : a) {
		System.out.println(a2.annotationType());
	}
	// 参数个数
	System.out.println("参数个数:" + method2.getParameterCount());
	// 获取形式参数列表的数据类型
	Type[] type = method2.getParameterTypes();
	System.out.println("参数个数type:" + type.length);
	System.out.print(i + "  " + annotatedType.getType() + "  " + className + "  ");
	for (Type t : type) {
		System.out.print(t.getTypeName() + "  ");
	}
	System.out.println();
	System.out.println(method2);
}
System.out.println("-----------------隔离线-----------------------");

// 获取已知任意方法
Method methodAll = userClass.getDeclaredMethod("insert", java.lang.Long.class);
System.out.println(methodAll);
System.out.println("-----------------隔离线-----------------------");

// 获取类中的所有的公共方法包括从父类继承下来的
Method[] methods1 = userClass.getMethods();
for (Method method2 : methods1) {
	System.out.println(method2);
}
System.out.println("-----------------隔离线-----------------------");
// 获取指定公共方法
Method methodPublic = userClass.getMethod("insert", java.lang.String.class, java.lang.String.class);
System.out.println(methodPublic);
第三步:利用反射API操作探究信息

在第二步中我们已经可以获得了类的几个主要组成部分——属性、构造方法、方法各自的对象了,接下来我们就可以控制这些对象来完成一些操作了。

利用反射技术而进行的常用操作主要有三个:
通过Constructor创建对象
通过Method执行方法
通过Field为属性赋值取值

示例
通过反射实例化对象并使用对象:

/**
* 使用构造方法实例化对象
* 
* @param <T>       返回对象
* @param o         构造参数列表
* @param userClass 传入一个类对象
* @return
*/
public static <T> T createObject(Class userClass, Object... o) {
	// TODO Auto-generated method stub
	try {
		Constructor[] constructorArray = userClass.getConstructors();
		int length = o.length;
		for (Constructor constructor : constructorArray) {
			Class[] claArray1 = constructor.getParameterTypes();
		
			//构造方法的参数个数和传入的参数个数
			if (claArray1.length == length) {
					
				//将Object数组中的数据类型提出
				Class[] oArray = dataConversion(o);
					
				//将claArray1中含有的基本数据类型转化为包装类
				Class[] claArray = dataConversion(claArray1);
					
				for (int i = 0; i < length; i++) {
					//比对数据类型是否相等
					if (!claArray[i].getName().equals(oArray[i].getName())) {
						throw new Exception("第" + (i + 2) + "个参数应该是" + claArray1[i].getName() + "类型的数据");
					}
				}
				return (T) constructor.newInstance(o);
			}
		}
			throw new Exception("没有该构造方法");
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return null;
}
/**
* 将数组每个数据转化为对应类
* @param o
* @return
*/
public static Class[] dataConversion(Object[] o) {
	Class[] cla = new Class[o.length];
	int length = cla.length;
	for (int i = 0; i < length; i++) {
		cla[i] = o[i].getClass();
	}
	return cla;
}
	
/**
* 将基本数据转化为包装类
* @param c
* @return
*/
public static Class[] dataConversion(Class[] c) {
	int length = c.length;
	for (int i = 0; i < length; i++) {
		if (c[i].getName().equals("byte")) {
			c[i] = Byte.class;
		}
		if (c[i].getName().equals("char")) {
			c[i] = Character.class;
		}
		if (c[i].getName().equals("short")) {
			c[i] = Short.class;
		}
		if (c[i].getName().equals("int")) {
			c[i] = Integer.class;
		}
		if (c[i].getName().equals("long")) {
			c[i] = Long.class;
		}
		if (c[i].getName().equals("double")) {
			c[i] = Double.class;
		}
		if (c[i].getName().equals("float")) {
			c[i] = Float.class;
		}
		if (c[i].getName().equals("boolean")) {
			c[i] = Boolean.class;
		}
	}
	return c;
}
/**
* 调用方法
*/
public static void meth() {
	// TODO Auto-generated method stub
	try {
		Class userClass = Class.forName("com.xxx.classroom.User");
		Object c = createObject(userClass, 5L, "张", "ssss");
		if (c != null) {
			String userName = (String) userClass.getDeclaredField("userName").get(c);
			String pwd = (String) userClass.getDeclaredField("password").get(c);
			System.out.println("姓名:" + userName);
			System.out.println("密码:" + pwd);
			Long id = (Long) userClass.getDeclaredField("id").get(c);
			System.out.println("id:" + id);

			// 获取getPassword方法
			Method method = userClass.getDeclaredMethod("getPassword");
			// 使用方法
			String s = (String) method.invoke(c);
			System.out.println(s);

			Method method2 = userClass.getDeclaredMethod("printNamePwd", int.class);
			String str = (String) method2.invoke(c, 1);
			System.out.println(str);
		} else {
			System.out.println("实例化对象失败");
		}
	} catch (Exception e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
	}
}

使用的user类:

public class User {
	private static Long cc;
	public Long id;
	public String userName;
	public String password;
	String s;
	
	public User() {
		super();
	}
	/**
	 * 
	 * @param id
	 * @param userName
	 * @param password
	 */
	public User(Long id, String userName, String password) {
		super();
		this.id = id;
		this.userName = userName;
		this.password = password;
	}
	public User(String userName, String password) {
		super();
		this.userName = userName;
		this.password = password;
	}
	/**
	 * 获取密码
	 * @return
	 */
	public String getPassword() {
		return password;
	}
	/**
	 * 获取名字密码
	 * @param i
	 * @return
	 */
	public String printNamePwd(int i) {
		StringBuffer sb = new StringBuffer();
		sb.append(this.userName);
		sb.append(this.password);
		sb.append(i);
		return String.valueOf(sb);
	}
	private void insert(Long id) {
		System.out.println("一个私有方法一个参数");
	}
	
	@Test
	public void insert(String userName ,String pwd) {
		
		System.out.println("这是一个共有的方法两个参数");
	}
	protected void insert(Long id,String userName ) {
		System.out.println("这是一个受保护的方法两个参数");
	}
}

更多方法参照JDK

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值