反射技术

 * 反射:就是通过class文件对象,去使用该文件中的成员变量,构造方法,成员方法。

* 获取class文件对象的方式:
* A:Object类的getClass()方法
* B:数据类型的静态属性class
* C:Class类中的静态方法
* public static Class forName(String className)

1         // 方式3
2         // ClassNotFoundException
3         Class c4 = Class.forName("cn.itcast_01.Person");
4         System.out.println(c == c4);

 * 通过反射获取构造方法并使用。

 1         // 获取字节码文件对象
 2         Class c = Class.forName("cn.itcast_01.Person");
 3 
 4         // 获取构造方法
 5         // public Constructor[] getConstructors():所有公共构造方法
 6         // public Constructor[] getDeclaredConstructors():所有构造方法
 7         // Constructor[] cons = c.getDeclaredConstructors();
 8         // for (Constructor con : cons) {
 9         // System.out.println(con);
10         // }
11 
12         // 获取单个构造方法
13         // public Constructor<T> getConstructor(Class<?>... parameterTypes)
14         // 参数表示的是:你要获取的构造方法的构造参数个数及数据类型的class字节码文件对象
15         Constructor con = c.getConstructor();// 返回的是构造方法对象
16 
17         // Person p = new Person();
18         // System.out.println(p);
19         // public T newInstance(Object... initargs)
20         // 使用此 Constructor 对象表示的构造方法来创建该构造方法的声明类的新实例,并用指定的初始化参数初始化该实例。
21         Object obj = con.newInstance();
22         System.out.println(obj);

* 需求:通过反射去获取该构造方法并使用:
* public Person(String name, int age, String address)
*
* Person p = new Person("林青霞",27,"北京");
* System.out.println(p);

 1         // 获取字节码文件对象
 2         Class c = Class.forName("cn.itcast_01.Person");
 3 
 4         // 获取带参构造方法对象
 5         // public Constructor<T> getConstructor(Class<?>... parameterTypes)
 6         Constructor con = c.getConstructor(String.class, int.class,
 7                 String.class);
 8 
 9         // 通过带参构造方法对象创建对象
10         // public T newInstance(Object... initargs)
11         Object obj = con.newInstance("林青霞", 27, "北京");
12         
13         System.out.println(obj);

* 需求:通过反射获取私有构造方法并使用
* private Person(String name){}
*
* Person p = new Person("风清扬");
* System.out.println(p);

 1         // 获取字节码文件对象
 2         Class c = Class.forName("cn.itcast_01.Person");
 3 
 4         // 获取私有构造方法对象
 5         // NoSuchMethodException:每个这个方法异常
 6         // 原因是一开始我们使用的方法只能获取公共的,下面这种方式就可以了。
 7         Constructor con = c.getDeclaredConstructor(String.class);
 8 
 9         // 用该私有构造方法创建对象
10         // IllegalAccessException:非法的访问异常。
11         // 暴力访问
12         con.setAccessible(true);// 值为true则指示反射的对象在使用时应该取消Java语言访问检查。
13         Object obj = con.newInstance("风清扬");
14 
15         System.out.println(obj);

 * 通过发生反射成员变量并使用

 1         // 获取字节码文件对象
 2         Class c = Class.forName("cn.itcast_01.Person");
 3 
 4         // 获取所有的成员变量
 5         // Field[] fields = c.getFields();
 6         // Field[] fields = c.getDeclaredFields();
 7         // for (Field field : fields) {
 8         // System.out.println(field);
 9         // }
10 
11         /*
12          * Person p = new Person(); p.address = "北京"; System.out.println(p);
13          */
14 
15         // 通过无参构造方法创建对象
16         Constructor con = c.getConstructor();
17         Object obj = con.newInstance();
18         System.out.println(obj);
19 
20         // 获取单个的成员变量
21         // 获取address并对其赋值
22         Field addressField = c.getField("address");
23         // public void set(Object obj,Object value)
24         // 将指定对象变量上此 Field 对象表示的字段设置为指定的新值。
25         addressField.set(obj, "北京"); // 给obj对象的addressField字段设置值为"北京"
26         System.out.println(obj);
27 
28         // 获取name并对其赋值
29         // NoSuchFieldException
30         Field nameField = c.getDeclaredField("name");
31         // IllegalAccessException
32         nameField.setAccessible(true);
33         nameField.set(obj, "林青霞");
34         System.out.println(obj);
35 
36         // 获取age并对其赋值
37         Field ageField = c.getDeclaredField("age");
38         ageField.setAccessible(true);
39         ageField.set(obj, 27);
40         System.out.println(obj);

 * 通过发生反射成员方法并使用

 1         // 获取字节码文件对象
 2         Class c = Class.forName("cn.itcast_01.Person");
 3 
 4         // 获取所有的方法
 5         // Method[] methods = c.getMethods(); // 获取自己的包括父亲的公共方法
 6         // Method[] methods = c.getDeclaredMethods(); // 获取自己的所有的方法
 7         // for (Method method : methods) {
 8         // System.out.println(method);
 9         // }
10 
11         Constructor con = c.getConstructor();
12         Object obj = con.newInstance();
13 
14         /*
15          * Person p = new Person(); p.show();
16          */
17 
18         // 获取单个方法并使用
19         // public void show()
20         // public Method getMethod(String name,Class<?>... parameterTypes)
21         // 第一个参数表示的方法名,第二个参数表示的是方法的参数的class类型
22         Method m1 = c.getMethod("show");
23         // obj.m1(); // 错误
24         // public Object invoke(Object obj,Object... args)
25         // 返回值是Object接收,第一个参数表示对象是谁,第二参数表示调用该方法的实际参数
26         m1.invoke(obj); // 调用obj对象的m1方法
27 
28         System.out.println("----------");
29         // public void method(String s)
30         Method m2 = c.getMethod("method", String.class);
31         m2.invoke(obj, "hello");
32         System.out.println("----------");
33 
34         // public String getString(String s, int i)
35         Method m3 = c.getMethod("getString", String.class, int.class);
36         Object objString = m3.invoke(obj, "hello", 100);
37         System.out.println(objString);
38         // String s = (String)m3.invoke(obj, "hello",100);
39         // System.out.println(s);
40         System.out.println("----------");
41 
42         // private void function()
43         Method m4 = c.getDeclaredMethod("function");
44         m4.setAccessible(true);
45         m4.invoke(obj);

* 通过配置文件运行类中的方法
*
* 反射:
* 需要有配置文件配合使用。
* 用class.txt代替。
* 并且你知道有两个键。
* className
* methodName

 1         // 反射前的做法
 2         // Student s = new Student();
 3         // s.love();
 4         // Teacher t = new Teacher();
 5         // t.love();
 6         // Worker w = new Worker();
 7         // w.love();
 8         // 反射后的做法
 9 
10         // 加载键值对数据
11         Properties prop = new Properties();
12         FileReader fr = new FileReader("class.txt");
13         prop.load(fr);
14         fr.close();
15 
16         // 获取数据
17         String className = prop.getProperty("className");
18         String methodName = prop.getProperty("methodName");
19 
20         // 反射
21         Class c = Class.forName(className);
22 
23         Constructor con = c.getConstructor();
24         Object obj = con.newInstance();
25 
26         // 调用方法
27         Method m = c.getMethod(methodName);
28         m.invoke(obj);

 * 我给你ArrayList<Integer>的一个对象,我想在这个集合中添加一个字符串数据,如何实现呢?

 1         // 创建集合对象
 2         ArrayList<Integer> array = new ArrayList<Integer>();
 3 
 4         // array.add("hello");
 5         // array.add(10);
 6 
 7         Class c = array.getClass(); // 集合ArrayList的class文件对象
 8         Method m = c.getMethod("add", Object.class);
 9 
10         m.invoke(array, "hello"); // 调用array的add方法,传入的值是hello
11         m.invoke(array, "world");
12         m.invoke(array, "java");
13 
14         System.out.println(array);

通过反射写一个通用的设置某个对象的某个属性为指定的值:

 1     public void setProperty(Object obj, String propertyName, Object value)
 2             throws NoSuchFieldException, SecurityException,
 3             IllegalArgumentException, IllegalAccessException {
 4         // 根据对象获取字节码文件对象
 5         Class c = obj.getClass();
 6         // 获取该对象的propertyName成员变量
 7         Field field = c.getDeclaredField(propertyName);
 8         // 取消访问检查
 9         field.setAccessible(true);
10         // 给对象的成员变量赋值为指定的值
11         field.set(obj, value);
12     }

动态代理:

 1 public class MyInvocationHandler implements InvocationHandler {
 2     private Object target; // 目标对象
 3 
 4     public MyInvocationHandler(Object target) {
 5         this.target = target;
 6     }
 7 
 8     @Override
 9     public Object invoke(Object proxy, Method method, Object[] args)
10             throws Throwable {
11         System.out.println("权限校验");
12         Object result = method.invoke(target, args);
13         System.out.println("日志记录");
14         return result; // 返回的是代理对象
15     }
16 }
 1     public static void main(String[] args) {
 2         UserDao ud = new UserDaoImpl();
 3         ud.add();
 4         ud.delete();
 5         ud.update();
 6         ud.find();
 7         System.out.println("-----------");
 8         // 我们要创建一个动态代理对象
 9         // Proxy类中有一个方法可以创建动态代理对象
10         // public static Object newProxyInstance(ClassLoader loader,Class<?>[]
11         // interfaces,InvocationHandler h)
12         // 我准备对ud对象做一个代理对象
13         MyInvocationHandler handler = new MyInvocationHandler(ud);
14         UserDao proxy = (UserDao) Proxy.newProxyInstance(ud.getClass()
15                 .getClassLoader(), ud.getClass().getInterfaces(), handler);
16         proxy.add();
17         proxy.delete();
18         proxy.update();
19         proxy.find();
20         System.out.println("-----------");
21 
22         StudentDao sd = new StudentDaoImpl();
23         MyInvocationHandler handler2 = new MyInvocationHandler(sd);
24         StudentDao proxy2 = (StudentDao) Proxy.newProxyInstance(sd.getClass()
25                 .getClassLoader(), sd.getClass().getInterfaces(), handler2);
26         proxy2.login();
27         proxy2.regist();
28     }
原文地址:https://www.cnblogs.com/samuraihuang/p/10057793.html