java反射详解实战代码

        JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;

        Java反射机制主要提供了以下功能: 在运行时判断任意一个对象所属的类;在运行时构造任意一个类的对象;在运行时判断任意一个类所具有的成员变量和方法;在运行时调用任意一个对象的方法;生成动态代理。

Class反射机制

  1. 指的是可以于运行时加载,探知和使用编译期间完全未知的类.
  2. 程序在运行状态中,可以动态加载一个只有名称的类,对于任意一个已经加载的类,能够知道这个类的所有属性和方法;对于任意一个对象,都能调用他的任意一个方法和属性;
  3. 加载完类之后,在堆内存中会产生一个Class类型的对象(一个类只有一个Class对象),这个对象包含了完整的类的结构信息,而且这个Class对象就像一面镜子,透过这个镜子看到类的结构,所以被称之为:反射。
  4. 每个类被加载进入内存之后,系统就会为该类生成一个对应的java.lang.Class对象,通过该Class对象就可以访问到JVM中的这个类.

Class对象的获取

  1. 对象的getClass()方法;
  2. 类的.class(最安全/性能最好)属性;
  3. 运用Class.forName(String className)动态加载类,className需要是类的全限定名(最常用).
        下面用代码展示一下:

package com.lwl.reflect;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

/**
 * 获取类的所有属性和方法及构造器
 * @create 2017-10-11 上午11:42:52
 * @version 1.0
 */
public class ReflectAllDemo {

	/**
	 * 获取类的所有属性和方法及构造器
	 * @param args
	 * @throws ClassNotFoundException 
	 * @create 2017-10-11 上午9:07:46
	 */
	public static void main(String[] args) throws ClassNotFoundException {
		
		//根据一个类的全名称获取类的类对象
		//如果类的全名称错误或者不存在,则会报类查询不到异常:ClassNotFoundException
		Class<?> clazz = Class.forName("java.lang.String");
		
		//获取传递过来的类的所有方法
		 Method[]	 methods = clazz.getDeclaredMethods();
		 for (Method method : methods) {
			System.out.println(method.toString());
		}
		 
		System.out.println("------------------------------我是分隔符:以下是类的属性--------------------------------"); 
		//获取传递过来的类的所有属性 
		Field[] fields = clazz.getDeclaredFields();
		for (Field field : fields) {
			System.out.println(field.toString());
		} 
		
		System.out.println("------------------------------我是分隔符:以下是构造方法--------------------------------");
		
		//获取传递过来的类的所有构造方法
		Constructor<?>[] constructor = clazz.getDeclaredConstructors();
		for (Constructor<?> ctt : constructor) {
			System.out.println(ctt.toString());
		}
		
	}

}

创建对象

通过反射来生成对象的方式有两种:

  1. 使用Class对象的newInstance()方法来创建该Class对象对应类的实例(这种方式要求该Class对象的对应类有默认构造器).
  2. 先使用Class对象获取指定的Constructor对象,再调用Constructor对象的newInstance()方法来创建该Class对象对应类的实例(通过这种方式可以选择指定的构造器来创建实例).

调用方法

当获取到某个类对应的Class对象之后,就可以通过该Class对象的getMethod来获取一个Method数组或Method对象.

每个Method对象对应一个方法,在获得Method对象之后,就可以通过调用invoke方法来调用该Method对象对应的方法.

package com.lwl.reflect;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * 通过反射,对类中的方法进行操作
 * @create 2017-10-11 上午11:45:57
 * @version 1.0
 */
public class ReflectMethodDemo {

	public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException {
		
		
		Class<?> clazz = Class.forName("com.lwl.reflect.Person");
		//获取对象
		Object instance = clazz.newInstance();
//		instance = clazz.getDeclaredConstructor(null).newInstance(null);
		
		//如果已经知道方法的名称,那么调用起来更加方便
		Method method = clazz.getDeclaredMethod("setName", new Class[]{String.class});
		//设置值
		method.invoke(instance, new String[]{"jack"});

		System.out.println(instance.toString());
		
		//获取值
		Method getMethod = clazz.getDeclaredMethod("getName", new Class[]{});
		Object getValue = getMethod.invoke(instance, new String[]{});
		System.out.println(getValue);
		
		//对对象中的静态方法进行访问
		Method staticMethod = clazz.getDeclaredMethod("printInfo", new Class[]{});
		//由于是静态方法,所以这里面的 instance 可以不传,只用用 null 表示
		Object staticValue = staticMethod.invoke(instance, new String[]{});
//		 staticValue = staticMethod.invoke(null, new String[]{});
		System.out.println(staticValue);
		
	}

}

访问成员变量

通过Class对象的的getField()方法可以获取该类所包含的全部或指定的成员变量Field,Filed提供了如下两组方法来读取和

设置成员变量值 .

  1. getXxx(Object obj): 获取obj对象的该成员变量的值, 此处的Xxx对应8中基本类型,如果该成员变量的类型是引用类型, 则取消get后面的Xxx;
  2. setXxx(Object obj, Xxx val): 将obj对象的该成员变量值设置成val值.此处的Xxx对应8种基本类型, 如果该成员类型是引用类型, 则取消set后面的Xxx;

package com.lwl.reflect;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * 通过反射,对类中的字段进行操作
 * @create 2017-10-11 上午11:45:20
 * @version 1.0
 */
public class ReflectFieldDemo {

	public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException, NoSuchFieldException {
		
		//获取类对象
		Class<?> clazz = Class.forName("com.lwl.reflect.Person");
		//获取对象
		Object instance = clazz.newInstance();
//		instance = clazz.getDeclaredConstructor(null).newInstance(null);
		
		//根据属性的名称 获取属性对象
		Field field = clazz.getDeclaredField("name");
		//获取属性的类型
		Class<?> type = field.getType();
		System.out.println(type); //out print class java.lang.String
		
		//获取属性的名称
		String name = field.getName();
		System.out.println(name);  //out print name
		
		//由于name属性是private,如果不设置setAccessible是无法直接对其进行设置
		//setAccessible是暴力破坏,如果是私有方法同理要设置
		field.setAccessible(true);
		field.set(instance, "张三");
		
		System.out.println(instance.toString()); //out print Person [id=null, name=张三, address=null]
		
	}

}

通过反射赋值

package com.lwl.reflect;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * 通过反射,对类对象进行赋值操作
 * @create 2017-10-11 上午11:44:58
 * @version 1.0
 */
public class ReflectSetValueDemo {

	/**
	 * 用一句话说明这个方法做什么 
	 * @param args
	 * @throws ClassNotFoundException 
	 * @throws SecurityException 
	 * @throws NoSuchFieldException 
	 * @throws NoSuchMethodException 
	 * @throws InvocationTargetException 
	 * @throws IllegalArgumentException 
	 * @throws IllegalAccessException 
	 * @throws InstantiationException 
	 * @create 2017-10-11 上午9:41:51
	 */
	public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, SecurityException, NoSuchMethodException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {

		//获取类的Class的三种方式
		/*
		 * 1. Class.forName(类名称全称:包括包名)
		 * 2. 类.class  即:Person.class
		 * 3. 对象.getClass()  new Person().getClass();
		 * */
		Class<?> clazz = Class.forName("com.lwl.reflect.Person");
//		clazz = new Person().getClass();
//		clazz = Person.class;
		
		//获取一个属性
		Field field = clazz.getDeclaredField("address");
		System.out.println(field.toString());
		
		System.out.println("--------------------------------------------我是分隔符:以下是对方法进行操作--------------------------------------------------------");
		
		//获取一个方法
		Method method = clazz.getDeclaredMethod("getName", new Class[]{});
		
		//传递的Class<?>的顺序要和方法的参数类型顺序保持一致,不然就无法匹配抛出异常:java.lang.NoSuchMethodException
		Method method1 = clazz.getDeclaredMethod("setName", String.class);
		//获取方法的名字
//		String name = method1.getName();
		Method method2 = clazz.getDeclaredMethod("setInfo", String.class,Integer.class);
		//method1 与 method2 还可以使用另外一种方式获取
		Method method3 = clazz.getDeclaredMethod("setName", new Class[]{String.class});
		Method method4 = clazz.getDeclaredMethod("setInfo", new Class[]{String.class,Integer.class});
		
		System.out.println(method.toString());
		System.out.println(method1.toString());
		System.out.println(method2.toString());
		System.out.println(method3.toString());
		System.out.println(method4.toString());
		
		System.out.println("--------------------------------------------我是分隔符:以下是对构造器进行操作--------------------------------------------------------");
		//因为默认构造器没有参数,使用可以传入null 或者 new Class[]{}
		 Constructor<?> cs =  clazz.getDeclaredConstructor(new Class[]{});
		 //带参数的构造器
		 Constructor<?> cs2 =  clazz.getDeclaredConstructor(new Class[]{Integer.class,String.class,String.class});
		 System.out.println(cs.toString());
		 System.out.println(cs2.toString());
		 
		 
		System.out.println("--------------------------------------------我是分隔符:以下是对反射赋值进行操作--------------------------------------------------------");
		//根据类的默认构造器 创建一个类对象	 
	    Object object =	cs.newInstance(new Object[]{});
//	    object = cs.newInstance(null);
	    //根据类的带参数构造器,创建一个类对象
	    Object object2 =	cs2.newInstance(new Object[]{1,"李四","南京"});
//	    object2 = cs2.newInstance(null);
		System.out.println("原始的对象属性情况:"+object); 
		System.out.println("原始的对象属性情况:"+object2); 
		
		 
		System.out.println("--------------------------------------------我是分隔符:以下是对反射赋值进行操作:设置开始--------------------------------------------------------");
		
		//对属性进行设置值,先获取所有的方法
		Method[] methods = clazz.getDeclaredMethods();
		//获取类的所有属性
		Field[] fields = clazz.getDeclaredFields();
		
		for (Method m : methods) {
			//获取方法的名称
			String name = m.getName();
			//如果名称是以set开头的,表示设置值
			if(name.startsWith("set")){
				//获取set之后的字符串,即属性的名称
				String fieldName = name.substring(3);
				//因为set之后的首个字符串是大写,所以要截取第一个字符串转化为小写,这里千万别把所有的字符串都转化为小写,防止出现UserName 被转化为username
				fieldName = fieldName.substring(0, 1).toLowerCase() + fieldName.substring(1);
				//这里会对类中的属性进行赋值
				//由于Person里面一个特殊的setInfo的方法,且info不是类的属性,则不会进行赋值
				setFieldValue(fieldName, fields, m, object);
			}
		}
		System.out.println("赋值后的对象属性情况:"+object); 
		System.out.println("赋值后的对象属性情况:"+object2); 
	    
	}

	/**
	 * 给类属性赋值 
	 * @param fieldName
	 * @param fields
	 * @param m
	 * @param object
	 * @throws IllegalAccessException
	 * @throws IllegalArgumentException
	 * @throws InvocationTargetException
	 * @create 2017-10-11 上午10:41:53
	 */
	public static void setFieldValue(String fieldName, Field[] fields, Method m,  Object object) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException{
		
		for (Field field : fields) {
			if (field.getName().equals(fieldName)){
				//获取字段的属性
				Class<?> fieldClass = field.getType();
				//如果是Integer 即知道这个是Person的ID
				if(fieldClass == Integer.class){
					//通过反射设置值:也就是通过object对象,调用当前的 m 方法,后面是 m 方法需要的参数
					m.invoke(object, new Integer[]{1});
				}
				//因为同为String的有2个set方法,所有要通过属性名称判断到底是调用哪个
				else if (fieldClass == String.class && "name".equals(fieldName)){
					//通过反射设置值:也就是通过object对象,调用当前的 m 方法,后面是 m 方法需要的参数
					m.invoke(object, new String[]{"jack"});
				}
				else if (fieldClass == String.class && "address".equals(fieldName)){
					//通过反射设置值:也就是通过object对象,调用当前的 m 方法,后面是 m 方法需要的参数
					m.invoke(object, new String[]{"南京"});
				}
				//不需要再次循环
				return;
			}
		}
		
	}
	
}

使用到的辅助类:

package com.lwl.reflect;

public class Person {

	
	private Integer id;
	
	private String name;
	
	private String address;

	public Person() {
	}

	public Person(Integer id, String name, String address) {
		this.id = id;
		this.name = name;
		this.address = address;
	}

	public Integer getId() {
		return id;
	}

	public void setId(Integer id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getAddress() {
		return address;
	}

	public void setAddress(String address) {
		this.address = address;
	}
	
	public void setInfo(String name,Integer id){
		this.id = id;
		this.name = name;
				
	}

	
	public static void printInfo(){
		System.out.println("我是静态方法,我被调用了");
	}
	
	@Override
	public String toString() {
		return "Person [id=" + id + ", name=" + name + ", address=" + address
				+ "]";
	}
	
	
	
	
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值