最新消息: USBMI致力于为网友们分享Windows、安卓、IOS等主流手机系统相关的资讯以及评测、同时提供相关教程、应用、软件下载等服务。

java反射机制原理,为什么需要反射,反射的作用

互联网 admin 2浏览 0评论

java反射机制原理,为什么需要反射,反射的作用

最近在学java反射以及动态代理,好多博客都写的十分官方。就自己整合些资料。加深java反射机制的理解。

在说反射之前,我们要先了解动态语言和静态语言的概念:

动态类型语言

所谓动态类型语言,就是类型的检查是在运行时才做。
动态类型在解释语言中极为普遍,如 JavaScript、Perl、Python、Ruby 等等

静态类型语言

静态类型语言的类型检查是在运行前的编译阶段,比如 C#、Java 等都是静态类型语言,静态类型语言为了达到多态会采取一些类型鉴别手段,如继承、接口,而动态类型语言却不需要

注意:但是JAVA有着一个非常突出的动态相关机制——Reflection(反射),用在Java身上指的是可以于运行时加载、探知、使用编译期间完全知的classes。换句话说,Java程序可以加载一个运行时才得知名称的class获悉其完整构造(但不包括methods定义),并生成其对象例(newInstance)或对其fields设值,或唤起(invoke)其methods方法。

什么叫反射机制?

反射机制是在运行状态中:

  • 对于任意一个类,都能够知道这个类的所有属性和方法。
  • 对于任意一个对象,都能够调用它的任意一个方法和属性。

反射的应用

我们可能听过,Java编写的程序,一次编译,到处运行。这也是Java程序为什么是无关平台的所在,原因在于,java的源代码会被编译成.class文件字节码,只要装有Java虚拟机JVM的地方(Java提供了各种不同平台上的虚拟机制。).class文件才可以在运行加载。

  • 第一步:由Java编译器进行源代码编译,得到相应类的字节码.class文件。
  • 第二步:生成class文件之后,通过ClassLoader类加载器加载进内存,Java字节码由JVM执行解释给目标计算机。
  • 第三步,目标计算机将结果呈现给我们计算机用户;因此,Java并不是编译机制,而是解释机制.class文件才可以在不同平台上运行加载。


Java的反射机制,操作的就是这个.class文件,首先加载相应类的字节码(运行编译器idea的时候,.class文件的字节码会加载到内存中),随后解剖(反射 reflect)出字节码中的构造函数、方法以及变量(字段),或者说是取出,我们先来定义一个类Person,里面定义一些构造函数,方法,以及变量:

package com.ztb.entity;
public class Person {private int age;private String name;/*** 有参构造器* @param name* @param age*/public Person( String name,int age) {this.age = age;this.name = name;}/*** 无参构造器*/public Person() {}//公有 有参方法public void public_show(String str,int i){System.out.println("public show "+str+"..."+i);}//公有 无参方法public void public_prin(){System.out.println("公有无参代码块。。。。");}//私有 有参方法private void private_show(String str,int i){System.out.println("私有有参代码块:private show "+str+"..."+i);}//私有 无参方法private void private_prin(){System.out.println("私有无参方法代码块:private prin");}
}

新建测试类TestClass

  //获取字节码文件中 方法 再取出其公有方法String classname = "com.ztb.entity.Person";//必须是全路径类名//寻找名称的类文件,加载进内存 产生class对象Class cl = Class.forName(classname);//获取一个Person对象System.out.println("获取一个Person对象:");Object obj=cl.newInstance();System.out.println();//1.获取 公有 无参方法  public void public_prin()Method Person_public_prin=cl.getMethod("public_prin",null);System.out.println("获取执行 public void public_prin ()方法:");Person_public_prin.invoke(obj,null);//obj 是这个类的实例System.out.println();//2.获取 公有 有参方法 public void public_show(java.lang.String,int)Method Person_public_show=cl.getMethod("public_show",String.class,int.class);System.out.println("获取执行 public void public_show(java.lang.String,int) :");Person_public_show.invoke(obj,"神奇的公有有参构造方法下的我",12);System.out.println();//3.获取 私有 无参方法  private void private_show()Method Person_private_prin=cl.getDeclaredMethod("private_prin",null);Person_private_prin.setAccessible(true);System.out.println("获取执行  private void private_show():");Person_private_prin.invoke(obj,null);System.out.println();//4.获取私有有参方法  private_prin(java.lang.String,int)Method Person_private_show=cl.getDeclaredMethod("private_show",String.class,int.class);Person_private_show.setAccessible(true);System.out.println("获取执行 private void demo2.Person.private_show(java.lang.String,int) :");Person_private_show.invoke(obj,"神奇的私有有参构造方法下的我 :",23);System.out.println();/*** 获取所有已经声明的公有的方法或者私有方法*/Method[] methods=cl.getDeclaredMethods();for (Method method: methods){System.out.println("方法名:"+method.getName()+"返回值类型:"+method.getGenericReturnType().getTypeName());}}

运行结果如图示:

为什么new一个对象那么简单,非要用反射技术中的newInstance?
为什么,我可以直接对象a1. 变量访问变量,却非要用反射那么费劲的获得name字段呢?
为什么,我几行代码就能搞定的事情,非要用反射呢?

假设我们定义了很多类,有Animal、Person、Car… ,如果我想要一个Animal实例,那我就new Animal(),如果另一个人想要一个Person实例,那么他需要new Person(),当然,另一个说,我只要一个Car实例,于是它要new Car()…这样一来就导致,每个用户new的对象需求不相同,因此他们只能修改源代码,并重新编译才能生效。这种将new的对象写死在代码里的方法非常不灵活,因此,为了避免这种情况的方法,Java提供了反射机制,典型的应用如下:

我们知道Spring的IOC,即“控制反转”(通过第三方配置文件实现对 对象的控制)。简单说是将我们设计好的对象交给容器控制,而不是直接交给程序内部进行对象的控制。

比如,在Spring中,我们经常看到:

针对上述的配置,我们Spring是怎么帮助我们实例化对象,并放到容器中去了呢? 没错,就是通过反射!!!!

我们看下,下面的伪代码实现过程:

java
//解析<bean .../>元素的id属性得到该字符串值为"sqlSessionFactory" String idStr = "sqlSessionFactory";  //解析<bean .../>元素的class属性得到该字符串值为"org.mybatis.spring.SqlSessionFactoryBean"  String classStr = "org.mybatis.spring.SqlSessionFactoryBean";  //利用反射知识,通过classStr获取Class类对象  Class cls = Class.forName(classStr);  //实例化对象  Object obj = cls.newInstance();  //container表示Spring容器  container.put(idStr, obj);  //当一个类里面需要用另一类的对象时,我们继续下面的操作//解析<property .../>元素的name属性得到该字符串值为“dataSource”  String nameStr = "dataSource";  //解析<property .../>元素的ref属性得到该字符串值为“dataSource”  String refStr = "dataSource";  //生成将要调用setter方法名  String setterName = "set" + nameStr.substring(0, 1).toUpperCase()  + nameStr.substring(1);  //获取spring容器中名为refStr的Bean,该Bean将会作为传入参数  Object paramBean = container.get(refStr);  //获取setter方法的Method类,此处的cls是刚才反射代码得到的Class对象  Method setter = cls.getMethod(setterName, paramBean.getClass());  //调用invoke()方法,此处的obj是刚才反射代码得到的Object对象  setter.invoke(obj, paramBean);

我们经常提到的Java web框架中,里面就用到了反射机制,只要在代码或配置文件中看到类的完全限定名(包名+类名),其底层原理基本上使用的就是Java的反射机制。

获得反射入口的三种方式(获得类)

1).Class.forName(全类名)(推荐使用)

Class<?> classStu = Class.forName("reflect.Student");System.out.println(classStu);

2).类名.class

Class<?> classStu2 = Student.class;System.out.println(classStu2);

3).对象.getClass()

Student stu = new Student();Class<?> classStu3 = stu.getClass();System.out.println(classStu3);

java反射机制原理,为什么需要反射,反射的作用

最近在学java反射以及动态代理,好多博客都写的十分官方。就自己整合些资料。加深java反射机制的理解。

在说反射之前,我们要先了解动态语言和静态语言的概念:

动态类型语言

所谓动态类型语言,就是类型的检查是在运行时才做。
动态类型在解释语言中极为普遍,如 JavaScript、Perl、Python、Ruby 等等

静态类型语言

静态类型语言的类型检查是在运行前的编译阶段,比如 C#、Java 等都是静态类型语言,静态类型语言为了达到多态会采取一些类型鉴别手段,如继承、接口,而动态类型语言却不需要

注意:但是JAVA有着一个非常突出的动态相关机制——Reflection(反射),用在Java身上指的是可以于运行时加载、探知、使用编译期间完全知的classes。换句话说,Java程序可以加载一个运行时才得知名称的class获悉其完整构造(但不包括methods定义),并生成其对象例(newInstance)或对其fields设值,或唤起(invoke)其methods方法。

什么叫反射机制?

反射机制是在运行状态中:

  • 对于任意一个类,都能够知道这个类的所有属性和方法。
  • 对于任意一个对象,都能够调用它的任意一个方法和属性。

反射的应用

我们可能听过,Java编写的程序,一次编译,到处运行。这也是Java程序为什么是无关平台的所在,原因在于,java的源代码会被编译成.class文件字节码,只要装有Java虚拟机JVM的地方(Java提供了各种不同平台上的虚拟机制。).class文件才可以在运行加载。

  • 第一步:由Java编译器进行源代码编译,得到相应类的字节码.class文件。
  • 第二步:生成class文件之后,通过ClassLoader类加载器加载进内存,Java字节码由JVM执行解释给目标计算机。
  • 第三步,目标计算机将结果呈现给我们计算机用户;因此,Java并不是编译机制,而是解释机制.class文件才可以在不同平台上运行加载。


Java的反射机制,操作的就是这个.class文件,首先加载相应类的字节码(运行编译器idea的时候,.class文件的字节码会加载到内存中),随后解剖(反射 reflect)出字节码中的构造函数、方法以及变量(字段),或者说是取出,我们先来定义一个类Person,里面定义一些构造函数,方法,以及变量:

package com.ztb.entity;
public class Person {private int age;private String name;/*** 有参构造器* @param name* @param age*/public Person( String name,int age) {this.age = age;this.name = name;}/*** 无参构造器*/public Person() {}//公有 有参方法public void public_show(String str,int i){System.out.println("public show "+str+"..."+i);}//公有 无参方法public void public_prin(){System.out.println("公有无参代码块。。。。");}//私有 有参方法private void private_show(String str,int i){System.out.println("私有有参代码块:private show "+str+"..."+i);}//私有 无参方法private void private_prin(){System.out.println("私有无参方法代码块:private prin");}
}

新建测试类TestClass

  //获取字节码文件中 方法 再取出其公有方法String classname = "com.ztb.entity.Person";//必须是全路径类名//寻找名称的类文件,加载进内存 产生class对象Class cl = Class.forName(classname);//获取一个Person对象System.out.println("获取一个Person对象:");Object obj=cl.newInstance();System.out.println();//1.获取 公有 无参方法  public void public_prin()Method Person_public_prin=cl.getMethod("public_prin",null);System.out.println("获取执行 public void public_prin ()方法:");Person_public_prin.invoke(obj,null);//obj 是这个类的实例System.out.println();//2.获取 公有 有参方法 public void public_show(java.lang.String,int)Method Person_public_show=cl.getMethod("public_show",String.class,int.class);System.out.println("获取执行 public void public_show(java.lang.String,int) :");Person_public_show.invoke(obj,"神奇的公有有参构造方法下的我",12);System.out.println();//3.获取 私有 无参方法  private void private_show()Method Person_private_prin=cl.getDeclaredMethod("private_prin",null);Person_private_prin.setAccessible(true);System.out.println("获取执行  private void private_show():");Person_private_prin.invoke(obj,null);System.out.println();//4.获取私有有参方法  private_prin(java.lang.String,int)Method Person_private_show=cl.getDeclaredMethod("private_show",String.class,int.class);Person_private_show.setAccessible(true);System.out.println("获取执行 private void demo2.Person.private_show(java.lang.String,int) :");Person_private_show.invoke(obj,"神奇的私有有参构造方法下的我 :",23);System.out.println();/*** 获取所有已经声明的公有的方法或者私有方法*/Method[] methods=cl.getDeclaredMethods();for (Method method: methods){System.out.println("方法名:"+method.getName()+"返回值类型:"+method.getGenericReturnType().getTypeName());}}

运行结果如图示:

为什么new一个对象那么简单,非要用反射技术中的newInstance?
为什么,我可以直接对象a1. 变量访问变量,却非要用反射那么费劲的获得name字段呢?
为什么,我几行代码就能搞定的事情,非要用反射呢?

假设我们定义了很多类,有Animal、Person、Car… ,如果我想要一个Animal实例,那我就new Animal(),如果另一个人想要一个Person实例,那么他需要new Person(),当然,另一个说,我只要一个Car实例,于是它要new Car()…这样一来就导致,每个用户new的对象需求不相同,因此他们只能修改源代码,并重新编译才能生效。这种将new的对象写死在代码里的方法非常不灵活,因此,为了避免这种情况的方法,Java提供了反射机制,典型的应用如下:

我们知道Spring的IOC,即“控制反转”(通过第三方配置文件实现对 对象的控制)。简单说是将我们设计好的对象交给容器控制,而不是直接交给程序内部进行对象的控制。

比如,在Spring中,我们经常看到:

针对上述的配置,我们Spring是怎么帮助我们实例化对象,并放到容器中去了呢? 没错,就是通过反射!!!!

我们看下,下面的伪代码实现过程:

java
//解析<bean .../>元素的id属性得到该字符串值为"sqlSessionFactory" String idStr = "sqlSessionFactory";  //解析<bean .../>元素的class属性得到该字符串值为"org.mybatis.spring.SqlSessionFactoryBean"  String classStr = "org.mybatis.spring.SqlSessionFactoryBean";  //利用反射知识,通过classStr获取Class类对象  Class cls = Class.forName(classStr);  //实例化对象  Object obj = cls.newInstance();  //container表示Spring容器  container.put(idStr, obj);  //当一个类里面需要用另一类的对象时,我们继续下面的操作//解析<property .../>元素的name属性得到该字符串值为“dataSource”  String nameStr = "dataSource";  //解析<property .../>元素的ref属性得到该字符串值为“dataSource”  String refStr = "dataSource";  //生成将要调用setter方法名  String setterName = "set" + nameStr.substring(0, 1).toUpperCase()  + nameStr.substring(1);  //获取spring容器中名为refStr的Bean,该Bean将会作为传入参数  Object paramBean = container.get(refStr);  //获取setter方法的Method类,此处的cls是刚才反射代码得到的Class对象  Method setter = cls.getMethod(setterName, paramBean.getClass());  //调用invoke()方法,此处的obj是刚才反射代码得到的Object对象  setter.invoke(obj, paramBean);

我们经常提到的Java web框架中,里面就用到了反射机制,只要在代码或配置文件中看到类的完全限定名(包名+类名),其底层原理基本上使用的就是Java的反射机制。

获得反射入口的三种方式(获得类)

1).Class.forName(全类名)(推荐使用)

Class<?> classStu = Class.forName("reflect.Student");System.out.println(classStu);

2).类名.class

Class<?> classStu2 = Student.class;System.out.println(classStu2);

3).对象.getClass()

Student stu = new Student();Class<?> classStu3 = stu.getClass();System.out.println(classStu3);
发布评论

评论列表 (0)

  1. 暂无评论