第十部分:反射
1. 反射机制的概念
2. 反射机制的作用
3. 反射机制的理解
4. Class类的使用
5. Class文件获取的三种方式
6. 获取Constructor对象
7. 获取私有Constructor对象
8. 获取Method对象
9. 获取私有Method对象
10. Constructor的使用
11. Method类的使用
12. Field类的使用
13. Modifier类的介绍
14. 反射使用练习
15. 反射机制在工厂设计模式中的应用
首先要知道两个概念:
编译期:在编译期,编译器把Java代码 (.java) 编译成JVM可识别的字节码文件 (.class)
运行期:指的是将可执行文件交给操作系统去执行
1.什么是反射机制
Java反射机制是在运行状态中,JVM动态加载类,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为Java语言的反射机制
简单说,反射机制指的是程序在运行时能够根据需要动态获取类的信息。在Java中,只要给定类的名字,那么就可以通过反射机制来获得类的所有信息。
反射的原理
下图是类的正常加载过程,反射原理与class对象:
Class对象的由来是将class文件读入内存,并为之创建一个Class对象。
三、反射的优缺点:
1、优点:
使用反射,我们就可以在运行时获得类的各种内容,进行反编译,对于Java这种先编译再运行的语言,能够让我们很方便的创建灵活的代码,这些代码可以在运行时装配。
2、缺点:
(1)反射会消耗一定的系统资源,因此,如果不需要动态地创建一个对象,那么就不需要用反射;
(2)反射调用方法时可以忽略权限检查,因此可能会破坏封装性而导致安全问题。
2. Java反射机制提供了什么功能?
在运行时判断任意一个类所具有的成员变量和方法
在运行时构造任意一个类的对象
在运行时调用任一对象的方法
在运行时能够判断任意一个对象所属的类
3.new和反射创建有什么区别呢?
new:静态编译,在编译期就将模块编译进来,执行该字节码文件,所有的模块都被加载;
反射:动态编译,编译期没有加载,等到模块被调用时才加载;
四、反射的用途:
1、反编译:.class-->.java
2、通过反射机制访问java对象的属性,方法,构造方法等
3、当我们在使用IDE,比如Ecplise时,当我们输入一个对象或者类,并想调用他的属性和方法是,一按点号,编译器就会自动列出他的属性或者方法,这里就是用到反射。
4、反射最重要的用途就是开发各种通用框架。比如很多框架(Spring)都是配置化的(比如通过XML文件配置Bean),为了保证框架的通用性,他们可能需要根据配置文件加载不同的类或者对象,调用不同的方法,这个时候就必须使用到反射了,运行时动态加载需要的加载的对象。
例如,在使用Strut2框架的开发过程中,我们一般会在struts.xml里去配置Action,比如
<action name="login" class="org.ScZyhSoft.test.action.SimpleLoginAction" method="execute">
<result>/shop/shop-index.jsp</result>
<result name="error">login.jsp</result>
</action>
比如我们请求login.action时,那么StrutsPrepareAndExecuteFilter就会去解析struts.xml文件,从action中查找出name为login的Action,并根据class属性创建SimpleLoginAction实例,并用Invoke方法来调用execute方法,这个过程离不开反射。配置文件与Action建立了一种映射关系,当View层发出请求时,请求会被StrutsPrepareAndExecuteFilter拦截,然后StrutsPrepareAndExecuteFilter会去动态地创建Action实例。
spring的ioc也用到反射机制,newInstance创建。更加的通用,并且降低耦合,避免了硬编码,只需提供一个字符串就可以动态的创建。
String className = readfromXMlConfig;//从xml 配置文件中获得字符串
Class c = Class.forName(className);
factory = (AInterface) c.newInstance();
加载数据库驱动,用到的也是反射。
Class.forName("com.mysql.jdbc.Driver"); // 动态加载mysql驱动
五、反射机制常用的类:
Java.lang.Class;
Java.lang.reflect.Constructor;
Java.lang.reflect.Field;
Java.lang.reflect.Method;
Java.lang.reflect.Modifier;
六、反射的基本使用:
1、获得Class:主要有三种方法:
(1)Object-->getClass
(2)任何数据类型(包括基本的数据类型)都有一个“静态”的class属性
(3)通过class类的静态方法:forName(String className)(最常用)
注意,在运行期间,一个类,只有一个Class对象产生,所以打印结果都是true;
三种方式中,常用第三种,第一种对象都有了还要反射干什么,第二种需要导入类包,依赖太强,不导包就抛编译错误。一般都使用第三种,一个字符串可以传入也可以写在配置文件中等多种方法。
/**
* 反射的基本使用,获取class对象
*/
public class ReflectionDemo {
public static void main(String[] args) {
//第一种方式获取Class对象
Student stu1 = new Student();//这一new 产生一个Student对象,一个Class对象。
Class stuClass = stu1.getClass();//获取Class对象
System.out.println(stuClass.getName());
//第二种方式获取Class对象
Class stuClass2 = Student.class;
System.out.println(stuClass == stuClass2);//判断第一种方式获取的Class对象和第二种方式获取的是否是同一个
//第三种方式获取Class对象
try {
Class stuClass3 = Class.forName("com.lzw.reflection.Student");//注意此字符串必须是真实路径,就是带包名的类路径,包名.类名
System.out.println(stuClass3 == stuClass2);//判断三种方式是否获取的是同一个Class对象
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
结果:
2、判断是否为某个类的示例:
一般的,我们使用instanceof 关键字来判断是否为某个类的实例。同时我们也可以借助反射中Class对象的isInstance()方法来判断是否为某个类的实例,他是一个native方法。
public native boolean isInstance(Object obj);