参考文章:https://blog.csdn.net/sinat_38259539/article/details/71799078

       https://blog.csdn.net/wanderlustLee/article/details/80431305

1、前置知识

1.1、java虚拟机的方法区

java虚拟机有一个运行时数据区,这个数据区又被分为方法区,堆区和栈区,我们这里需要了解的主要是方法区。

方法区主要用来存放已经被虚拟机加载的类信息、静态变量、方法等信息。

当虚拟机需要装载某个类的时候,需要类装载器定位相应的class文件,然后将其读入到java虚拟机中,紧接着虚拟机提取class中的类型信息,将这些信息存储到方法区中。

1.2、Class类

在程序运行期间,java运行时系统始终为所有对象维护一个被称为运行时的类型标识。这个信息跟踪着每个对象所属的类。虚拟机利用运行时类型信息选择相应的方法执行。包含这些信息的类被称为Class。

Class 没有公共构造方法。Class 对象是在加载类时由 Java 虚拟机以及通过调用类加载器中的defineClass 方法自动构造的。也就是这不需要我们自己去处理创建,JVM已经帮我们创建好了。

反射的本质就是得到class对象后反向获取对应对象的各种信息。

2、什么是反射?

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

自己的理解:反射就是利用Class对象把java类中的各种成分(成员变量、构造方法、方法等信息)映射成一个个的java对象。

3、反射能做什么?为什么要使用反射?

直接创建对象不就行了,为什么要用反射?这里首先要明白动态和静态的概念。

静态编译:在编译时确定类型,绑定对象,即通过。
动态编译:运行时确定类型,绑定对象。动态编译最大限度发挥了java的灵活性,体现了多态的应用,有以降低类之间的藕合性。
一句话,反射机制的优点就是可以实现动态创建对象和编译,体现出很大的灵活性,特别是在J2EE的开发中它的灵活性就表现的十分明显。

比如,一个大型的软件,不可能一次就把把它设计的很完美,当这个程序编译后,发布了,当发现需要更新某些功能时,我们不可能要用户把以前的卸载,再重新安装新的版本,假如这样的话,这个软件肯定是没有多少人用的。
采用静态的话,需要把整个程序重新编译一次才可以实现功能的更新,而采用反射机制的话,它就可以不用卸载,只需要在运行时才动态的创建和编译,就可以实现该功能。它的缺点是对性能有影响。

反射机制可以帮我们做那些重复的有规律的事情,现在很多的自动生成代码的软件就是运用反射机制来完成的。

反射最重要的用途就是开发各种通用框架,比如在spring中,我们将所有的类Bean交给spring容器管理,无论是XML配置Bean还是注解配置,当我们从容器中获取Bean来依赖注入时,容器会读取配置,而配置中给的就是类的信息,spring根据这些信息,需要创建那些Bean,spring就动态的创建这些类。

还有在我们创建数据库链接时,这句代码Class tc = Class.forName("com.java.dbtest.TestConnection")就是告诉JVM去加载这个类,而加载的过程是在程序执行过程中动态加载的。通过类的全类名让jvm在服务器中找到并加载这个类,而如果是使用别的数据库,那就要换一个类了,如果是传统写死的方法创建,就要修改原来类的代码,而对于反射,则只是传入的参数就变成另一个了而已,可以通过修改配置文件,而不是直接修改代码。

4、反射的基本使用

4.1、反射机制获取类有三种方法

  1. package fanshe;
  2. /**
  3. * 获取Class对象的三种方式
  4. * 1 Object ——> getClass();
  5. * 2 任何数据类型(包括基本数据类型)都有一个“静态”的class属性
  6. * 3 通过Class类的静态方法:forName(String className)(常用)
  7. *
  8. */
  9. public class Fanshe {
  10. public static void main(String[] args) {
  11. //第一种方式获取Class对象
  12. Student stu1 = new Student();//这一new 产生一个Student对象,一个Class对象。
  13. Class stuClass = stu1.getClass();//获取Class对象
  14. System.out.println(stuClass.getName());
  15.  
  16. //第二种方式获取Class对象
  17. Class stuClass2 = Student.class;
  18. System.out.println(stuClass == stuClass2);//判断第一种方式获取的Class对象和第二种方式获取的是否是同一个
  19.  
  20. //第三种方式获取Class对象
  21. try {
  22. Class stuClass3 = Class.forName("fanshe.Student");//注意此字符串必须是真实路径,就是带包名的类路径,包名.类名
  23. System.out.println(stuClass3 == stuClass2);//判断三种方式是否获取的是同一个Class对象
  24. } catch (ClassNotFoundException e) {
  25. e.printStackTrace();
  26. }
  27.  
  28. }
  29. }

关于三种方式的选择:

  常用第三种,可以字符串传入也可以写在配置文件中,可通过getName()获取对象的全限定名,另外这个类必须在classpath路径下,不然会抛出 ClassNotFoundException 的异常。

  第一种对象都有了,不需要用反射。

  第二种需要导入类的包,依赖太强,不导包就抛编译错误。一般用于导入的包没有源码,只有class文件,需要修改方法或属性的情况。

4.2、通过反射获取构造函数并使用

student类(共六个构造函数):

  1. package fanshe;
  2.  
  3. public class Student {
  4.  
  5. //---------------构造方法-------------------
  6. //(默认的构造方法)
  7. Student(String str){
  8. System.out.println("(默认)的构造方法 s = " + str);
  9. }
  10.  
  11. //无参构造方法
  12. public Student(){
  13. System.out.println("调用了公有、无参构造方法执行了。。。");
  14. }
  15.  
  16. //有一个参数的构造方法
  17. public Student(char name){
  18. System.out.println("姓名:" + name);
  19. }
  20.  
  21. //有多个参数的构造方法
  22. public Student(String name ,int age){
  23. System.out.println("姓名:"+name+"年龄:"+ age);//这的执行效率有问题,以后解决。
  24. }
  25.  
  26. //受保护的构造方法
  27. protected Student(boolean n){
  28. System.out.println("受保护的构造方法 n = " + n);
  29. }
  30.  
  31. //私有构造方法
  32. private Student(int age){
  33. System.out.println("私有的构造方法 年龄:"+ age);
  34. }
  35.  
  36. }

测试类:

  1. package fanshe;
  2.  
  3. import java.lang.reflect.Constructor;
  4.  
  5. /*
  6. * 通过Class对象可以获取某个类中的:构造方法、成员变量、成员方法;并访问成员;
  7. *
  8. * 1.获取构造方法:
  9. * 1).批量的方法:
  10. * public Constructor[] getConstructors():所有"公有的"构造方法
  11. public Constructor[] getDeclaredConstructors():获取所有的构造方法(包括私有、受保护、默认、公有)
  12.  
  13. * 2).获取单个的方法,并调用:
  14. * public Constructor getConstructor(Class... parameterTypes):获取单个的"公有的"构造方法:
  15. * public Constructor getDeclaredConstructor(Class... parameterTypes):获取"某个构造方法"可以是私有的,或受保护、默认、公有;
  16. *
  17. * 调用构造方法:
  18. * Constructor-->newInstance(Object... initargs)
  19. */
  20. public class Constructors {
  21.  
  22. public static void main(String[] args) throws Exception {
  23. //1.加载Class对象
  24. Class clazz = Class.forName("fanshe.Student");
  25.  
  26. //2.获取所有公有构造方法
  27. System.out.println("**********************所有公有构造方法*********************************");
  28. Constructor[] conArray = clazz.getConstructors();
  29. for(Constructor c : conArray){
  30. System.out.println(c);
  31. }
  32.  
  33. System.out.println("************所有的构造方法(包括:私有、受保护、默认、公有)***************");
  34. conArray = clazz.getDeclaredConstructors();
  35. for(Constructor c : conArray){
  36. System.out.println(c);
  37. }
  38.  
  39. System.out.println("*****************获取公有、无参的构造方法*******************************");
  40. Constructor con = clazz.getConstructor(null);
  41. //1>、因为是无参的构造方法所以类型是一个null,不写也可以:这里需要的是一个参数的类型,切记是类型
  42. //2>、返回的是描述这个无参构造函数的类对象。
  43.  
  44. System.out.println("con = " + con);
  45. //调用构造方法
  46. Object obj = con.newInstance();
  47. // System.out.println("obj = " + obj);
  48. // Student stu = (Student)obj;
  49.  
  50. System.out.println("******************获取私有构造方法,并调用*******************************");
  51. con = clazz.getDeclaredConstructor(char.class);
  52. System.out.println(con);
  53. //调用构造方法
  54. con.setAccessible(true);//暴力访问(忽略掉访问修饰符,允许访问私有成员)
  55. obj = con.newInstance('男');
  56. }
  57.  
  58. }

输出:

  1. **********************所有公有构造方法*********************************
  2. public fanshe.Student(java.lang.String,int)
  3. public fanshe.Student(char)
  4. public fanshe.Student()
  5. ************所有的构造方法(包括:私有、受保护、默认、公有)***************
  6. private fanshe.Student(int)
  7. protected fanshe.Student(boolean)
  8. public fanshe.Student(java.lang.String,int)
  9. public fanshe.Student(char)
  10. public fanshe.Student()
  11. fanshe.Student(java.lang.String)
  12. *****************获取公有、无参的构造方法*******************************
  13. con = public fanshe.Student()
  14. 调用了公有、无参构造方法执行了。。。
  15. ******************获取私有构造方法,并调用*******************************
  16. public fanshe.Student(char)
  17. 姓名:男

4.3、获取成员变量并调用

student类:

  1. package fanshe.field;
  2.  
  3. public class Student {
  4. public Student(){
  5.  
  6. }
  7. //**********字段*************//
  8. public String name;
  9. protected int age;
  10. char sex;
  11. private String phoneNum;
  12.  
  13. @Override
  14. public String toString() {
  15. return "Student [name=" + name + ", age=" + age + ", sex=" + sex
  16. + ", phoneNum=" + phoneNum + "]";
  17. }
  18.  
  19. }

测试类:

  1. package fanshe.field;
  2. import java.lang.reflect.Field;
  3. /*
  4. * 获取成员变量并调用:
  5. *
  6. * 1.批量的
  7. * 1).Field[] getFields():获取所有的"公有字段"
  8. * 2).Field[] getDeclaredFields():获取所有字段,包括:私有、受保护、默认、公有;
  9. * 2.获取单个的:
  10. * 1).public Field getField(String fieldName):获取某个"公有的"字段;
  11. * 2).public Field getDeclaredField(String fieldName):获取某个字段(可以是私有的)
  12. *
  13. * 设置字段的值:
  14. * Field --> public void set(Object obj,Object value):
  15. * 参数说明:
  16. * 1.obj:要设置的字段所在的对象;
  17. * 2.value:要为字段设置的值;
  18. *
  19. */
  20. public class Fields {
  21.  
  22. public static void main(String[] args) throws Exception {
  23. //1.获取Class对象
  24. Class stuClass = Class.forName("fanshe.field.Student");
  25. //2.获取字段
  26. System.out.println("************获取所有公有的字段********************");
  27. Field[] fieldArray = stuClass.getFields();
  28. for(Field f : fieldArray){
  29. System.out.println(f);
  30. }
  31. System.out.println("************获取所有的字段(包括私有、受保护、默认的)********************");
  32. fieldArray = stuClass.getDeclaredFields();
  33. for(Field f : fieldArray){
  34. System.out.println(f);
  35. }
  36. System.out.println("*************获取公有字段**并调用***********************************");
  37. Field f = stuClass.getField("name");
  38. System.out.println(f);
  39. //获取一个对象
  40. Object obj = stuClass.getConstructor().newInstance();//产生Student对象--》Student stu = new Student();
  41. //为字段设置值
  42. f.set(obj, "刘德华");//为Student对象中的name属性赋值--》stu.name = "刘德华"
  43. //验证
  44. Student stu = (Student)obj;
  45. System.out.println("验证姓名:" + stu.name);
  46.  
  47. System.out.println("**************获取私有字段****并调用********************************");
  48. f = stuClass.getDeclaredField("phoneNum");
  49. System.out.println(f);
  50. f.setAccessible(true);//暴力反射,解除私有限定
  51. f.set(obj, "18888889999");
  52. System.out.println("验证电话:" + stu);
  53.  
  54. }
  55. }

输出:

  1. ************获取所有公有的字段********************
  2. public java.lang.String fanshe.field.Student.name
  3. ************获取所有的字段(包括私有、受保护、默认的)********************
  4. public java.lang.String fanshe.field.Student.name
  5. protected int fanshe.field.Student.age
  6. char fanshe.field.Student.sex
  7. private java.lang.String fanshe.field.Student.phoneNum
  8. *************获取公有字段**并调用***********************************
  9. public java.lang.String fanshe.field.Student.name
  10. 验证姓名:刘德华
  11. **************获取私有字段****并调用********************************
  12. private java.lang.String fanshe.field.Student.phoneNum
  13. 验证电话:Student [name=刘德华, age=0, sex=

4.4、获取成员方法并调用

  1. package fanshe.method;
  2.  
  3. public class Student {
  4. //**************成员方法***************//
  5. public void show1(String s){
  6. System.out.println("调用了:公有的,String参数的show1(): s = " + s);
  7. }
  8. protected void show2(){
  9. System.out.println("调用了:受保护的,无参的show2()");
  10. }
  11. void show3(){
  12. System.out.println("调用了:默认的,无参的show3()");
  13. }
  14. private String show4(int age){
  15. System.out.println("调用了,私有的,并且有返回值的,int参数的show4(): age = " + age);
  16. return "abcd";
  17. }
  18. }

测试类:

  1. package fanshe.method;
  2.  
  3. import java.lang.reflect.Method;
  4.  
  5. /*
  6. * 获取成员方法并调用:
  7. *
  8. * 1.批量的:
  9. * public Method[] getMethods():获取所有"公有方法";(包含了父类的方法也包含Object类)
  10. * public Method[] getDeclaredMethods():获取所有的成员方法,包括私有的(不包括继承的)
  11. * 2.获取单个的:
  12. * public Method getMethod(String name,Class<?>... parameterTypes):
  13. * 参数:
  14. * name : 方法名;
  15. * Class ... : 形参的Class类型对象
  16. * public Method getDeclaredMethod(String name,Class<?>... parameterTypes)
  17. *
  18. * 调用方法:
  19. * Method --> public Object invoke(Object obj,Object... args):
  20. * 参数说明:
  21. * obj : 要调用方法的对象;
  22. * args:调用方式时所传递的实参;
  23. ):
  24. */
  25. public class MethodClass {
  26.  
  27. public static void main(String[] args) throws Exception {
  28. //1.获取Class对象
  29. Class stuClass = Class.forName("fanshe.method.Student");
  30. //2.获取所有公有方法
  31. System.out.println("***************获取所有的”公有“方法*******************");
  32. stuClass.getMethods();
  33. Method[] methodArray = stuClass.getMethods();
  34. for(Method m : methodArray){
  35. System.out.println(m);
  36. }
  37. System.out.println("***************获取所有的方法,包括私有的*******************");
  38. methodArray = stuClass.getDeclaredMethods();
  39. for(Method m : methodArray){
  40. System.out.println(m);
  41. }
  42. System.out.println("***************获取公有的show1()方法*******************");
  43. Method m = stuClass.getMethod("show1", String.class);
  44. System.out.println(m);
  45. //实例化一个Student对象
  46. Object obj = stuClass.getConstructor().newInstance();
  47. m.invoke(obj, "刘德华");
  48.  
  49. System.out.println("***************获取私有的show4()方法******************");
  50. m = stuClass.getDeclaredMethod("show4", int.class);
  51. System.out.println(m);
  52. m.setAccessible(true);//解除私有限定
  53. Object result = m.invoke(obj, 20);//需要两个参数,一个是要调用的对象(获取有反射),一个是实参
  54. System.out.println("返回值:" + result);
  55.  
  56. }
  57. }

输出:

  1. ***************获取所有的”公有“方法*******************
  2. public void fanshe.method.Student.show1(java.lang.String)
  3. public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
  4. public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
  5. public final void java.lang.Object.wait() throws java.lang.InterruptedException
  6. public boolean java.lang.Object.equals(java.lang.Object)
  7. public java.lang.String java.lang.Object.toString()
  8. public native int java.lang.Object.hashCode()
  9. public final native java.lang.Class java.lang.Object.getClass()
  10. public final native void java.lang.Object.notify()
  11. public final native void java.lang.Object.notifyAll()
  12. ***************获取所有的方法,包括私有的*******************
  13. public void fanshe.method.Student.show1(java.lang.String)
  14. private java.lang.String fanshe.method.Student.show4(int)
  15. protected void fanshe.method.Student.show2()
  16. void fanshe.method.Student.show3()
  17. ***************获取公有的show1()方法*******************
  18. public void fanshe.method.Student.show1(java.lang.String)
  19. 调用了:公有的,String参数的show1(): s = 刘德华
  20. ***************获取私有的show4()方法******************
  21. private java.lang.String fanshe.method.Student.show4(int)
  22. 调用了,私有的,并且有返回值的,int参数的show4(): age = 20
  23. 返回值:abcd

4.5、反射Main方法

  1. package fanshe.main;
  2.  
  3. public class Student {
  4.  
  5. public static void main(String[] args) {
  6. System.out.println("main方法执行了。。。");
  7. }
  8. }
  1. package fanshe.main;
  2.  
  3. import java.lang.reflect.Method;
  4.  
  5. /**
  6. * 获取Student类的main方法、不要与当前的main方法搞混了
  7. */
  8. public class Main {
  9.  
  10. public static void main(String[] args) {
  11. try {
  12. //1、获取Student对象的字节码
  13. Class clazz = Class.forName("fanshe.main.Student");
  14.  
  15. //2、获取main方法
  16. Method methodMain = clazz.getMethod("main", String[].class);//第一个参数:方法名称,第二个参数:方法形参的类型,
  17. //3、调用main方法
  18. // methodMain.invoke(null, new String[]{"a","b","c"});
  19. //第一个参数,对象类型,因为方法是static静态的,所以为null可以,第二个参数是String数组,这里要注意在jdk1.4时是数组,jdk1.5之后是可变参数
  20. //这里拆的时候将 new String[]{"a","b","c"} 拆成3个对象。。。所以需要将它强转。
  21. methodMain.invoke(null, (Object)new String[]{"a","b","c"});//方式一
  22. // methodMain.invoke(null, new Object[]{new String[]{"a","b","c"}});//方式二
  23.  
  24. } catch (Exception e) {
  25. e.printStackTrace();
  26. }
  27.  
  28. }
  29. }

输出:main方法执行了。。。

【java】-- java反射机制的更多相关文章

  1. Java 类反射机制分析

    Java 类反射机制分析 一.反射的概念及在Java中的类反射 反射主要是指程序可以访问.检测和修改它本身状态或行为的一种能力.在计算机科学领域,反射是一类应用,它们能够自描述和自控制.这类应用通过某 ...

  2. java的反射机制

    一.java的反射机制浅谈 最近研究java研究得很给力,主要以看博文为学习方式.以下是我对java的反射机制所产生的一些感悟,希望各位童鞋看到失误之处不吝指出.受到各位指教之处,如若让小生好好感动, ...

  3. Java中反射机制和Class.forName、实例对象.class(属性)、实例对象getClass()的区别

    一.Java的反射机制   每个Java程序执行前都必须经过编译.加载.连接.和初始化这几个阶段,后三个阶段如下图:   其中

  4. java笔记--反射机制之基础总结与详解

    一.反射之实例化Class类的5种方式: java的数据类型可以分为两类,即引用类型和原始类型(即基本数据类型). 对于每种类型的对象,java虚拟机会实例化不可变的java.lang.Class对象 ...

  5. JAVA的反射机制学习笔记(二)

    上次写JAVA的反射机制学习笔记(一)的时候,还是7月22号,这些天就瞎忙活了.自己的步伐全然被打乱了~不能继续被动下去.得又一次找到自己的节奏. 4.获取类的Constructor 通过反射机制得到 ...

  6. java笔录---反射机制(1)

    引言   为了方便记忆java的反射机制,在这里仔细的总结了一下.主要是怕以后忘记了,这样也方便回忆.因为最近利用空余时间深入的了解spring和Mybatis框架,   像spring中核心模块IO ...

  7. Java高新技术 反射机制

     Java高新技术 反射机制 知识概要:                   (1)反射的基石 (2)反射 (3)Constructor类 (4)Field类 (5)Method类 (6)用反射方 ...

  8. java的反射机制浅谈(转)

    原文链接:java的反射机制浅谈 一.java的反射机制浅谈 1.何谓反射机制 根据网文,java中的反射机制可以如此定义: JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性 ...

  9. 【转】Java利用反射机制访问私有化构造器

    Java利用反射机制访问私有化构造器 博客分类: java   我们都知道,当一个类的构造方法被设为私有的时候(private),在其他类中是无法用new来实例化一个对象的. 但是有一种方法可以把带有 ...

  10. 【转】java原理—反射机制

    一.什么是反射:反射的概念是由Smith在1982年首次提出的,主要是指程序可以访问.检测和修改它本身状态或行为的一种能力.这一概念的提出很快引发了计算机科学领域关于应用反射性的研究.它首先被程序语言 ...

随机推荐

  1. 2018-2019-2 《Java程序设计》第7周学习总结

    20175319 2018-2019-2 <Java程序设计>第7周学习总结 教材学习内容总结 本周学习<Java程序设计>第8章: 1.String类: Java专门提供了用 ...

  2. XSS绕过<>进行测试

    大家都知道,普遍的防御XSS攻击的方法是在后台对以下字符进行转义:<.>.’.”,但是经过本人的研究发现,在一些特殊场景下,即使对以上字符进行了转义,还是可以执行XSS攻击的. 首先看一个 ...

  3. 用python3读CSV文件,出现UnicodeDecodeError: 'utf-8' codec can't decode byte 0xd0 in position 0: invalid con

    使用pd.read_csv()读csv文件时,出现如下错误: UnicodeDecodeError: ‘utf-8’ codec can’t decode byte 0xd0 in position ...

  4. cocos2d-x入门学习笔记——Hello world分析

    Hello world分析 1. “resource”文件夹 用于存放图片.音频和配置等资源文件.为了方便管理,可以创建在其中创建子文件夹.Cocos2d-x为我们屏蔽了不同平台对于文件路径的定义. ...

  5. element-ui多选框模糊搜索输入文字闪动问题

    .el-select__tags { .el-select__input { width: 50px !important; } } 添加这段代码即可 <el-select v-model=&q ...

  6. python2x如何迁移代码到python3中

    2to3 - 自动Python 2到3代码转换 2to3是一个Python程序,它读取Python 2.x源代码并应用一系列修复程序将其转换为有效的Python 3.x代码.标准库包含一组丰富的修复程 ...

  7. React 轮播图实现

    接到项目, 用react和material-ui实现轮播图. 搜索了一些方法参考, 不论语言/框架的使用,大体上分为两种思路 超宽列表实现法 在原生JS或者JQuery中,轮播图的实现一般是这样子的 ...

  8. boston_housing-多分类问题

    from keras.datasets import boston_housing import numpy as np from keras import models from keras imp ...

  9. HeatMap

    Reprinting From https://blog.csdn.net/JNingWei/article/details/78803669 ColorMap(色度图) 在图像处理中,伪色彩用途广泛 ...

  10. stat 文件三个时间点

    Linux文件3个时间点(access time,modify time,change time) access time:表示最后一次访问(仅仅是访问,没有改动)文件的时间. 注意:至于为什么会出现 ...