Java语言的反射机制 笔记 摘自 http://blog.csdn.net/kaoa000/article/details/8453371

在Java运行时环境中,对于任意一个类,能否知道这个类有哪些属性和方法?对于任意一个对象,能否调用它的任意一个方法?答案是肯定的。这种动态获取类的信息以及动态调用对象的方法的功能来自于Java 语言的反射(Reflection)机制。

1、Java 反射机制主要提供了以下功能:

在运行时判断任意一个对象所属的类。
在运行时构造任意一个类的对象。
在运行时判断任意一个类所具有的成员变量和方法。
在运行时调用任意一个对象的方法

2、Reflection 是Java被视为动态(或准动态)语言的一个关键性质。这个机制允许程序在运行时透过Reflection APIs取得任何一个已知名称的class的内部信息,包括其modifiers(诸如public, static 等等)、superclass(例如Object)、实现之interfaces(例如Serializable),也包括fields和methods的所有信息,并可于运行时改变fields内容或调用methods

尽管Java不是动态语言,它却有着一个非常突出的动态相关机制:Reflection。这个字的意思是“反射、映象、倒影”,用在Java身上指的是我们可以于运行时加载、探知、使用编译期间完全未知的classes。换句话说,Java程序可以加载一个运行时才得知名称的class,获悉其完整构造(但不包括methods定义),并生成其对象实体、或对其fields设值、或唤起其methods。这种“看透class”的能力(the ability of the program to examine itself)被称为introspection(内省、内观、反省)。Reflection和introspection是常被并提的两个术语

java中,无论生成某个类的多少个对象(实例),这些对象都会对应同一个Class对象。

3、在JDK中,主要由以下类来实现Java反射机制,这些类都位于java.lang.reflect包中
    –Class类:代表一个类(这个类很特殊,位于java.lang包下)。
    –Field 类:代表类的成员变量(成员变量也称为类的属性)。
    –Method类:代表类的方法。
    –Constructor 类:代表类的构造方法。
    –Array类:提供了动态创建数组,以及访问数组的元素的静态方法

使用反射生成对象和调用方法:

[java] view plain copy

  1. import java.lang.reflect.Method;
  2. public class InvokeTester
  3. {
  4. public int add(int param1,int param2)
  5. {
  6. return param1 + param2;
  7. }
  8. public String echo(String message)
  9. {
  10. return "hello : " + message;
  11. }
  12. public static void main(String[] args) throws Exception
  13. {
  14. Class<?> classType = InvokeTester.class;
  15. Object invokeTester = classType.newInstance();
  16. Method addMethod = classType.getMethod("add", new Class[]{int.class,int.class});
  17. Object result = addMethod.invoke(invokeTester, new Object[]{1,2});
  18. System.out.println((Integer)result);
  19. System.out.println("----------");
  20. Method echoMethod = classType.getMethod("echo", new Class[]{String.class});
  21. Object result1 = echoMethod.invoke(invokeTester, new Object[]{"world"});
  22. System.out.println((String)result1);
  23. }
  24. }

使用反射调用方法的步骤:

a)要想使用反射,首先需要获得待处理类或对象所对应的Class对象。

b)获取某个类或某个对象所对应的Class对象的常用的3种方式:

1)使用Class类的静态方法forName,Class.forName(“java.lang.String”)

2)使用类的.class语法:String.class,如这个例子中的Class<?> classType = InvokeTester.class;

3)使用对象的getClass()方法:String s = “aa”;Class<?> clazz=s.getClass();

c)通过获取的Class对象,产生一个实例

d)获得想要调用方的Method对象,如Method addMethod = classType.getMethod("add", new Class[]{int.class,int.class});

e)通过获得的Method对象,在特定实例(对象)上调用方法:Object result = addMethod.invoke(invokeTester, new Object[]{1,2});

4、Class的newInstance()方法相当于调用不带参数的构造方法来构建对象,如果构造方法带参数,就不能使用这种方法。

使用反射实现对象拷贝的程序:

[java] view plain copy

  1. import java.lang.reflect.Constructor;
  2. import java.lang.reflect.Field;
  3. import java.lang.reflect.Method;
  4. public class ReflectTester
  5. {
  6. // 该方法实现对Custmoer对象的拷贝
  7. public Object copy(Object object) throws Exception
  8. {
  9. Class<?> classType = object.getClass();
  10. // Constructor cons = classType.getConstructor(new Class[]{});
  11. //
  12. // Object obj = cons.newInstance(new Object[]{});
  13. // 以上两行代码等价于下面一行,不带参数
  14. // Object obj2 = classType.newInstance();
  15. Object objectCopy = classType.getConstructor(new Class[] {}).newInstance(new Object[] {});
  16. Field[] fields = classType.getDeclaredFields();
  17. for (Field field : fields)
  18. {
  19. String name = field.getName();
  20. String firstLetter = name.substring(0, 1).toUpperCase();
  21. String getMethodName = "get" + firstLetter + name.substring(1);
  22. String setMethodName = "set" + firstLetter + name.substring(1);
  23. Method getMethod = classType.getMethod(getMethodName,new Class[] {});
  24. Method setMethod = classType.getMethod(setMethodName,new Class[] { field.getType() });
  25. Object value = getMethod.invoke(object, new Object[] {});
  26. setMethod.invoke(objectCopy, new Object[] { value });
  27. }
  28. return objectCopy;
  29. }
  30. public static void main(String[] args) throws Exception
  31. {
  32. Customer cu = new Customer("tom", 30);
  33. cu.setId(1L);
  34. ReflectTester test = new ReflectTester();
  35. Customer cu1 = (Customer) test.copy(cu);
  36. System.out.println(cu1.getId() + cu1.getName() + cu1.getAge());
  37. }
  38. }
  39. class Customer
  40. {
  41. private Long id;
  42. private String name;
  43. private int age;
  44. public Customer()
  45. {
  46. }
  47. public Customer(String name, int age)
  48. {
  49. this.name = name;
  50. this.age = age;
  51. }
  52. public Long getId()
  53. {
  54. return id;
  55. }
  56. public void setId(Long id)
  57. {
  58. this.id = id;
  59. }
  60. public String getName()
  61. {
  62. return name;
  63. }
  64. public void setName(String name)
  65. {
  66. this.name = name;
  67. }
  68. public int getAge()
  69. {
  70. return age;
  71. }
  72. public void setAge(int age)
  73. {
  74. this.age = age;
  75. }
  76. }

    若想通过类的不带参数的构造方法来生成对象,两种方式:

1)先获得Class对象,然后通过该Class对象的newInstance()方法直接生成即可:

Class<?> classType=String.class;

Object obj=classType.newInstance();

2)先获得Class对象,然后通过该对象获得对应的Constructor对象,再通过该Constructor对象的newInstance()方法生成:

Class<?> classType = Customer.class;

Constructor cons =classType.getConstructor(new Class[]{});

Object obj = cons.newInstance(new Object[]{})

   若想通过类的带参数的构造方法生成对象,只能使用下面一种方式:

Class<?> classType = Customer.class;

Constructor cons =classType.getConstructor(new Class[]{String.class,int.class});

Object obj = cons.newInstance(new Object[]{“hello”,4});

5、在java.lang.Object类中定义了getClass()方法,因此对于任意一个Java对象,都可以通过此方法获得对象的类型。Class类是Reflection API 中的核心类,它有以下方法
    –getName():获得类的完整名字。
    –getFields():获得类的public类型的属性。
    –getDeclaredFields():获得类的所有属性。
    –getMethods():获得类的public类型的方法。
    –getDeclaredMethods():获得类的所有方法。

- getMethod(String name, Class[] parameterTypes):获得类的特定方法,name参数指定方法的名字,parameterTypes参数指定方法的参数类型。
    - getConstructors():获得类的public类型的构造方法。
    - getConstructor(Class[] parameterTypes):获得类的特定构造方法,parameterTypes参数指定构造方法的参数类型。
    - newInstance():通过类的不带参数的构造方法创建这个类的一个对象。

6、关于java.lang.reflect.Array类,Array 类提供了动态创建和访问数组元素的各种静态方法。

[java] view plain copy

  1. import java.lang.reflect.Array;
  2. public class ArrayTest
  3. {
  4. public static void main(String[] args) throws Exception
  5. {
  6. Class<?> classType = Class.forName("java.lang.String");
  7. Object array = Array.newInstance(classType,10);
  8. Array.set(array,5,"hello");
  9. String str = (String)Array.get(array,5);
  10. System.out.println(str);
  11. }
  12. }

Array类提供了newInstance方法,对于一维数组,第一个参数相当于数组中元素的类型,第二个参数是数组的长度。set方法用于给特定数组对象的第几个元素赋值。

7、Integer.Type返回的是int,而Integer.class返回的是Integer类所对应的Class对象:java.lang.Integer

对于多维数组

[java] view plain copy

  1. import java.lang.reflect.Array;
  2. public class ArrayTest2
  3. {
  4. public static void main(String[] args)
  5. {
  6. int[] dims =new int[]{5,10,15};
  7. Object array = Array.newInstance(Integer.TYPE,dims);
  8. Object arrayObj = Array.get(array,3);
  9. //Class<?> classType = arrayObj.getClass().getComponentType();
  10. arrayObj = Array.get(arrayObj,5);
  11. Array.set(arrayObj,10,34);
  12. int[][][] arrayCast = (int[][][])array;
  13. System.out.println(arrayCast[3][5][10]);
  14. }
  15. }

Array.newInstance(Integer.TYPE,dims);相当于定义了一个多维数组,数组的维度使用一个int数组指定,这里是dims,也就是说arra是一个三维数组,维度分别是5,10,15,

Object arrayObj = Array.get(array,3);是取array数组的第一维的下标为3的对象,返回一个二维数组,arrayObj = Array.get(arrayObj,5);就是取二维数组的下标为5的一行,得到一维数组,Array.set(arrayObj,10,34);设置一维数组的下标10位置元素为34。array就是一个三维数组,所以可以转换。

8、对私有方法的访问

[java] view plain copy

  1. public class Private2
  2. {
  3. private String name = "zhangsan";
  4. public String getName()
  5. {
  6. return this.name;
  7. }
  8. }
  9. public class TestPrivate2
  10. {
  11. public static void main(String[] args) throws Exception
  12. {
  13. Private2 p = new Private2();
  14. Class<?> classType = p.getClass();
  15. Field field = classType.getDeclaredField("name");
  16. field.setAccessible(true);
  17. field.set(p,"lisi");
  18. String str = p.getName();
  19. System.out.println(str);
  20. }
  21. }
  22. 对私有方法进行调用时,必须使用method.setAccessible(true)来禁止java虚拟机对此对象进行的java访问规则检查,如果不设置,默认就是setAccessible(falsse),将执行Java访问规则检查,这时外部类是不能访问类内部的私有方法的,所以会报错。

[java] view plain copy

对私有成员变量的访问:

[java] view plain copy

  1. public class TestPrivate2
  2. {
  3. public static void main(String[] args) throws Exception
  4. {
  5. Private2 p = new Private2();
  6. Class<?> classType = p.getClass();
  7. Field field = classType.getDeclaredField("name");
  8. field.setAccessible(true);
  9. field.set(p,"lisi");
  10. String str = p.getName();
  11. System.out.println(str);
  12. }
  13. }
  14. public class Private2
  15. {
  16. private String name = "zhangsan";
  17. public String getName()
  18. {
  19. return this.name;
  20. }
  21. }
 
9、关于Class class(Class类)
众所周知Java有个Object class,是所有Java classes的继承根源,其内声明了数个methods:hashCode()、equals()、clone()、toString()、getClass()等。其中getClass()返回一个Class object。Class class十分特殊。它和一般classes一样继承自Object,其实体用以表达Java程序运行时的classes和interfaces,也用来表达enum、array、primitive Java types(boolean, byte, char, short, int, long, float, double)以及关键词void。当一个class被加载,或当加载器(class loader)的defineClass()被JVM调用,JVM 便自动产生一个Class object。如果您想借由“修改Java标准库源码”来观察Class object的实际生成时机(例如在Class的constructor内添加一个println()),不能够!因为Class并没有public constructor
Class是Reflection起源。针对任何您想探勘的class,唯有先为它产生一个Class object,接下来才能经由后者唤起为数十多个的Reflection APIs
Class的getSuperclass()返回类的父类的Class对象。
时间: 2024-10-17 14:23:21

Java语言的反射机制 笔记 摘自 http://blog.csdn.net/kaoa000/article/details/8453371的相关文章

转:Java面试题集(51-70) http://blog.csdn.net/jackfrued/article/details/17403101

Java面试题集(51-70) Java程序员面试题集(51-70) http://blog.csdn.net/jackfrued/article/details/17403101 摘要:这一部分主要讲解了异常.多线程.容器和I/O的相关面试题.首先,异常机制提供了一种在不打乱原有业务逻辑的前提下,把程序在运行时可能出现的状况处理掉的优雅的解决方案,同时也是面向对象的解决方案.而Java的线程模型是建立在共享的.默认的可见的可变状态以及抢占式线程调度两个概念之上的.Java内置了对多线程编程的支

Consul+upsync+Nginx实现动态负载均衡 摘自https://blog.csdn.net/qq_29247945/article/details/80787014

传统感念:每次修改完nginx配置文件,要重启nginx 动态感念:每次修改完nginx配置信息,不需要重启,nginx实时读取配置信息. Nginx: 反向代理和负载均衡 Consul:是用go编写(谷歌),实现对动态负载均衡注册与发现功能 SpringCloud支持  Zookeeper.Eureka.Consul服务注册与发现. 服务注册:服务实现者可以通过HTTP API或DNS方式,将服务注册到Consul. 服务发现:服务消费者可以通过HTTP API或DNS方式,从Consul获取

java按照map的value排序 转载http://blog.csdn.net/tsingheng/article/details/7909861

java的TreeMap可以排序,只可惜是按照key来排序的,或者重写其他Map的排序算法也都是按照key来排序的,下面贴出来一个按照value排序的算法: [java] view plaincopy public class SortMap { public static void main(String[] args) throws Exception { // TODO code application logic here Map<String, Integer> myMap = ne

Win32消息循环机制等【转载】http://blog.csdn.net/u013777351/article/details/49522219

Dos的过程驱动与Windows的事件驱动 在讲本程序的消息循环之前,我想先谈一下Dos与Windows驱动机制的区别: DOS程序主要使用顺序的,过程驱动的程序设计方法.顺序的,过程驱动的程序有一个明显的开始,明显的过程及一个明显的结束,因此程序能直接控制程序事件或过程的顺序.虽然在顺序的过程驱动的程序中也有很多处理异常的方法,但这样的异常处理也仍然是顺序的,过程驱动的结构. 而Windows的驱动方式是事件驱动,就是不由事件的顺序来控制,而是由事件的发生来控制,所有的事件是无序的,所为一个程

解析Javascript事件冒泡机制(转) 本文转自:http://blog.csdn.net/luanlouis/article/details/23927347

本文转自:http://blog.csdn.net/luanlouis/article/details/23927347 1. 事件 在浏览器客户端应用平台,基本生都是以事件驱动的,即某个事件发生,然后做出相应的动作. 浏览器的事件表示的是某些事情发生的信号.事件的阐述不是本文的重点,尚未了解的朋友,可以访问W3school教程 进行了解,这将有助于更好地理解以下的内容 . 2. 冒泡机制 什么是冒泡呢? 下面这个图片大家应该心领神会吧,气泡从水底开始往上升,由深到浅,升到最上面.在上升的过程中

分享一篇文章C语言字节对齐问题(适用于C++)转载至http://blog.csdn.net/21aspnet/article/details/6729724

文章最后本人做了一幅图,一看就明白了,这个问题网上讲的不少,但是都没有把问题说透. 一.概念    对齐跟数据在内存中的位置有关.如果一个变量的内存地址正好位于它长度的整数倍,他就被称做自然对齐.比如在32位cpu下,假设一个整型变量的地址为0x00000004,那它就是自然对齐的.   二.为什么要字节对齐   需要字节对齐的根本原因在于CPU访问数据的效率问题.假设上面整型变量的地址不是自然对齐,比如为0x00000002,则CPU如果取它的值的话需要访问两次内存,第一次取从0x000000

ref与out之间的区别整理 摘自与望楼http://blog.csdn.net/xiaoning8201/article/details/6893154

ref和out都是C#中的关键字,所实现的功能也差不多,都是指定一个参数按照引用传递. 对于编译后的程序而言,它们之间没有任何区别,也就是说它们只有语法区别. 总结起来,他们有如下语法区别: 1.ref传进去的参数必须在调用前初始化,out不必,即: int i; SomeMethod( ref i );//语法错误 SomeMethod( out i );//通过 2.ref传进去的参数在函数内部可以直接使用,而out不可: public void SomeMethod(ref int i)

转-java编译时error: illegal character &#39;\ufeff&#39; 的解决办法-https://blog.csdn.net/t518vs20s/article/details/80833061

原文链接:https://blog.csdn.net/shixing_11/article/details/6976900 最近开发人员通过SVN提交了xxx.java文件,因发布时该包有问题需要回退,故SCM将该xxx.java文件用editplus打开删除了新添的一行,删除后重新编译打包,却报了如下异常: java:[1,0] illegal character: \65279 表面看着该文件确实没错,看不出来问题,后来从SVN上更新下代码以后,发现本地也不报错,后来通过Eclipse查看了

Java的垃圾回收机制(转自:http://blog.csdn.net/zsuguangh/article/details/6429592)

1. 垃圾回收的意义 在C++中,对象所占的内存在程序结束运行之前一直被占用,在明确释放之前不能分配给其它对象:而在Java中,当没有对象引用指向原先分配给某个对象的内存时,该内存便成为垃圾.JVM的一个系统级线程会自动释放该内存块.垃圾回收意味着程序不再需要的对象是"无用信息",这些信息将被丢弃.当一个对象不再被引用的时候,内存回收它占领的空间,以便空间被后来的新对象使用.事实上,除了释放没用的对象,垃圾回收也可以清除内存记录碎片.由于创建对象和垃圾回收器释放丢弃对象所占的内存空间,