java反射机制&动态代理

综合各个博客主的帖子而来,感谢以下博主!

java反射机制详解:http://www.cnblogs.com/lzq198754/p/5780331.html

java中的反射机制:http://blog.csdn.net/liujiahan629629/article/details/18013523

java中的动态代理详解:http://www.cnblogs.com/xiaoluo501395377/p/3383130.html

反射机制

1.反射机制的定义

反射机制是在运行状态中,对于任意一个类,都能够获得这个类的状态,能够访问,检测和修改它本身状态或者行为的一种能力。并能根据自身行为的状态和结果,调整或修改应用所描述行为的状态和相关的语义。简单来讲,就是对于任意一个类,都能在运行状态下,获得这个类的所有属性和方法;对于任何一个对象,都能够调用它的任意一个方法和属性。

2.反射机制能做什么?

  • 反编译 .class->.java
  • 通过反射机制访问对象的方法,属性等;
  • 运行时判断任意一个对象所属的类;
  • 运行时构造任意一个类的对象;
  • 运行时调用任意一个对象的方法;
  • 生成动态代理等;

反射机制非常强大,几乎可以不创建对象而调用另外一个对象所有东西,对应的也就有了下面的例子。可以调用的功能如下:

  • 获得一个对象的类Class
  • 获得这个Class之后可以获得这个类的所有的属性(返回Field数组,getDeclaredFields())以及属性相关的名字等,并设置相关的属性
  • 获得这个Class之后可以获得这个类的单个属性(返回Field对象,getDeclareField(String name))
  • 获得这个Class之后可以获得这个类的所有的f方法(返回Method数组,getMethods())
  • 获得这个Class之后可以获得这个类的单个方法(返回Method对象,getMethod(String methodNAME,Parameter.class)如果有参数,Parameter.class)
  • 获得方法的参数情况(返回Parameter[]数组,或者返回单个Paratmeter),类似于上面的情况
  • 获得这个Class之后可以获得这个类的所有的构造函数(返回Constructor数组,getContructors())
  • 获得这个Class之后可以获得这个类的单个构造函数,不写了,自己看api去吧,反正很多。
  • 反射机制对数组进行操作Array类的很多静态方法
  • 反射机制进行动态代理

3.反射机制的类以及API

java.lang.Class;

java.lang.reflect.Constructor;

java.lang.reflect.Field;

java.lang.reflec.Method;

java.lang.reflect.Modifier;

API我们通过一些例子来看

获得一个对象的完整的包名和类名以及类加载器

 
  1. public class TestReflectGetClassName {

  2.  
  3. public static void main(String[] args) {

  4. // TODO Auto-generated method stub

  5. TestReflectGetClassName t = new TestReflectGetClassName();

  6. System.out.println(t.getClass().getName()+" "+t.getClass().getClassLoader());

  7. }

  8.  
  9. }

获取类,注意是类

 
  1. public class TestReflectGetClass {

  2. public void getClasses() throws ClassNotFoundException{

  3. //第一种方式,使用注册的方式

  4. Class c1 = Class.forName("TestReflectGetClass");

  5.  
  6. //第二种方式,使用每个类里面自带的class属性

  7. Class c2 = TestReflectGetClassName.class;

  8.  
  9. //第三种方式,每个对象的getClass方法

  10. TestReflectGetClassName t = new TestReflectGetClassName();

  11. Class c3 = t.getClass();

  12. }

  13.  
  14. }

实例化Class类对象

 
  1. //先使用任意一种方式获得类,比如使用注册的方式

  2. Class c1 = Class.forName("TestReflectGetClass");

  3. //然后调用newInstance()方法

  4. Object trg = c1.newInstance();

获取属性,其实第一个后去class名和加载器的方式也算是获得属性的方式;

包括获得父类,获得接口(getInterfaces()),获得所有的方法,获得所有的参数等

 
  1. public class TestReflectGetClassName {

  2. int a=0;

  3. int b=2;

  4. String s = "1";

  5.  
  6. public static void main(String[] args) throws ClassNotFoundException, IllegalArgumentException, IllegalAccessException {

  7. // TODO Auto-generated method stub

  8. //获得当前类的名字和类加载器

  9. TestReflectGetClassName t = new TestReflectGetClassName();

  10. System.out.println(t.getClass().getName()+" "+t.getClass().getClassLoader());

  11.  
  12. Class<?> c = Class.forName("javaReflection.TestReflectGetClassName");

  13. //获得父类

  14. Class<?> parent = c.getSuperclass();

  15. System.out.println("parent's name"+parent.getName());

  16. //获得所有属性的名字

  17. Field[] fs = c.getDeclaredFields();

  18.  
  19. for(Field f:fs){

  20. //获得当前域的类型

  21. System.out.print("type:"+f.getType().getName()+" ");

  22. //获得当前这个域的名字,a/b/s

  23. System.out.print("name:"+f.getName()+" ");

  24. //获得对象t的当前这个域的值,也可以是其他同类型对象

  25. System.out.println("value:"+f.get(t));

  26. //修改当前对象的值t,由于不是同一类型,所以只能修改为原来的值

  27. f.set(t, f.get(t));

  28. }

  29. System.out.println("--------------");

  30. //获得所有的方法

  31. Method[] ms = c.getMethods();

  32. for(Method m:ms){

  33. //获得方法名

  34. System.out.print("name:"+m.getName()+" ");

  35. //获得返回类型

  36. System.out.print("returType:"+m.getReturnType()+" ");

  37. //获得参数个数

  38. System.out.println("parameters number:"+m.getParameterCount());

  39. }

  40. }

  41.  
  42. public int getA() {

  43. return a;

  44. }

  45.  
  46. public void setA(int a) {

  47. this.a = a;

  48. }

  49.  
  50. public int getB() {

  51. return b;

  52. }

  53.  
  54. public void setB(int b) {

  55. this.b = b;

  56. }

  57.  
  58. public String getS() {

  59. return s;

  60. }

  61.  
  62. public void setS(String s) {

  63. this.s = s;

  64. }

  65. }

通过反射机制获取全部的构造函数并使用构造函数初始化对象

 
  1. public class TestReflect {

  2. public static void main(String[] args) throws Exception {

  3. Class<?> class1 = null;

  4. class1 = Class.forName("javaReflection.User");

  5. // 第一种方法,实例化默认构造方法,调用set赋值

  6. User user = (User) class1.newInstance();

  7. user.setAge(20);

  8. user.setName("Rollen");

  9. System.out.println(user);

  10. // 结果 User [age=20, name=Rollen]

  11. // 第二种方法 取得全部的构造函数 使用构造函数赋值

  12. Constructor<?> cons[] = class1.getConstructors();

  13. // 查看每个构造方法需要的参数

  14. for (int i = 0; i < cons.length; i++) {

  15. Class<?> clazzs[] = cons[i].getParameterTypes();

  16. System.out.print("cons[" + i + "] (");

  17. for (int j = 0; j < clazzs.length; j++) {

  18. if (j == clazzs.length - 1)

  19. System.out.print(clazzs[j].getName());

  20. else

  21. System.out.print(clazzs[j].getName() + ",");

  22. }

  23. System.out.println(")");

  24. }

  25. // 结果

  26. // cons[0] (int,java.lang.String)

  27. // cons[1] (java.lang.String)

  28. // cons[2] ()

  29. //这里必须按照前面的结果顺序来。

  30. user = (User) cons[0].newInstance(20,"Rollen");

  31. System.out.println(user);

  32. // 结果 User [age=0, name=Rollen]

  33. user = (User) cons[1].newInstance( "Rollen");

  34. System.out.println(user);

  35. // 结果 User [age=20, name=Rollen]

  36. }

  37. }

  38. class User {

  39. private int age;

  40. private String name;

  41. public User() {

  42. super();

  43. }

  44. public User(String name) {

  45. super();

  46. this.name = name;

  47. }

  48. public User(int age, String name) {

  49. super();

  50. this.age = age;

  51. this.name = name;

  52. }

  53. public int getAge() {

  54. return age;

  55. }

  56. public void setAge(int age) {

  57. this.age = age;

  58. }

  59. public String getName() {

  60. return name;

  61. }

  62. public void setName(String name) {

  63. this.name = name;

  64. }

  65. @Override

  66. public String toString() {

  67. return "User [age=" + age + ", name=" + name + "]";

  68. }

  69. }

4.反射机制实战

在泛型Integer的ArrayList中存放一个String类型的对象

 
  1. public class TestReflect {

  2. public static void main(String[] args) throws Exception {

  3. ArrayList<Integer> list = new ArrayList<Integer>();

  4. Method method = list.getClass().getMethod("add", Object.class);

  5. method.invoke(list, "Java反射机制实例。");

  6. System.out.println(list.get(0));

  7. }

  8. }

通过反射机制取得并修改数组的信息

 
  1. public class TestReflect3 {

  2. /*执行结果

  3. * 数组类型: int

  4. * 数组长度 5

  5. * 数组的第一个元素: 1

  6. * 修改之后数组第一个元素为: 100

  7. */

  8.  
  9. public static void main(String[] args) {

  10. // TODO Auto-generated method stub

  11. int[] array = {1,2,3,4,5};

  12. Class<?> cl = array.getClass().getComponentType();

  13. System.out.println("数组类型: " + cl.getName());

  14. System.out.println("数组长度 " + Array.getLength(array));

  15. System.out.println("数组的第一个元素: " + Array.get(array, 0));

  16. Array.set(array, 0, 100);

  17. System.out.println("修改之后数组第一个元素为: " + Array.get(array, 0));

  18. }

  19. }

通过反射机制修改数组大小

 
  1. /*

  2. * 数组长度为: 15

  3. *1 2 3 4 5 6 7 8 9 0 0 0 0 0 0

  4. *数组长度为: 8

  5. *a b c null null null null null

  6. */

  7.  
  8. public class TestReflect4 {

  9. public static void main(String[] args) throws Exception {

  10. int[] temp = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };

  11. int[] newTemp = (int[]) arrayInc(temp, 15);

  12. print(newTemp);

  13. String[] atr = { "a", "b", "c" };

  14. String[] str1 = (String[]) arrayInc(atr, 8);

  15. print(str1);

  16. }

  17. // 修改数组大小

  18. public static Object arrayInc(Object obj, int len) {

  19. Class<?> arr = obj.getClass().getComponentType();

  20. Object newArr = Array.newInstance(arr, len);

  21. int co = Array.getLength(obj);

  22. System.arraycopy(obj, 0, newArr, 0, co);

  23. return newArr;

  24. }

  25. // 打印

  26. public static void print(Object obj) {

  27. Class<?> c = obj.getClass();

  28. if (!c.isArray()) {

  29. return;

  30. }

  31. System.out.println("数组长度为: " + Array.getLength(obj));

  32. for (int i = 0; i < Array.getLength(obj); i++) {

  33. System.out.print(Array.get(obj, i) + " ");

  34. }

  35. System.out.println();

  36. }

  37. }


 

动态代理--基于反射机制

在学习Spring的时候,我们知道Spring主要有两大思想,一个是IoC,另一个就是AOP,对于IoC,依赖注入就不用多说了,而对于Spring的核心AOP来说,我们不但要知道怎么通过AOP来满足的我们的功能,我们更需要学习的是其底层是怎么样的一个原理,而AOP的原理就是java的动态代理机制,所以本篇随笔就是对java的动态机制进行一个回顾。

在java的动态代理机制中,有两个重要的类或接口,一个是 InvocationHandler(Interface)、另一个则是 Proxy(Class),这一个类和接口是实现我们动态代理所必须用到的。

 
  1. public interface Subject

  2. {

  3. public void doSomething();

  4. }

  5. public class RealSubject implements Subject

  6. {

  7. public void doSomething()

  8. {

  9. System.out.println( "call doSomething()" );

  10. }

  11. }

  12. public class ProxyHandler implements InvocationHandler

  13. {

  14. private Object proxied;

  15.  
  16. public ProxyHandler( Object proxied )

  17. {

  18. this.proxied = proxied;

  19. }

  20.  
  21. public Object invoke( Object proxy, Method method, Object[] args ) throws Throwable

  22. {

  23. //在转调具体目标对象之前,可以执行一些功能处理

  24.  
  25. //转调具体目标对象的方法

  26. return method.invoke( proxied, args);

  27.  
  28. //在转调具体目标对象之后,可以执行一些功能处理

  29. }

  30. }

 
  1. import java.lang.reflect.InvocationHandler;

  2. import java.lang.reflect.Method;

  3. import java.lang.reflect.Proxy;

  4. import sun.misc.ProxyGenerator;

  5. import java.io.*;

  6. public class DynamicProxy

  7. {

  8. public static void main( String args[] )

  9. {

  10. RealSubject real = new RealSubject();

  11. Subject proxySubject = (Subject)Proxy.newProxyInstance(Subject.class.getClassLoader(),

  12. new Class[]{Subject.class},

  13. new ProxyHandler(real));

  14.  
  15. proxySubject.doSomething();

  16.  
  17. //write proxySubject class binary data to file

  18. createProxyClassFile();

  19. }

  20.  
  21. public static void createProxyClassFile()

  22. {

  23. String name = "ProxySubject";

  24. byte[] data = ProxyGenerator.generateProxyClass( name, new Class[] { Subject.class } );

  25. try

  26. {

  27. FileOutputStream out = new FileOutputStream( name + ".class" );

  28. out.write( data );

  29. out.close();

  30. }

  31. catch( Exception e )

  32. {

  33. e.printStackTrace();

  34. }

  35. }

  36. }

总的来说,proxy生成了一个关于指定定对象(real)的代理对象(proxySubject),这个对象继承了proxy,同时实现了被代理对象(上述的RealSubject类的对象)的所有接口(Subject接口)。因此这个代理对象能够调用被代理对象的所有方法(被代理对象的非接口实现方法无法调用,也算是个缺陷吧),调用这个方法的步骤是 proxySubject调用doSomething方法,这个doSomething 方法调用InvocatoinHandler的invoke方法,invoke方法通过method参数和一开始初始化的代理对象real调用real的doSomething方法。就是这样。

具体的实现比较难理解,源代码涉及到非常复杂的情况,有空再看。

猜你喜欢

转载自blog.csdn.net/weixin_38503885/article/details/82019789
今日推荐