实践

通过反射实例化

  1. package com.reflectionTest;
  2. public class People {
  3. private String name = "";
  4. private int year = 0;
  5. private People(){}
  6. private People(String name,int year){
  7. this.name = name;
  8. this.year = year;
  9. }
  10. public void say(){
  11. System.out.println("Hello,My name is "+name +",it is a Non-parameter method");
  12. }
  13. public void eat(String food){
  14. System.out.println(name +"eat "+food+",it is a Method with parameters");
  15. }
  16. public static void run(){
  17. System.out.println("it is a static method");
  18. }
  19. }
  1. package com.reflectionTest;
  2. import java.lang.reflect.Constructor;
  3. import java.lang.reflect.Method;
  4. public class Test {
  5. public static void main(String[] args) {
  6. try{
  7. Class<?> clz = Class.forName("com.reflectionTest.People");
  8. Constructor<?> cons = clz.getConstructor();
  9. Object obj1 = cons.newInstance();
  10. //通过无参构造函数进行创建
  11. Constructor<?> constructor = clz.getDeclaredConstructor(String.class,int.class);
  12. Object obj2 = constructor.newInstance(new Object[]{"小华",12});
  13. //通过带参数构造函数进行创建
  14. Method method = clz.getDeclaredMethod("say");
  15. method.invoke(obj1);//把实例化作为第一个参数传入
  16. //调用无参数的非静态方法
  17. Method method2 = clz.getDeclaredMethod("eat",String.class);
  18. method2.invoke(obj1,new Object[]{"小明"});//第一个参数为实例,之后的参数为具体参数值
  19. //调用带参数的非静态方法
  20. }catch (Exception e){
  21. e.printStackTrace();
  22. }
  23. }
  24. }

调用私有方法

  1. package com.reflectionTest;
  2. public class People {
  3. private String name;
  4. public People(String name){
  5. this.name = name;
  6. }
  7. /**
  8. * 私有方法
  9. */
  10. private void println(){
  11. System.out.println("it is a private method,这个人名叫:"+name);
  12. }
  13. /**
  14. * 有返回值的私有方法
  15. * @return
  16. */
  17. private String getName(){
  18. return name;
  19. }
  20. /**
  21. * 有一个传参的私有方法
  22. * @param name
  23. */
  24. private void setName(String name){
  25. this.name = name;
  26. }
  27. /**
  28. * 有多个传参的私有方法
  29. * @param name
  30. */
  31. private void setInfo(String name,int age){
  32. this.name = name;
  33. }
  34. /**
  35. * 静态私有方法
  36. */
  37. private static void run(){
  38. System.out.println("it is a private and static method");
  39. }
  40. }
  1. package com.reflectionTest;
  2. import java.lang.reflect.Method;
  3. public class Main {
  4. public static void main(String[] args) throws Exception{
  5. People people = new People("小明");
  6. //有返回值的无参方法
  7. Method getNameMethod = people.getClass().getDeclaredMethod("getName");
  8. getNameMethod.setAccessible(true);
  9. String name = (String) getNameMethod.invoke(people);
  10. System.out.println("获取带参私有函数的返回值:"+name);
  11. //调用带参数的方法
  12. Method setNameMethod = people.getClass().getDeclaredMethod("setName",String.class);
  13. setNameMethod.setAccessible(true);
  14. setNameMethod.invoke(people,"小红");
  15. //调用多个参数的方法
  16. Method setInfoMethod = people.getClass().getDeclaredMethod("setInfo",String.class,int.class);
  17. setInfoMethod.setAccessible(true);
  18. setInfoMethod.invoke(people,"小红",12);
  19. //无参无返回值的方法
  20. Method printMethod= people.getClass().getDeclaredMethod("println");
  21. printMethod.setAccessible(true);
  22. printMethod.invoke(people);
  23. //静态方法
  24. Class<?> clz = Class.forName("com.reflectionTest.People");
  25. Method method3 = clz.getDeclaredMethod("run");
  26. method3.setAccessible(true);//将作为域设置为可见(也就是public)
  27. method3.invoke(null);//和调用非静态方法的区别在于不用利用反射实例化,第一个参数直接传入null即可。
  28. }
  29. }

获取带参私有函数的返回值:小明 it is a private method,这个人名叫:小红 it is a private and static method

私有方法传参为数组或List的处理方法

  1. package com.reflectionTest;
  2. import java.util.List;
  3. public class People {
  4. private String name;
  5. private People[] mChild;
  6. public People(String name){
  7. this.name = name;
  8. }
  9. public String getName(){
  10. return name;
  11. }
  12. private void setChildrenArray(People[] children){
  13. this.mChild = children;
  14. }
  15. private void setChildrenList(List<People> children){
  16. this.mChild = (People[]) children.toArray();
  17. }
  18. public People[] getChildArray(){
  19. return mChild;
  20. }
  21. }
  1. package com.reflectionTest;
  2. import java.lang.reflect.Method;
  3. import java.util.Arrays;
  4. import java.util.List;
  5. public class Main {
  6. public static void main(String[] args) throws Exception{
  7. People people = new People("小明");
  8. People[] child = new People[2];
  9. child[0] = new People("小红");
  10. child[1] = new People("小刚");
  11. //数组的传参处理
  12. Method setChildrenArrayMethod = people.getClass().getDeclaredMethod("setChildrenArray",People[].class);
  13. setChildrenArrayMethod.setAccessible(true);
  14. setChildrenArrayMethod.invoke(people, (Object) child);
  15. System.out.println("设置数组后获取到的内容如下:");
  16. for (People p:people.getChildArray()){
  17. System.out.println(p.getName());
  18. }
  19. //ArrayList/List的处理方法
  20. Method setChildrenListMethod = people.getClass().getDeclaredMethod("setChildrenList", List.class);
  21. setChildrenListMethod.setAccessible(true);
  22. setChildrenListMethod.invoke(people, Arrays.asList(child));
  23. System.out.println("设置List后获取到的内容如下:");
  24. for (People p:people.getChildArray()){
  25. System.out.println(p.getName());
  26. }
  27. }
  28. }

参考:https://segmentfault.com/q/1010000018762976/a-1020000018765152
简述:传参为List类似时,无论元素类型是什么,直接传参List.class即可,泛型参数在编译后会被擦除掉,无论List里面是String还是什么别的东西都不会影响获取到那个method,在invoke的时候传的参数对不上的话才会产生异常。

获取及修改私有变量

  1. package com.hxw.test;
  2. public class People {
  3. private String name = "未名";
  4. private static String type = "人类";//静态私有变量
  5. public People(){}
  6. public People(String name){
  7. this.name = name;
  8. }
  9. public void println(){
  10. System.out.println("我的名字叫:"+name);
  11. }
  12. }
  1. import com.hxw.test.People;
  2. import java.lang.reflect.Field;
  3. public class Main {
  4. public static void main(String[] args) throws Exception{
  5. People people = new People("小明");
  6. Class clazz = Class.forName("com.hxw.test.People");
  7. Field nameF = clazz.getDeclaredField("name");
  8. nameF.setAccessible(true);//将私有变量设置为可访问
  9. //获取私有变量的值
  10. String name = (String) nameF.get(people);
  11. System.out.println(name);
  12. //这里获取到实例People的私有变量,打印的结果为:小明
  13. //修改私有变量
  14. nameF.set(people,"小红");
  15. people.println();//已将People的私有变量name修改为:小红
  16. //获取私有静态变量
  17. Field typeF = People.class.getDeclaredField("type");
  18. typeF.setAccessible(true);//将私有变量设置为可访问
  19. String type = (String) typeF.get(null);//获取静态变量传参直接为null即可
  20. System.out.println(type);
  21. //修改私有静态变量
  22. typeF.set(null,"狗");
  23. System.out.println((String) typeF.get(null));
  24. }
  25. }

小明 我的名字叫:小红 人类 狗

API

反射机制的相关类

与Java反射相关的类如下:

类名 用途
Class类 代表类的实体,在运行的Java应用程序中表示类和接口
Field类 代表类的成员变量(成员变量也称为类的属性)
Method类 代表类的方法
Constructor类 代表类的构造方法

Class类

Class代表类的实体,在运行的Java应用程序中表示类和接口。在这个类中提供了很多有用的方法,这里对他们简单的分类介绍。

  • 获得类相关的方法 | 方法 | 用途 | | —- | —- | | asSubclass(Class clazz) | 把传递的类的对象转换成代表其子类的对象 | | Cast | 把对象转换成代表类或是接口的对象 | | getClassLoader() | 获得类的加载器 | | getClasses() | 返回一个数组,数组中包含该类中所有公共类和接口类的对象 | | getDeclaredClasses() | 返回一个数组,数组中包含该类中所有类和接口类的对象 | | forName(String className) | 根据类名返回类的对象 | | getName() | 获得类的完整路径名字 | | newInstance() | 创建类的实例 | | getPackage() | 获得类的包 | | getSimpleName() | 获得类的名字 | | getSuperclass() | 获得当前类继承的父类的名字 | | getInterfaces() | 获得当前类实现的类或是接口 |


  • 获得类中属性相关的方法 | 方法 | 用途 | | —- | —- | | getField(String name) | 获得某个公有的属性对象 | | getFields() | 获得所有公有的属性对象 | | getDeclaredField(String name) | 获得某个属性对象 | | getDeclaredFields() | 获得所有属性对象 |
  • 获得类中构造器相关的方法 | 方法 | 用途 | | —- | —- | | getConstructor(Class…<?> parameterTypes) | 获得该类中与参数类型匹配的公有构造方法 | | getConstructors() | 获得该类的所有公有构造方法 | | getDeclaredConstructor(Class…<?> parameterTypes) | 获得该类中与参数类型匹配的构造方法 | | getDeclaredConstructors() | 获得该类所有构造方法 |
  • 获得类中方法相关的方法 | 方法 | 用途 | | —- | —- | | getMethod(String name, Class…<?> parameterTypes) | 获得该类某个公有的方法 | | getMethods() | 获得该类所有公有的方法 | | getDeclaredMethod(String name, Class…<?> parameterTypes) | 获得该类某个方法 | | getDeclaredMethods() | 获得该类所有方法 |
  • 类中其他重要的方法 | 方法 | 用途 | | —- | —- | | isAnnotation() | 如果是注解类型则返回true | | isAnnotationPresent(Class<? extends Annotation> annotationClass) | 如果是指定类型注解类型则返回true | | isAnonymousClass() | 如果是匿名类则返回true | | isArray() | 如果是一个数组类则返回true | | isEnum() | 如果是枚举类则返回true | | isInstance(Object obj) | 如果obj是该类的实例则返回true | | isInterface() | 如果是接口类则返回true | | isLocalClass() | 如果是局部类则返回true | | isMemberClass() | 如果是内部类则返回true |

Field类

Field代表类的成员变量(成员变量也称为类的属性)。

方法 用途
equals(Object obj) 属性与obj相等则返回true
get(Object obj) 获得obj中对应的属性值
set(Object obj, Object value) 设置obj中对应属性值

Method类

Method代表类的方法。

方法 用途
invoke(Object obj, Object… args) 传递object对象及参数调用该对象对应的方法

Constructor类

Constructor代表类的构造方法。

方法 用途
newInstance(Object… initargs) 根据传递的参数创建类的对象