image.png
    反射:将类的各个组成部分封装为其他对象,这就是反射机制
    好处:

    1. 可以在程序运行过程中,操作这些对象
    2. 可以解耦,提高程序的可扩展性

    获取Class对象的方式

    1. Class.forName(”全类名”):将字节码文件加载进内存,返回Class对象

    多用于配置文件,将类名定义在配置文件中。读取文件,加载类

    1. 类名.Class:通过类名的属性Class获取

    多用于参数的传递

    1. 对象.getclass():getclass()方法在Object类中定义着

    多用于对象的获取字节码的方式

    Class对象功能
    获取功能
    1.获取成员变量们
    Field[ ] getFields( ) :获取所有public修饰的成员变量
    Field getField(String name) :获取指定名称的public修饰的成员变量

    Field[ ] getDeclaredFields( ) :获取所有的成员变量,不考虑修饰符
    Field getDeclaredField(String name)
    2.获取构造方法们
    Constructor<?>[ ] getConstructors( )
    Constructor getConstructor(类<?>… parmeterTypes)**

    Constructor getDeclaredConstructor(类<?>… parameterTypes)
    Constructor<?>[ ] getDeclaredConstructors( )
    3.获取成员方法们
    Method[ ] getMethods( )
    Method getMethod(String name,类<?>… parameterTypers)

    Method[ ] getDeclaredMethods( )
    Method getDeclaredMethod(String name,类<?>… parameterTypers)
    4**.**获取类名
    String getName( )
    **
    Field:成员变量
    操作
    1.设置值
    void set(Object obj,Object value)
    2.获取值
    get(Object obj)
    3.忽略访问权限修饰符的安全检查
    setAccessible(true):暴力反射
    Person类:

    1. package HeiMa.Reflect;/*
    2. @create 2020--12--24--20:53
    3. */
    4. public class Person {
    5. private String name;
    6. private int age;
    7. public String a;
    8. protected String b;
    9. String c;
    10. private String d;
    11. public Person() {
    12. }
    13. public Person(String name, int age, String a, String b, String c, String d) {
    14. this.name = name;
    15. this.age = age;
    16. this.a = a;
    17. this.b = b;
    18. this.c = c;
    19. this.d = d;
    20. }
    21. public String getName() {
    22. return name;
    23. }
    24. public void setName(String name) {
    25. this.name = name;
    26. }
    27. public int getAge() {
    28. return age;
    29. }
    30. public void setAge(int age) {
    31. this.age = age;
    32. }
    33. public String getA() {
    34. return a;
    35. }
    36. public void setA(String a) {
    37. this.a = a;
    38. }
    39. public String getB() {
    40. return b;
    41. }
    42. public void setB(String b) {
    43. this.b = b;
    44. }
    45. public String getC() {
    46. return c;
    47. }
    48. public void setC(String c) {
    49. this.c = c;
    50. }
    51. public String getD() {
    52. return d;
    53. }
    54. public void setD(String d) {
    55. this.d = d;
    56. }
    57. @Override
    58. public String toString() {
    59. return "Person{" +
    60. "name='" + name + '\'' +
    61. ", age=" + age +
    62. ", a='" + a + '\'' +
    63. ", b='" + b + '\'' +
    64. ", c='" + c + '\'' +
    65. ", d='" + d + '\'' +
    66. '}';
    67. }
    68. public void eat() {
    69. System.out.println("eat...");
    70. }
    71. public void eat(String food) {
    72. System.out.println("eat..."+ food);
    73. }
    74. }

    获取成员变量:

    1. package HeiMa.Reflect;/*
    2. @create 2020--12--24--20:55
    3. */
    4. import java.lang.reflect.Field;
    5. public class ReflectDemo {
    6. public static void main(String[] args) throws Exception {
    7. //获取person的class对象
    8. Class personClass = Person.class;
    9. // Field[] getFields()获取所有public修饰的成员变量
    10. Field[] fields = personClass.getFields();
    11. for (Field field : fields) {
    12. System.out.println(field);
    13. }
    14. System.out.println("------------------");
    15. Field a = personClass.getField("a");
    16. //获取成员变量a的值
    17. Person person = new Person();
    18. Object o = a.get(person);
    19. System.out.println(o);
    20. a.set(person, "张三");
    21. System.out.println(person);
    22. System.out.println("===================");
    23. Field[] declaredFields = personClass.getDeclaredFields();
    24. for (Field declaredField : declaredFields) {
    25. System.out.println(declaredField);
    26. }
    27. //field getDeclaredField(String name)
    28. Field d = personClass.getDeclaredField("d");
    29. //忽略访问权限修饰符的安全检查
    30. d.setAccessible(true);//暴力反射
    31. Object o1 = d.get(person);
    32. System.out.println(o1);
    33. }
    34. }

    Constructor:构造方法
    创建对象:
    T newInstance(Object……initargs)

    如果使用空参数构造方法创建对象,操作可以简化:Class对象的newInstance

    获取构造方法:

    1. package HeiMa.Reflect;/*
    2. @create 2020--12--24--20:55
    3. */
    4. import java.lang.reflect.Constructor;
    5. import java.lang.reflect.Field;
    6. public class ReflectDemo2 {
    7. public static void main(String[] args) throws Exception {
    8. //获取person的class对象
    9. Class personClass = Person.class;
    10. Constructor constructor = personClass.getConstructor(String.class, int.class,String.class,String.class,String.class,String.class);
    11. System.out.println(constructor);
    12. //创建对象
    13. Object person = constructor.newInstance("张三", 28,"a","b","c","d");
    14. System.out.println(person);
    15. System.out.println("---------------------");
    16. Constructor constructor1 = personClass.getConstructor();
    17. System.out.println(constructor1);
    18. //创建对象
    19. Object o = constructor1.newInstance();
    20. System.out.println(o);
    21. Object o1 = personClass.newInstance();
    22. System.out.println(o1);
    23. }
    24. }

    Method:方法对象
    执行方法
    Object invoke(Object obj,Object…… args)

    获取方法名称:
    String getName:获取方法名

    获取方法对象及方法名:

    1. package HeiMa.Reflect;/*
    2. @create 2020--12--24--20:55
    3. */
    4. import java.lang.reflect.Constructor;
    5. import java.lang.reflect.Method;
    6. public class ReflectDemo3 {
    7. public static void main(String[] args) throws Exception {
    8. //获取person的class对象
    9. Class personClass = Person.class;
    10. //获取指定名称的方法
    11. Method eat = personClass.getMethod("eat");
    12. Person p = new Person();
    13. //执行方法
    14. eat.invoke(p);
    15. Method eat1 = personClass.getMethod("eat", String.class);
    16. //执行方法
    17. eat1.invoke(p, "饭");
    18. System.out.println("-----------");
    19. //获取所有public修饰的方法
    20. Method[] methods = personClass.getMethods();
    21. for (Method method : methods) {
    22. System.out.println(method);
    23. System.out.println(method.getName());
    24. }
    25. //获取类名
    26. String name = personClass.getName();
    27. System.out.println(name);
    28. }
    29. }

    同一个字节码文件(*.class)在一次程序运行过程中,只会被加载一次,不论通过哪一种方式获取的Class对象都是同一个

    Java反射机制是Java中底层的一个功能,就是通过这个机制可以进行对象的灵活的调用和处理
    在后期学习中会用到反射的相关的内容,但是都是底层的理解,比如:文件的加载,spring框架底层……

    目前我们讲反射是讲解反射的使用

    Java中提供了一个api - Class用于反射机制的一个类
    是在Java.lang包下的,不需要导包

    当前案例演示利用反射的机制获取对象的属性

    1. package Test25_Demo.TestDemo2;/*
    2. @create 2020--12--18--10:14
    3. */
    4. import org.junit.Test;
    5. public class ReflectDemo {
    6. //新建对象的获取直接使用反射获取 - 不适用new
    7. //单元测试
    8. @Test
    9. public void test1() {
    10. //已知明确的类型,获取Class对象
    11. Class clazz = Student.class;
    12. System.out.println(clazz);//class Test25_Demo.TestDemo2.Student
    13. }
    14. @Test
    15. public void test2() {
    16. //已知对象获取class对象
    17. Student s = new Student();
    18. Class clazz = s.getClass();//getClass()是顶级父类Object中的方法
    19. System.out.println(clazz);//class Test25_Demo.TestDemo2.Student
    20. }
    21. @Test
    22. public void test3() throws ClassNotFoundException {
    23. //完全限定名(包名.类名),获取Class对象 - 比较常用 - 安全
    24. String className = "Test25_Demo.TestDemo2.Student";
    25. //forName()返回这个地址值所对应的类
    26. Class<?> aClass = Class.forName(className);
    27. System.out.println(aClass);//class Test25_Demo.TestDemo2.Student
    28. }
    29. //测试结果:通过不同的反射获取的对象是同一个
    30. @Test
    31. public void test4() throws ClassNotFoundException {
    32. Class clazz1 = Student.class;
    33. Student s1 = new Student();
    34. Class clazz2 = s1.getClass();
    35. String className = "Test25_Demo.TestDemo2.Student";
    36. Class<?> aClass = Class.forName(className);
    37. //比较
    38. System.out.println(clazz1 == clazz2);//true
    39. System.out.println(clazz2 == aClass);//true
    40. System.out.println(clazz1 == aClass);//true
    41. }
    42. }
    1. package Test25_Demo.TestDemo2;/*
    2. @create 2020--12--18--10:14
    3. */
    4. import org.junit.Test;
    5. import java.lang.reflect.Constructor;
    6. import java.lang.reflect.InvocationTargetException;
    7. /**
    8. * 通过Java反射机制构建对象的测试 - 这些操作平时只要我们创建对象,内存中就偷偷的帮我们做了
    9. * 步骤:
    10. * 1.创建该类的Class对象
    11. * 2.利用Class对象去创建类对象
    12. * 3.利用Class对象中的newInstance方法创建对象,类中有公共的无参构造方法
    13. * 4.最后获取Class类中的构造函数对象,通过构造函数创建实例对象
    14. */
    15. public class ReflectDemo2 {
    16. @Test
    17. public void test01() throws IllegalAccessException, InstantiationException {
    18. //类中有无参构造方法
    19. Class clazz = Student.class;
    20. Object obj = clazz.newInstance();//默认调用的是无参的 - 创建实例
    21. System.out.println(clazz);//class Test25_Demo.TestDemo2.Student
    22. System.out.println(obj);//Student{id=0, name='null'} - 当前的Object进行了向下转型给了反射获取到的类Student
    23. }
    24. @Test
    25. public void test02() throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
    26. //获取Class类中的构造函数对象
    27. Class clazz = Student.class;
    28. //获取到构造函数 - 有参
    29. Constructor constructor = clazz.getConstructor(int.class, String.class);
    30. //通过构造函数为属性赋值
    31. Object tom = constructor.newInstance(20, "Tom");//Student{id=20, name='Tom'}
    32. System.out.println(tom);
    33. }
    34. //演示普通的方式实例化对象做不到的事情
    35. @Test
    36. public void test03() {
    37. Student s = new Student();
    38. s.setId(1);
    39. //s.setName();//不能进行name的赋值,因为方法是私有的
    40. System.out.println(s);//Student{id=1, name='null'}
    41. }
    42. }