java中通过反射获取class文件对象、构造方法、成员变量、成员方法实例

一、 反射:

 通过class文件对象,使用该文件中的成员变量、构造方法、成员方法

1. 通过反射获取class文件对象

 a) Object类中的getClass()方法
 b) 数据类型的静态属性class
 c) Class类中的静态方法
  public static Class forName(String className)
  className为类的全路径(带包名)
 d) 使用哪一种?
  开发时常用第三种,因为第三种className是一个字符串,而不是一个具体的类名。
  这样我们就可以将字符串配置到配置文件中。
 e) 下面给出获取class文件对象的三种实例

2. 通过反射获取构造方法 Constructor

 a) public Constructor[] getConstructors()
  仅能获取公共构造方法
 b) public Constructor[] getDeclaredConstructors()
  获取所有的构造方法
 c) public Constructor getConstructor(Class … parameterTypes)
  获取单个构造方法,参数是 要获取的构造方法的构造参数个数及数据类型的class字节码文件对象
 d) public T newInstance(Object … initargs)
  使用此Constructor对象表示的构造方法来创建该构造方法的声明类的新实例,
  并用指定的初始化参数初始化此实例
 e) 下面给出实例

3. 通过反射获取成员变量 Field

 a) public Field[] getFields()
  仅能获取公共成员变量
 b) public Field[] getDeclared Fields()
  获取所有的成员变量
 c) public Field getField(String name)
  获取名字为name的成员变量
 d) public void set(Object obj , Object value)
  将指定对象变量上此Field对象表示的字段设置为指定的新值
  obj为反射出来的对象,value为给此变量设置的新值
 e) 下面给出实例

4. 通过反射获取成员方法 Method

 a) public Method[] getMethods()
  获取自己包括父亲的公共成员方法
 b) public Method[] getDeclareMethods()
  获取自己的所有的成员方法
 c) public Method getMethod (String name, Class… parameterTypes)
  获取指定的成员方法
  第一个参数为成员方法名,第二个参数为调用的成员方法的参数的class类型
 d) public Object invoke(Object obj,Object …args)
  返回值是Object接收,为字节码文件中方法的返回值。
  第一个参数是对象,第二个参数为调用该方法的实际参数,
 e) 下面给出实例

5. 动态代理:在程序运行中通过反射产生代理对象

  JDK提供的代理只能针对接口做代理,(通过使用Proxy类和InvocationHandler接口),有更强大的代理cglib,下面给出实例

代码实例:

1、获取class对象的三种方法
package test01_class;
/*
 * 三种获取class对象的方法
 * 		每种方法获取的class对象都相同
 */
public class ClassDemo {
	public static void main(String[] args) throws ClassNotFoundException {
		
		StudentDemo sd1=new StudentDemo();
		StudentDemo sd2=new StudentDemo();
		
		//方法一
		Class <? extends StudentDemo> c1=sd1.getClass();
		Class <? extends StudentDemo> c2=sd2.getClass();
		
		System.out.println(sd1==sd2);	//false
		System.out.println(c1==c2);		//true
		
		//方法二
		Class <StudentDemo> c3=StudentDemo.class;
		System.out.println(c3==c2); 	//true
		
		//方法三,必须写class文件的全路径,开发中常用,因为可以将字符串配置到配置文件中
		Class<?> c4=Class.forName("test_class.StudentDemo");
		System.out.println(c4==c2); 	//true
	}
}

2、获取构造方法

测试类

package test02_constructor;

import java.lang.reflect.Constructor;

/*
 * 	通过反射获取构造方法
 * 		反射可以访问私有构造方法,但是需要修改访问权限
 */
public class ConstructorDemo {
	public static void main(String[] args) throws Exception {
		//获取字节码文件对象
		Class<?> c=Class.forName("test_constructor.People");
		
		//获取公共构造方法
		Constructor<?>  [] cons1=c.getConstructors();
		for(Constructor<?> con:cons1) {
			System.out.println(con);
		}
		System.out.println("---------------");
		
		//获取全部构造方法
		Constructor<?>  [] cons2=c.getDeclaredConstructors();
		for(Constructor<?> con:cons2) {
			System.out.println(con);
		}
		
		//获取、并设置单个无参构造方法
		Constructor<?> cons3=c.getConstructor();
		Object obj1=cons3.newInstance();
		System.out.println(obj1);
		
		//获取、并设置带参构造方法
		Constructor<?> cons4=c.getConstructor(String.class,int.class);
		Object obj2=cons4.newInstance("zfliu",18);
		System.out.println(obj2);
		
		//获取、并设置私有构造方法
		Constructor<?> cons5=c.getDeclaredConstructor(int.class);
		//值为true,则指示反射的对象在使用时应该取消Java语言访问检查
		cons5.setAccessible(true);
		Object obj3=cons5.newInstance(20);
		System.out.println(obj3);
	}

}

class文件对象类

package test02_constructor;

public class People {
	private int age;
	private String name;
	
	public People() {
		System.out.println("无参构造方法");
	}
	
	public People(String name,int age) {
		this.age=age;
		this.name=name;
		
	}
	
	People(String name){
		this.name=name;
	}
	
	private People(int age) {
		this.age=age;
	}
	
	public String toString() {
		return "People [age=" + age + ", name=" + name + "]";
	}
	
	People p1=new People(100);
	
}
2、获取成员变量

测试类

package test03_field;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
/*
 * 获取成员变量
 */
public class FiledDemo {
	public static void main(String[] args) throws Exception {
		Class<?> c=Class.forName("test03_field.Student");
		
		//获取公共成员变量
		Field [] f1=c.getFields();
		for(Field f:f1) {
			System.out.println(f);
		}
		System.out.println("------------------------------");
		
		//获取所有成员变量
		Field [] f2=c.getDeclaredFields();
		for(Field f:f2) {
			System.out.println(f);
		}
		System.out.println("------------------------------");
		
		//获取单个公共成员变量
		Field f3=c.getField("name");
		System.out.println(f3);
		
		//设置单个公共成员变量
		//1、获取构造方法
		Constructor<?> con1=c.getConstructor();
		//2、通过构造方法创建对象
		Object obj1=con1.newInstance();
		System.out.println(obj1);
		//3、设置obj1对象中的f3变量的值为"zfliu"
		f3.set(obj1, "zfliu");
		
		System.out.println(obj1);
		System.out.println("------------------------------");
		
		//获取单个私有成员变量
		Field f4=c.getDeclaredField("age");
		
		//设置单个私有成员变量
		//1、获取构造方法
		Constructor<?> con2=c.getConstructor();
		//2、通过构造方法创建对象
		Object obj2=con2.newInstance();
		//3、设置私有变量可以访问的权限
		f4.setAccessible(true);
		//4、设置私有变量
		f4.set(obj2, 18);
		System.out.println(obj2);
		
	}
}

class文件对象类

package test03_field;

public class Student {
	int grade;
	public String name;
	private int age;
	
	public Student() {

	}
	
	@Override
	public String toString() {
		return "Student [grade=" + grade + ", name=" + name + ", age=" + age + "]";
	}
	
	
}

4、获取成员方法

测试类

package test04_method;

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
/*
 * 获取成员方法
 */
public class MethodDemo {
	public static void main(String[] args) throws Exception {
		Class<?> c=Class.forName("test04_method.Student");
		
		//获取自己以及父类的所有公共成员方法
		Method [] m1 =c.getMethods();
		for(Method m:m1) {
			System.out.println(m);
		}
		System.out.println("--------------------------");
		
		//获取自己的所有成员方法
		Method []m2 =c.getDeclaredMethods();
		for(Method m:m2) {
			System.out.println(m);
		}
		
		//获取并设置单个无参、无返回值的成员方法
		Constructor<?> con1=c.getConstructor();
		Object obj1=con1.newInstance();
		Method m3=c.getDeclaredMethod("show");
		m3.invoke(obj1);

		
		//获取并设置单个带参,带返回值的成员方法
		Constructor<?> con2=c.getConstructor( );
		Object obj2=con2.newInstance();
		Method m4=c.getDeclaredMethod("show",String.class);
		String s1=(String) m4.invoke(obj2, "zfliu96");
		System.out.println(s1);
		
		//获取私有成员方法
		//1、通过构造方法调用(构造方法内部有调用)
		Constructor<?> con3=c.getConstructor(Boolean.class);
		con3.newInstance(true);

		//2、通过改变访问权限访问
		Constructor<?> con4=c.getConstructor(Boolean.class);
		Object obj4=con4.newInstance(false);
		Method m5=c.getDeclaredMethod("show1");
		m5.setAccessible(true);
		m5.invoke(obj4);
	}
}

class文件对象类

package test04_method;

public class Student {
	public Student() {
		
	}
	//此构造方法仅是为了解决私有方法如果本类不调用会产生警告的问题
	public Student(Boolean a) {
		if(a.equals(true)) {
			show1();
		}
	}
	public void show() {
		System.out.println("无参无返回值的成员方法");
	}
	public String show(String s) {
		
		System.out.println("带参数带返回值的成员方法");
		return s;
	}
	private void show1() {
		System.out.println("私有成员方法");
	}
	
}

5、通过配置文件运行类中的方法

测试类

package test05_peizhiwenjian;


import java.io.FileReader;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.Properties;

/*
 * 通过配置文件运行类中的方法
 * 
 * 反射:
 * 		需要配置文件配合使用
 * 		用class.txt代替
 */
public class TestDemo {
	public static void main(String[] args) throws Exception {
		Properties prop=new Properties();
		
		FileReader fr=new FileReader("class.txt");
		
		prop.load(fr);
		
		fr.close();
		
		String className=prop.getProperty("className");
		String methodName=prop.getProperty("methodName");
		
		Class<?> c=Class.forName(className);
		Constructor<?> con=c.getConstructor();
		Object obj=con.newInstance();
		
		Method m=c.getMethod(methodName);
		m.invoke(obj);
		
		
	}
}

class文件对象类

package test05_peizhiwenjian;

public class Student {
	public Student() {
		
	}

	public void show() {
		System.out.println("show");
	}
}

配置文件

className=test05_peizhiwenjian.Student
methodName=show

6、通过反射来越过泛型检查
package test06_fanxing;


import java.lang.reflect.Method;
import java.util.ArrayList;

/*
 * 通过反射越过泛型检查
 * 		ArrayList按规定只能存储Integer类型的数据,通过反射可以向其添加String类型数据
 * 		
 */
public class Demo {
	public static void main(String[] args) throws Exception {
		//正常方式添加,只能添加Integer类型数据,能添加int类型是因为自动装箱机制
		ArrayList<Integer> al=new ArrayList<>();
		al.add(10);
		System.out.println(al);
		
		//通过反射添加任意类型的数据
		Class<?> c=al.getClass();
		//由于其已经有al对象,便不需要重新创建新的对象
		Method m=c.getMethod("add", Object.class);
		m.invoke(al, "Hello");
		m.invoke(al, true);
		System.out.println(al);
	}
}

7、代理

测试类

package test07_daili;

import java.lang.reflect.Proxy;

/*
 * 利用反射实现代理动态代理,通过代理对象对原方法进行修改
 */
public class Demo {
	public static void main(String[] args) {
		//通过接口实现类实现方法(只能实现原方法,如果想要改变此方法必须修改原代码)
		Student s=new StudentImpl();
		s.show1();
		s.show2();
		System.out.println("----------------------");
		
		//通过代理对象实现原方法的改变,但是并不改变之前的代码
		//需要一个实现类去个实现接口InvocationHandler
		//对s对象做一个代理对象
		MyInvocationHandler mih=new MyInvocationHandler(s);
		Student s_proxy=(Student)Proxy.newProxyInstance(s.getClass().getClassLoader(), s.getClass().getInterfaces(), mih);
		s_proxy.show1();
		s_proxy.show2();
	}
}

代理类

package test07_daili;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class MyInvocationHandler implements InvocationHandler {
	private Object target;//目标对象 
	
	public MyInvocationHandler(Object target ) {
		this.target=target;
	}
	
	//在与方法关联的代理实例上调用方法时,将在调用处理程序上调用此方法并返回结果
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		//proxy在其上调用方法的实例
		//method对应于在代理实例上调用的接口方法的Method实例
		//args包含传入代理实例上方法调用的参数值的对象数组
		System.out.println("权限检查");
		Object result =method.invoke(target, args);
		System.out.println("日志记录");
		return result;
	}

}

原接口类

package test07_daili;

public interface Student {
	public abstract void show1();
	public abstract void show2();
}

接口实现类

package test07_daili;

public class StudentImpl implements Student {

	@Override
	public void show1() {
		System.out.println("show1");
		
	}

	@Override
	public void show2() {
		System.out.println("show2");		
	}
	
}

你可能感兴趣的:(java)