一、Java反射的理解(反射是研究框架的基础之一)

Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为Java语言的反射机制。

二、逐步分析

参考:https://blog.csdn.net/u012585964/article/details/52011138

1、关于Class

  1、Class是一个类,一个描述类的类(也就是描述类本身),封装了描述方法的Method,描述字段的Filed,描述构造器的Constructor等属性
    2、对象照镜子后(反射)可以得到的信息:某个类的数据成员名、方法和构造器、某个类到底实现了哪些接口。
    3、对于每个类而言,JRE 都为其保留一个不变的 Class 类型的对象。 一个 Class 对象包含了特定某个类的有关信息。
    4、Class 对象只能由系统建立对象
    5、一个类在 JVM 中只会有一个Class实例

下面创建一个例子:后面的分析均以此案例为基准。

创建一个空接口:(后面会不断补充)

  1. package com.xfwl.reflection;
  2.  
  3. public interface IHuman {
  4.  
  5. }

创建一个空基类:(后面会不断补充)

  1. package com.xfwl.reflection;
  2.  
  3. public class Human {
  4.  
  5. }

创建一个子类:(后面会不断补充)

  1. package com.xfwl.reflection;
  2.  
  3. public class Person extends Human implements IHuman {
  4. /**
  5. * 默认default修饰
  6. */
  7. String name;
  8. /**
  9. * private修饰
  10. */
  11. private int age;
  12. /**
  13. * public修饰
  14. */
  15. public char sex='M';
  16. /**
  17. * 无参构造
  18. */
  19. public Person(){
  20. System.out.println("无参构造!!!");
  21. }
  22. /**
  23. * 有参构造
  24. */
  25. public Person(String name,int age,char sex){
  26. System.out.println("有参构造!!!");
  27. this.name=name;
  28. this.age=age;
  29. this.sex=sex;
  30. }
  31. public String getName() {
  32. return name;
  33. }
  34. public void setName(String name) {
  35. this.name = name;
  36. }
  37. public int getAge() {
  38. return age;
  39. }
  40. public void setAge(int age) {
  41. this.age = age;
  42. }
  43. public char getSex() {
  44. return sex;
  45. }
  46. public void setSex(char sex) {
  47. this.sex = sex;
  48. }
  49. public String toString() {
  50. return "Person{" +
  51. "name='" + name + '\'' +
  52. ", age=" + age +
  53. ", sex='" + sex + '\'' +
  54. '}';
  55. }
  56. }

2、反射获取类对象的三种方式(通过一个Junit测试来说明)

  1. package com.xfwl.reflection;
  2.  
  3. import org.junit.Test;
  4. /**
  5. * 测试类
  6. * @function
  7. * @author 小风微凉
  8. * @time 2018-6-3 下午12:28:38
  9. */
  10. public class TestAction {
  11. /**
  12. * 反射机制获取类有三种方法
  13. */
  14. @Test
  15. public void testGetClass() throws ClassNotFoundException {
  16. Class clazz = null;
  17.  
  18. //1 直接通过类名.Class的方式得到
  19. clazz = Person.class;
  20. System.out.println("通过类名: " + clazz);
  21.  
  22. //2 通过对象的getClass()方法获取,这个使用的少(一般是传的是Object,不知道是什么类型的时候才用)
  23. Object obj = new Person();
  24. clazz = obj.getClass();
  25. System.out.println("通过getClass(): " + clazz);
  26.  
  27. //3 通过全类名获取,用的比较多,但可能抛出ClassNotFoundException异常
  28. clazz = Class.forName("com.xfwl.reflection.Person");
  29. System.out.println("通过全类名获取: " + clazz);
  30. }
  31. }

运行结果:

  1. 通过类名: class com.xfwl.reflection.Person
  2. 无参构造!!!
  3. 通过getClass(): class com.xfwl.reflection.Person
  4. 通过全类名获取: class com.xfwl.reflection.Person

特别注意:(以下2中方式不会调用构造方法,因为没有实例化操作)  

  1. //1 直接通过类名.Class的方式得到
  2. clazz = Person.class;
  3. //3 通过全类名获取,用的比较多,但可能抛出ClassNotFoundException异常
  4. clazz = Class.forName("com.xfwl.reflection.Person");

3、利用newInstance创建对象:调用的类必须有无参的构造器

  1. /**
  2. * Class类的newInstance()方法,创建类的一个对象。
  3. * @throws ClassNotFoundException
  4. * @throws IllegalAccessException
  5. * @throws InstantiationException
  6. */
  7. @Test
  8. public void testNewInstance()
  9. throws ClassNotFoundException, IllegalAccessException, InstantiationException {
  10.  
  11. Class clazz = Class.forName("com.xfwl.reflection.Person");
  12.  
  13. //使用Class类的newInstance()方法创建类的一个对象
  14. //实际调用的类的那个 无参数的构造器(这就是为什么写的类的时候,要写一个无参数的构造器,就是给反射用的)
  15. //一般的,一个类若声明了带参数的构造器,也要声明一个无参数的构造器
  16. Object obj = clazz.newInstance();
  17. System.out.println(obj);
  18. }

测试结果:

那么,如果删除Person.java中的无参构造,继续测试,结果如下:

4、ClassLoader类加载器


  1. 类加载器详解:
    http://blog.csdn.net/ochangwen/article/details/51473120 
  1. /**
  2. * ClassLoader类装载器
  3. */
  4. @Test
  5. public void testClassLoader1() throws ClassNotFoundException, IOException {
  6. //1、获取一个系统的类加载器
  7. ClassLoader classLoader = ClassLoader.getSystemClassLoader();
  8. System.out.println("系统的类加载器-->" + classLoader);
  9.  
  10. //2、获取系统类加载器的父类加载器(扩展类加载器(extensions classLoader))
  11. classLoader = classLoader.getParent();
  12. System.out.println("扩展类加载器-->" + classLoader);
  13.  
  14. //3、获取扩展类加载器的父类加载器
  15. //输出为Null,无法被Java程序直接引用
  16. classLoader = classLoader.getParent();
  17. System.out.println("启动类加载器-->" + classLoader);
  18.  
  19. //4、测试当前类由哪个类加载器进行加载 ,结果就是系统的类加载器
  20. classLoader = Class.forName("com.xfwl.reflection.Person").getClassLoader();
  21. System.out.println("当前类由哪个类加载器进行加载-->"+classLoader);
  22.  
  23. //5、测试JDK提供的Object类由哪个类加载器负责加载的
  24. //输出为Null,无法被Java程序直接引用
  25. classLoader = Class.forName("java.lang.Object").getClassLoader();
  26. System.out.println("JDK提供的Object类由哪个类加载器加载-->" + classLoader);
  27. }

测试结果:

  1. 系统的类加载器-->sun.misc.Launcher$AppClassLoader@18b4aac2
  2. 扩展类加载器-->sun.misc.Launcher$ExtClassLoader@614c5515
  3. 启动类加载器-->null
  4. 当前类由哪个类加载器进行加载-->sun.misc.Launcher$AppClassLoader@18b4aac2
  5. JDK提供的Object类由哪个类加载器加载-->null

5、反射机制通过加载器获取流对象:getResourceAsStream方法

  1. /**
  2. * 反射机制通过加载器获取流对象:getResourceAsStream方法
  3. * @throws ClassNotFoundException
  4. * @throws IOException
  5. */
  6. @Test
  7. public void testGetResourceAsStream() throws ClassNotFoundException, IOException {
  8. //调用getResourceAsStream 获取类路径下的文件对应的输入流
  9. /**
  10. * 特别说明:
  11. * getResourceAsStream("path"),path的路径和new Person()的位置有关
  12. */
  13.  
  14. InputStream in = new Person().getClass().getClassLoader()
  15. .getResourceAsStream("com/xfwl/reflection/test.properties");
  16. System.out.println("in: " +in);
  17.  
  18. Properties properties = new Properties();
  19. properties.load(in);
  20. System.out.println("文件内容:"+properties);
  21. System.out.println("name: "+properties.getProperty("name"));
  22. System.out.println("age: " + properties.getProperty("age"));
  23. System.out.println("sex: "+properties.getProperty("sex"));
  24. System.out.println("desc: " + properties.getProperty("desc"));
  25. }

test.properties文件内容如下:文件编码格式:ISO-8859-1

  1. name=\u5C0F\u98CE\u5FAE\u51C9\u0087\u0089
  2. age=23
  3. sex=M
  4. desc=\u53CD\u5C04\u673A\u5236\u5B66\u4E60

运行结果:(直接解析会出现乱码问题,这个可以通过new String(乱码格式处理参数)来处理)

  1. 无参构造!!!
  2. in: java.io.BufferedInputStream@215be6bb
  3. 文件内容:{age=23, name=小风微凉??, sex=M, desc=反射机制学习}
  4. name: 小风微凉??
  5. age: 23
  6. sex: M
  7. desc: 反射机制学习

6、反射机制获取类中的方法:Method: 对应类中的方法

现在给Person类添加一个private 方法、一个public 方法、一个defaut 方法、一个protected方法

  1. /**
  2. * Java权限有四个,分别为public,protected,默认,private,其开放程度依次降低
  3. * public可供所有类访问
  4. * protected继承可见
  5. * private只能类本身内部的方法可以访问
  6. */
  7. public void method_public(){
  8. System.out.println("method_public");
  9. }
  10. public void method_public_2(String name,int age,char sex){//public 带参数
  11. System.out.println("method_public_2");
  12. String info="Person{" +
  13. "name='" + name + '\'' +
  14. ", age=" + age +
  15. ", sex='" + sex + '\'' +
  16. '}';
  17. System.out.println(info);
  18. }
  19. protected void method_protected(){
  20. System.out.println("method_protected");
  21. }
  22. protected void method_protected_2(String info){//protected 带参数
  23. System.out.println("method_protected_2:"+info);
  24. }
  25. void method_default(){
  26. System.out.println("method_default");
  27. }
  28. void method_default_2(String info){//默认修饰符 带参数
  29. System.out.println("method_default_2:"+info);
  30. }
  31. private void method_private(){
  32. System.out.println("method_private");
  33. }
  34. private void method_private_2(String info){//private 带参数
  35. System.out.println("method_private_2:"+info);
  36. }

开始测试如何通过反射机制使用这些方法

  1. /**
  2. * 如何通过反射机制使用这些方法
  3. * @throws ClassNotFoundException
  4. * @throws NoSuchMethodException
  5. * @throws IllegalAccessException
  6. * @throws InstantiationException
  7. * @throws InvocationTargetException
  8. */
  9. @Test
  10. public void testMethod() throws ClassNotFoundException, NoSuchMethodException,
  11. IllegalAccessException, InstantiationException, InvocationTargetException {
  12. Class clazz = Class.forName("com.xfwl.reflection.Person");
  13.  
  14. //1、得到clazz 对应的类中有哪些方法,不能获取private方法
  15. Method[] methods =clazz.getMethods();
  16. System.out.println("通过反射机制可以拿到的方法:clazz.getMethods()");
  17. for (Method method : methods){
  18. System.out.println(method.getName());
  19. }
  20. System.out.println("<-------------------------->");
  21.  
  22. //2、获取所有的方法(且只获取当着类声明的方法,包括private方法)
  23. Method[] methods2 = clazz.getDeclaredMethods();
  24. System.out.println("通过反射机制可以拿到的方法:clazz.getDeclaredMethods()");
  25. for (Method method : methods2){
  26. System.out.println(method.getName());
  27. }
  28. System.out.println("<-------------------------->");
  29. System.out.println("通过反射机制可以拿到指定的方法:clazz.getDeclaredMethod()");
  30. //3、获取指定的方法
  31. Method method1= clazz.getDeclaredMethod("method_private");
  32. System.out.println("private 无参:"+method1);
  33.  
  34. Method method2 = clazz.getDeclaredMethod("method_private_2",String.class);//第一个参数是方法名,后面的是方法里的参数
  35. System.out.println("private 有参:"+method2);
  36.  
  37. Method method3 = clazz.getDeclaredMethod("method_public_2",String.class,int.class,char.class);//第一个参数是方法名,后面的是方法里的参数
  38. System.out.println("public 有参:"+method2);
  39.  
  40. //4、执行方法!
  41. Object obj = clazz.newInstance();
  42. method3.invoke(obj, "小风微凉", 23,'M'); //执行方法:invoke(类对象)
  43. }

测试结果:

  1. 通过反射机制可以拿到的方法:clazz.getMethods():不能获取private/protected/default方法
  2. toString
  3. getName
  4. setName
  5. method_public_2
  6. setAge
  7. method_public
  8. getSex
  9. getAge
  10. setSex
  11. wait
  12. wait
  13. wait
  14. equals
  15. hashCode
  16. getClass
  17. notify
  18. notifyAll
  19. <-------------------------->
  20. 通过反射机制可以拿到的方法:clazz.getDeclaredMethods():获取所有修饰权限的方法
  21. toString
  22. getName
  23. setName
  24. method_private_2
  25. method_private
  26. method_public_2
  27. setAge
  28. method_public
  29. method_default
  30. method_default_2
  31. getSex
  32. getAge
  33. setSex
  34. method_protected
  35. method_protected_2
  36. <-------------------------->
  37. 通过反射机制可以拿到指定的方法:clazz.getDeclaredMethod()
  38. private 无参:private void com.xfwl.reflection.Person.method_private()
  39. private 有参:private void com.xfwl.reflection.Person.method_private_2(java.lang.String)
  40. public 有参:private void com.xfwl.reflection.Person.method_private_2(java.lang.String)
  41. 无参构造!!!
  42. method_public_2
  43. Person{name='小风微凉', age=23, sex='M'}

继续分析一下:

JDK中的获取方法

获取方法:默认只能获取public修饰的方法

  1. @CallerSensitive
  2. public Method[] getMethods() throws SecurityException {
  3. checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true);
  4. return copyMethods(privateGetPublicMethods());
  5. }

获取方法:所有修饰权限的方法都可以获得

  1. @CallerSensitive
  2. public Method[] getDeclaredMethods() throws SecurityException {
  3. checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), true);
  4. return copyMethods(privateGetDeclaredMethods(false));
  5. }

获取方法:获取指定的方法(所有修饰权限)

  1. /**
  2. * @jls 8.2 Class Members
  3. * @jls 8.4 Method Declarations
  4. * @since JDK1.1
  5. */
  6. @CallerSensitive
  7. public Method getDeclaredMethod(String name, Class<?>... parameterTypes)
  8. throws NoSuchMethodException, SecurityException {
  9. checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), true);
  10. Method method = searchMethods(privateGetDeclaredMethods(false), name, parameterTypes);
  11. if (method == null) {
  12. throw new NoSuchMethodException(getName() + "." + name + argumentTypesToString(parameterTypes));
  13. }
  14. return method;
  15. }

  分析一下上面这个方法:

    String name:方法的名称

       Class<?>... parameterTypes:一个或多个方法参数的类型,注意要一一对应,否则会报错的哦

执行方法:invoke(方法对象,方法实际参数)

  1. @CallerSensitive
  2. public Object invoke(Object obj, Object... args)
  3. throws IllegalAccessException, IllegalArgumentException,
  4. InvocationTargetException
  5. {
  6. if (!override) {
  7. if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
  8. Class<?> caller = Reflection.getCallerClass();
  9. checkAccess(caller, clazz, obj, modifiers);
  10. }
  11. }
  12. MethodAccessor ma = methodAccessor; // read volatile
  13. if (ma == null) {
  14. ma = acquireMethodAccessor();
  15. }
  16. return ma.invoke(obj, args);
  17. }

7、反射机制获取类中的方法:Method: 对应基类或接口中的方法

上面分析了,如何通过反射拿到当前本类里面的各个修饰权限的方法,下面来继续分析一下,如何读取父类或实现的接口中的方法:

现在,给父类添加一些方法,在接口中定义一些方法:

接口中的方法声明:

  1. package com.xfwl.reflection;
  2.  
  3. public interface IHuman {
  4.  
  5. void eat();
  6. void eat(String info);
  7. }

Person.java实现接口方法

  1. public void eat() {
  2. System.out.println("实现接口的方法:eat()无参:");
  3. }
  4. public void eat(String info) {
  5. System.out.println("实现接口的方法:eat()有参:"+info);
  6. }

父类中的方法定义:

  1. package com.xfwl.reflection;
  2.  
  3. public class Human {
  4. public void play_public(){
  5. System.out.println("public无参:play_public");
  6. }
  7. public void play_public_2(String info){
  8. System.out.println("public有参:play_public2:"+info);
  9. }
  10. protected void play_protected(){
  11. System.out.println("protected无参:play_protected");
  12. }
  13. protected void play_protected_2(String info){
  14. System.out.println("protected有参:play_protected_2:"+info);
  15. }
  16. void play_default(){
  17. System.out.println("默认修饰符无参:play_default");
  18. }
  19. void play_default_2(String info){//默认修饰符 带参数
  20. System.out.println("默认修饰符有参:play_default_2:"+info);
  21. }
  22. private void play_private(){
  23. System.out.println("private无参:play_private");
  24. }
  25. private void play_private_2(String info){
  26. System.out.println("private有参:play_private_2:"+info);
  27. }
  28. }

开始测试:

1、拿到当前Person类反射对象,能否得到接口中的方法

  1. /**
  2. * 反射机制获取类中的方法:Method: 对应基类或接口中的方法
  3. * @throws ClassNotFoundException
  4. * @throws SecurityException
  5. * @throws NoSuchMethodException
  6. * @throws InstantiationException
  7. * @throws InvocationTargetException
  8. * @throws IllegalArgumentException
  9. * @throws IllegalAccessException
  10. */
  11. @Test
  12. public void testInterfaceOrSupperClass() throws ClassNotFoundException, NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, InstantiationException{
  13. Class clazz = Class.forName("com.xfwl.reflection.Person");
  14. //拿到当前Person类反射对象,能否得到接口中的方法
  15. for (Method method : clazz.getMethods()){
  16. System.out.println(method.getName());
  17. }
  18. //获取当前类实现的接口中的方法
  19. Method method1= clazz.getDeclaredMethod("eat");
  20. Method method2= clazz.getDeclaredMethod("eat",String.class);
  21. //执行
  22. method1.invoke(clazz.newInstance());
  23. method2.invoke(clazz.newInstance(),"eat有参数");
  24. }

测试结果:(可以拿到实现的接口中的方法并执行)

  1. toString
  2. getName
  3. setName
  4. eat
  5. eat
  6. method_public_2
  7. setAge
  8. getSex
  9. setSex
  10. getAge
  11. method_public
  12. play_public_2
  13. play_public
  14. wait
  15. wait
  16. wait
  17. equals
  18. hashCode
  19. getClass
  20. notify
  21. notifyAll
  22. 无参构造!!!
  23. 实现接口的方法:eat()无参:
  24. 无参构造!!!
  25. 实现接口的方法:eat()有参:eat有参数

2、拿到当前Person类反射对象,能否获取父类中的方法

通过当前反射对象,拿到父类反射对象

  1. Class clazz = Class.forName("com.xfwl.reflection.Person");
  2. Class superClazz = clazz.getSuperclass();
  1. /**
  2. * 反射机制获取类中的方法:Method: 对应基类或接口中的方法
  3. * @throws ClassNotFoundException
  4. * @throws SecurityException
  5. * @throws NoSuchMethodException
  6. * @throws InstantiationException
  7. * @throws InvocationTargetException
  8. * @throws IllegalArgumentException
  9. * @throws IllegalAccessException
  10. */
  11. @Test
  12. public void testInterfaceOrSupperClass() throws ClassNotFoundException, NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, InstantiationException{
  13. Class clazz = Class.forName("com.xfwl.reflection.Person");
  14. System.out.println("<------------父类中能够使用的公共权限的方法------------------------>");
  15. //拿到当前Person类反射对象,能否获取父类中的方法
  16. Class superClazz = clazz.getSuperclass();
  17. for (Method method : superClazz.getMethods()){
  18. System.out.println(method.getName());
  19. }
  20. System.out.println("<----------------父类中所有的方法:仅仅父类中的方法-------------------->");
  21. //拿到父类中的所有权限修饰符修饰的方法
  22. for (Method method : superClazz.getDeclaredMethods()){
  23. System.out.println(method.getName());
  24. }
  25. }

运行结果:

  1. <------------父类中能够使用的公共权限的方法------------------------>
  2. play_public
  3. play_public_2
  4. wait
  5. wait
  6. wait
  7. equals
  8. toString
  9. hashCode
  10. getClass
  11. notify
  12. notifyAll
  13. <----------------父类中所有的方法:仅仅父类中的方法-------------------->
  14. play_private_2
  15. play_public
  16. play_public_2
  17. play_private
  18. play_protected
  19. play_default
  20. play_protected_2
  21. play_default_2

那么可以执行父类中的方法吗?

  1. //是否可以通过子类对象拿到父类中的方法
  2. Method method3= clazz.getDeclaredMethod("play_public");
  3. Method method4= clazz.getDeclaredMethod("play_public_2",String.class);
  4. Method method5= clazz.getDeclaredMethod("play_private");
  5. Method method6= clazz.getDeclaredMethod("play_private_2",String.class);

上面代码报错,说明不可以,public修饰的方法也拿不到

  1.      Method method7= superClazz.getDeclaredMethod("play_public");
  2. Method method8= superClazz.getDeclaredMethod("play_public_2",String.class);
  3. Method method9= superClazz.getDeclaredMethod("play_private");
  4. Method method10= superClazz.getDeclaredMethod("play_private_2",String.class);

上面代码正常执行,说明父类的反射对象可以拿到自己的public或private方法

  1. //使用子类的反射对象执行方法
  2. method7.invoke(clazz.newInstance());
  3. method8.invoke(clazz.newInstance(), "play_public_2有参数");
  4. method9.invoke(clazz.newInstance()); //无法执行,Junit报错
  5. method10.invoke(clazz.newInstance(), "play_private_2有参数");//无法执行,Junit报错
  1. //使用父类的反射对象执行方法
  2. method7.invoke(superClazz.newInstance());
  3. method8.invoke(superClazz.newInstance(), "play_public_2有参数");
  4. method9.invoke(superClazz.newInstance()); //无法执行,Junit报错
  5. method10.invoke(superClazz.newInstance(), "play_private_2有参数");//无法执行,Junit报错

上面代码执行部分报错,说明通过子类的反射对象和拿到的父类反射对象,也仅仅只能执行public和protected和default默认修饰的方法,不能执行private修饰的方法

7、反射机制获取类中的字段属性:Field字段

  1. /**
  2. * 默认default修饰
  3. */
  4. String name;
  5. /**
  6. * private修饰
  7. */
  8. private int age;
  9. /**
  10. * public修饰
  11. */
  12. public char sex='M';
  13. /**
  14. * protected修饰
  15. */
  16. protected boolean isBeauty=true;

开始测试:如何获取

  1. /**
  2. * 反射机制获取类中的字段属性:Field字段
  3. * @throws ClassNotFoundException
  4. * @throws SecurityException
  5. * @throws NoSuchFieldException
  6. * @throws IllegalAccessException
  7. * @throws IllegalArgumentException
  8. */
  9. @Test
  10. public void testFiled() throws ClassNotFoundException, NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException{
  11. //拿到反射Class对象
  12. Class clazz = Class.forName("com.xfwl.reflection.Person");
  13. //获取Field的数组,私有字段也能获取
  14. Field[] fields = clazz.getDeclaredFields();
  15. System.out.println("<----遍历拿到字段:开始--------------------->");
  16. for (Field field: fields) {
  17. System.out.println(field.getName());
  18. }
  19. System.out.println("<------------获取指定名字的Field以及类型--------------------------->");
  20. //获取指定名字的Field(如果是私有的,见下面的4)
  21. Field field1 = clazz.getDeclaredField("name");
  22. System.out.println("获取指定Field名=: " + field1.getName()+",类型:"+field1.getType());
  23. Field field2 = clazz.getDeclaredField("age");
  24. System.out.println("获取指定Field名=: " + field2.getName()+",类型:"+field2.getType());
  25. Field field3 = clazz.getDeclaredField("sex");
  26. System.out.println("获取指定Field名=: " + field3.getName()+",类型:"+field3.getType());
  27. Field field4 = clazz.getDeclaredField("isBeauty");
  28. System.out.println("获取指定Field名=: " + field4.getName()+",类型:"+field4.getType());
  29.  
  30. System.out.println("<----------获取指定对象的Field的值 ----------------------------->");
  31. Person person = new Person("小风微凉", 12,'M');
  32. //获取指定对象的Field的值
  33. Object val = field1.get(person);
  34. System.out.println("获取指定对象字段'name'的Field的值=: " + val);
  35.  
  36. System.out.println("<----------设置指定对象的Field的值----------------------------->");
  37. //设置指定对象的Field的值
  38. field1.set(person, "反射学习A");
  39. System.out.println("设置指定对象字段'name'的Field的值=: " + person.name);
  40.  
  41. System.out.println("<----------若该字段是私有的,需要调用setAccessible(true)方法----------------------------->");
  42. //若该字段是私有的,需要调用setAccessible(true)方法
  43. field2 = clazz.getDeclaredField("age");
  44. field2.setAccessible(true);
  45. System.out.println("获取指定私有字段名=: " + field2.getName());
  46. }

测试结果:

  1. <----遍历拿到字段:开始--------------------->
  2. name
  3. age
  4. sex
  5. isBeauty
  6. <------------获取指定名字的Field以及类型--------------------------->
  7. 获取指定Field名=: name,类型:class java.lang.String
  8. 获取指定Field名=: age,类型:int
  9. 获取指定Field名=: sex,类型:char
  10. 获取指定Field名=: isBeauty,类型:boolean
  11. <----------获取指定对象的Field的值 ----------------------------->
  12. 有参构造!!!
  13. 获取指定对象字段'name'的Field的值=: 小风微凉
  14. <----------设置指定对象的Field的值----------------------------->
  15. 设置指定对象字段'name'的Field的值=: 反射学习A
  16. <----------若该字段是私有的,需要调用setAccessible(true)方法----------------------------->
  17. 获取指定私有字段名=: age

8、反射机制获取类中的构造器:构造器(Constructor)

Person的构造器

  1. /**
  2. * 无参构造
  3. */
  4. public Person(){
  5. System.out.println("无参构造!!!");
  6. }
  7. /**
  8. * 有参构造
  9. */
  10. public Person(String name,int age,char sex){
  11. System.out.println("有参构造!!!");
  12. this.name=name;
  13. this.age=age;
  14. this.sex=sex;
  15. }

@Test测试

  1. /**
  2. * 构造器:开发用的比较少
  3. */
  4. @Test
  5. public void testConstructor() throws ClassNotFoundException, NoSuchMethodException,
  6. IllegalAccessException, InvocationTargetException, InstantiationException {
  7. String className = "com.xfwl.reflection.Person";
  8. Class<Person> clazz = (Class<Person>) Class.forName(className);
  9.  
  10. //1.获取Constructor对象
  11. Constructor<Person>[] constructors =
  12. (Constructor<Person>[]) Class.forName(className).getConstructors();
  13.  
  14. System.out.println("<-------------打印所有的构造器---------------------->");
  15. for (Constructor<Person> constructor: constructors) {
  16. System.out.println(constructor);
  17. }
  18. System.out.println("<------------------------------------------------>");
  19. Constructor<Person> constructor = clazz.getConstructor(String.class, int.class,char.class);
  20. System.out.println("拿到指定的-->" + constructor);
  21.  
  22. //2.调用构造器的newInstance()方法创建对象
  23. Object obj= constructor.newInstance("changwen", 11,'M');
  24. }

运行结果:

  1. <-------------打印所有的构造器---------------------->
  2. public com.xfwl.reflection.Person()
  3. public com.xfwl.reflection.Person(java.lang.String,int,char)
  4. <------------------------------------------------>
  5. 拿到指定的-->public com.xfwl.reflection.Person(java.lang.String,int,char)
  6. 有参构造!!!

9、反射机制获取类中的注解:注解(Annotation)

 •从 JDK5.0 开始,Java 增加了对元数据(MetaData)的支持,也就是Annotation(注释) 
    •Annotation其实就是代码里的特殊标记,这些标记可以在编译,类加载, 运行时被读取,并执行相应的处理.通过使用Annotation,程序员可以在不改变原有逻辑的情况下,在源文件中嵌入一些补充信息. 
    •Annotation 可以像修饰符一样被使用,可用于修饰包,类,构造器, 方法,成员变量, 参数,局部变量的声明,这些信息被保存在Annotation的 “name=value”对中. 
    •Annotation能被用来为程序元素(类,方法,成员变量等)设置元数据 

基本的 Annotation

•使用 Annotation时要在其前面增加@符号,并把该Annotation 当成一个修饰符使用.用于修饰它支持的程序元素 
•三个基本的Annotation: 
    –@Override:限定重写父类方法,该注释只能用于方法 
    –@Deprecated:用于表示某个程序元素(类,方法等)已过时 
    –@SuppressWarnings:抑制编译器警告. 

自定义 Annotation

    •定义新的 Annotation类型使用@interface关键字 
    •Annotation 的成员变量在Annotation 定义中以无参数方法的形式来声明.其方法名和返回值定义了该成员的名字和类型. 
    •可以在定义Annotation的成员变量时为其指定初始值,指定成员变量的初始值可使用default关键字 
    •没有成员定义的Annotation称为标记;包含成员变量的Annotation称为元数据Annotation 
  1. package com.xfwl.reflection;
  2.  
  3. 3 import java.lang.annotation.ElementType;
  4. 4 import java.lang.annotation.Retention;
  5. 5 import java.lang.annotation.RetentionPolicy;
  6. 6 import java.lang.annotation.Target;
  7.  
  8. public class Person extends Human implements IHuman {
  9.  
  10. @Retention(RetentionPolicy.RUNTIME) //运行时检验
  11. @Target(value = {ElementType.METHOD}) //作用在方法上
  12. public @interface AgeValidator {
  13.  
  14. int min();
  15. int max();
  16. }
  17. //......其余部分省略
  18. }
  1. /**
  2. * 自定义一个注解:检查年龄范围
  3. * @function
  4. * @author 小风微凉
  5. * @time 2018-6-3 下午3:56:03
  6. */
  7. @Retention(RetentionPolicy.RUNTIME) //运行时检验
  8. @Target(value = {ElementType.METHOD}) //作用在方法上
  9. public @interface AgeValidator {
  10. int min();
  11. int max();
  12. }

@Test测试

  1. /**
  2. * 通过反射才能获取注解
  3. */
  4. @Test
  5. public void testAnnotation() throws Exception {
  6. //这样的方式不能使用注解
  7. /*Person person3 = new Person();
  8. person3.setAge(10);*/
  9.  
  10. //拿到反射Class对象
  11. String className = "com.xfwl.reflection.Person";
  12. Class clazz = Class.forName(className);
  13. Object obj = clazz.newInstance();
  14. //拿到指定方法
  15. Method method = clazz.getDeclaredMethod("setAge",int.class);
  16. int val =40;
  17.  
  18. //获取注解
  19. Annotation annotation = method.getAnnotation(AgeValidator.class);
  20. if (annotation != null){
  21. if (annotation instanceof AgeValidator){
  22. AgeValidator ageValidator = (AgeValidator) annotation;
  23.  
  24. if (val< ageValidator.min() || val>ageValidator.max()){
  25. throw new RuntimeException("数值超出范围");
  26. }
  27. }
  28. }
  29. //执行方法
  30. method.invoke(obj, val);
  31. System.out.println(obj);
  32. }

运行结果:

  1. 无参构造!!!
  2. Person{name='null', age=40, sex='M'}

获取指定注解:

  1. //获取注解
  2. Annotation annotation = method.getAnnotation(AgeValidator.class);

获取所有注解:

  1. //获取所有注解
  2. Annotation[] arr=clazz.getDeclaredAnnotations();

提取 Annotation信息

•JDK5.0 在 java.lang.reflect包下新增了 AnnotatedElement接口,该接口代表程序中可以接受注释的程序元素
•当一个 Annotation类型被定义为运行时Annotation后,该注释才是运行时可见,当 class文件被载入时保存在 class文件中的 Annotation才会被虚拟机读取
•程序可以调用AnnotationElement对象的如下方法来访问 Annotation信息
–获取 Annotation实例:
getAnnotation(Class<T> annotationClass)

JDK 的元Annotation

•JDK 的元Annotation 用于修饰其他Annotation 定义
•@Retention:只能用于修饰一个 Annotation定义,用于指定该 Annotation可以保留多长时间,@Rentention包含一个RetentionPolicy类型的成员变量,使用 @Rentention时必须为该 value成员变量指定值:
    –RetentionPolicy.CLASS:编译器将把注释记录在 class文件中.当运行 Java程序时,JVM 不会保留注释.这是默认值
    –RetentionPolicy.RUNTIME:编译器将把注释记录在class文件中. 当运行 Java 程序时, JVM 会保留注释. 程序可以通过反射获取该注释
    –RetentionPolicy.SOURCE:编译器直接丢弃这种策略的注释
•@Target: 用于修饰Annotation 定义,用于指定被修饰的 Annotation能用于修饰哪些程序元素.@Target 也包含一个名为 value的成员变量.
•@Documented:用于指定被该元 Annotation修饰的 Annotation类将被 javadoc工具提取成文档.
•@Inherited:被它修饰的 Annotation将具有继承性.如果某个类使用了被@Inherited 修饰的Annotation, 则其子类将自动具有该注释 
 
后续补充整理:
(1)通过getDeclaredMethod拿到的方法,可以获取个中修饰符修饰的方法名称和对象,但是private的方法无法invoke执行
UserBean.java

  1. package com.xfwl.reflect;
  2.  
  3. public class UserBean {
  4.  
  5. private String uname;
  6. private String upwd;
  7. public UserBean(){
  8. this.setUname("xfwl");
  9. this.setUpwd("123456");
  10. }
  11. public UserBean(String uname,String upwd){
  12. this.setUname(uname);
  13. this.setUpwd(uname);
  14. }
  15. public void logIn(UserBean user){
  16. System.out.println("用户登录:uname="+this.getUname()+",upwd="+this.getUpwd());
  17. }
  18. public String getUname() {
  19. return uname;
  20. }
  21. private void logOut(UserBean user){
  22. System.out.println("用户退出:uname="+this.getUname()+",upwd="+this.getUpwd());
  23. }
  24. public void setUname(String uname) {
  25. this.uname = uname;
  26. }
  27.  
  28. public String getUpwd() {
  29. return upwd;
  30. }
  31.  
  32. public void setUpwd(String upwd) {
  33. this.upwd = upwd;
  34. }
  35. }

测试类:ReflectAction.java

  1. package com.xfwl.reflect;
  2.  
  3. import java.lang.reflect.Method;
  4.  
  5. public class ReflectAction {
  6. /**
  7. * @param args
  8. */
  9. public static void main(String[] args) {
  10. UserBean jack=null;
  11. UserBean tom=null;
  12. Class tomC=null;
  13. try{
  14. jack=(UserBean)Class.forName("com.xfwl.reflect.UserBean").newInstance();
  15. //jack.logIn();
  16.  
  17. tomC=Class.forName("com.xfwl.reflect.UserBean");
  18. tom=(UserBean) tomC.newInstance();
  19. Method[] methods = tomC.getDeclaredMethods();
  20. for (Method method : methods){
  21. if("logOut".equals(method.getName())){
  22. method=tomC.getDeclaredMethod(method.getName(),UserBean.class);
  23. System.out.println(method);
  24. method.invoke(tomC.newInstance(),tom);
  25. }
  26. }
  27. }catch(Exception e){
  28.  
  29. }
  30.  
  31. }
  32.  
  33. }

运行结果:没有执行:logOut()

修改:

  1. public void logOut(UserBean user){
  2. System.out.println("用户退出:uname="+this.getUname()+",upwd="+this.getUpwd());
  3. }

即可执行:logOut()

Java反射学习:深入学习Java反射机制的更多相关文章

  1. Java学习笔记之使用反射+泛型构建通用DAO

    PS:最近简单的学了学后台Servlet+JSP.也就只能学到这里了.没那么多精力去学SSH了,毕竟Android还有很多东西都没学完.. 学习内容: 1.如何使用反射+泛型构建通用DAO. 1.使用 ...

  2. Java学习笔记54(反射详解)

    反射概念: java反射机制是在运行状态中,对于任意一个类,都能知道所有属性和方法 对于任意一个对象都能调用它的任意一个方法和属性,这种动态获取和调用的功能称为java的反射机制 实际作用: 已经完成 ...

  3. Java第三阶段学习(九、类加载器、反射)

    一.类加载器 1.类的加载: 当程序要使用某个类时,如果该类还未被加载到内存中,则系统会通过加载,连接,初始化三步来实现对这个类进行初始化. 1.1 加载: 就是指将class文件读入内存,并为之自动 ...

  4. Java反射:Web学习的灵魂

    反射:Web学习的灵魂 我们从最初的 javac -HelloWorld.java,到面向对象部分,我们可以将Java代码在计算机中经历的阶段分为三部分:Scource源代码阶段 -- Class类对 ...

  5. 【Java语言特性学习之二】反射

    一.概念java加载class文件分两种情况:(1)类型是编译器已知的,这种文件的.class文件在编译的时候,编译器会把.class文件打开(不加载)检查,称为Run- Time Type Iden ...

  6. Java学习笔记--注解和反射

    注解和反射 1. 注解 注解作用: 对程序做出解释 被其他程序读取 注解格式: @注释名,还可以添加一些参数值,例如@SuppressWarnings(value="unchecked&qu ...

  7. Java反射及注解学习- 反射的使用 - JDK动态代理

    代理模式基本概念:1.代理模式的作用:为其他对象提供一种以控制对方的访问在某种情况下,一个客户不想或者不能直接引用另一个对象,代理可以在客户端和目标对象之间起到中介的作用代理的角色:(1)抽象角色:声 ...

  8. Java 基础 类加载器和双亲委派机制 学习笔记

    转自博客:https://blog.csdn.net/weixin_38118016/article/details/79579657 文章不是我写的,但是感觉写的挺通俗易懂的,然后防止以后丢失,就转 ...

  9. 菜鸟学Java(十五)——Java反射机制(二)

    上一篇博文<菜鸟学编程(九)——Java反射机制(一)>里面,向大家介绍了什么是Java的反射机制,以及Java的反射机制有什么用.上一篇比较偏重理论,理论的东西给人讲出来总感觉虚无缥缈, ...

  10. 菜鸟学Java(十四)——Java反射机制(一)

    说到反射,相信有过编程经验的人都不会陌生.反射机制让Java变得更加的灵活.反射机制在Java的众多特性中是非常重要的一个.下面就让我们一点一点了解它是怎么一回事. 什么是反射 在运行状态中,对于任意 ...

随机推荐

  1. int 和 Integer 有什么区别

    原文地址:https://blog.csdn.net/chenliguan/article/details/53888018 1 int与Integer的基本使用对比 (1)Integer是int的包 ...

  2. 中小公司的Java工程师应该如何逆袭冲进BAT?

    (1)80% Java工程师都有的迷茫 这篇文章,跟大家聊一聊很多很多很多人问我的一个问题:中小公司的Java工程师应该如何规划准备,才能跳槽进入BAT这类一线互联网公司? 之所以我用了三个 “很多” ...

  3. videojs集成--播放rtmp流

    之前说到已经把流推送过来了,这时候就可以使用videojs来进行显示播放. 首先要先有一个文件,那就是video-js.swf 因为,这种播放方式html已经不能很好的进行播放了,需要用到flash来 ...

  4. An internal error occurred during: "Map/Reducelocation status updater".java.lang.NullPointerException

    当我们运行wordcount代码时,出现报错,如下所示: An internal error occurred during: "Map/Reducelocation status upda ...

  5. thinkphp模板中for循环与switch的使用

    1.for用法 <for start="开始值" end="结束值" comparison="" step="步进值&quo ...

  6. Oracle 常见hint

    Hints 应该慎用,收集相关表的统计信息,根据执行计划,来改变查询方式 只能在SELECT, UPDATE, INSERT, MERGE, or DELETE 关键字后面,只有insert可以用2个 ...

  7. 转载:Oracle RAC日常基本维护命令

    本文转载自: https://blog.csdn.net/tianlesoftware/article/details/5358573 Oracle RAC日常基本维护命令 好文转载, Oracle  ...

  8. php命令执行

    php命令执行通过函来执行外部应用程序,函数有shell_exec(),exec(),system(),passthru() <?php $i = $_GET['cmd']; echo exec ...

  9. js中的class

    js中的class 类写法 class SuperClass { constructor(option) { this.a = option; } fn() { console.log(this.b) ...

  10. 用Dos黑窗口运行Cmd命令

    public class BlackWindow { private static BlackWindow _instance; public static BlackWindow Instance ...