反射(Reflection)
反射的核心是JVM在运行时才动态加载类或调用方法/访问属性,它不需要事先(写代码的时候或编译期)知道运行对象是谁。 重点:是运行时而不是编译时
eg: 举一个例子,在运用Struts 2框架的开发中我们一般会在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>
配置文件与Action建立了一种映射关系,当View层发出请求时,请求会被StrutsPrepareAndExecuteFilter拦截,然后StrutsPrepareAndExecuteFilter会去动态地创建Action实例。
——比如我们请求login.action,那么StrutsPrepareAndExecuteFilter就会去解析struts.xml文件,检索action中name为login的Action,并根据class属性创建SimpleLoginAction实例,并用invoke方法来调用execute方法,这个过程离不开反射。
反射虽小但作用非常大,它是各种容器实现的核心,当深入框架会了解更多一点
反射的基本应用
1.获取class对象
方法有三种
(1)使用Class类的forName静态方法:
但是要抛出异常
public static Class<?> forName(String className)
在JDBC开发中常用此方法加载数据库驱动:
java
Class.forName(driver);
(2)直接获取某一个对象的class,比如:
Class<?> klass = int.class;
Class<?> classInt = Integer.TYPE;
(3)调用某个对象的getClass()方法,比如:
StringBuilder str = new StringBuilder("123");
Class<?> klass = str.getClass();
2.判断是否为某个类的实例
一般地,我们用instanceof关键字来判断是否为某个类的实例。同时我们也可以借助反射中Class对象的isInstance()方法来判断是否为某个类的实例,它是一个Native方法: public native boolean isInstance(Object obj);
3.创建实例
通过反射来生成对象主要有两种方式。
(1)使用Class对象的newInstance()方法来创建Class对象对应类的实例。
Class<?> c = String.class;
Object str = c.newInstance();
(2)先通过Class对象获取指定的Constructor对象,再调用Constructor对象的newInstance()方法来创建实例。这种方法可以用指定的构造器构造类的实例。
//获取String所对应的Class对象
Class<?> c = String.class;
//获取String类带一个String参数的构造器
Constructor constructor = c.getConstructor(String.class);
//根据构造器创建实例
Object obj = constructor.newInstance("23333");
System.out.println(obj);
4.获取方法
获取某个Class对象的方法集合,主要有以下几个方法:
getDeclaredMethods()方法返回类或接口声明的所有方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法。
public Method[] getDeclaredMethods() throws SecurityException
getMethods()方法返回某个类的所有公用(public)方法,包括其继承类的公用方法。
public Method[] getMethods() throws SecurityException
getMethod方法返回一个特定的方法,其中第一个参数为方法名称,后面的参数为方法的参数对应Class的对象
public Method getMethod(String name, Class<?>... parameterTypes)
5.获取成员变量
主要是这几个方法,在此不再赘述:
getFiled: 访问公有的成员变量
getDeclaredField:所有已声明的成员变量。但不能得到其父类的成员变量
getFileds和getDeclaredFields用法同上(参照Method)
6.调用方法
当我们从类中获取了一个方法后,我们就可以用invoke()方法来调用这个方法。invoke方法的原型为:
public Object invoke(Object obj, Object... args)
throws IllegalAccessException, IllegalArgumentException,
InvocationTargetException
下面是一个实例:
public class test1 {
public static void main(String[] args) throws IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
Class<?> klass = methodClass.class;
//创建methodClass的实例
Object obj = klass.newInstance();
//获取methodClass类的add方法
Method method = klass.getMethod("add",int.class,int.class);
//调用method对应的方法 => add(1,4)
Object result = method.invoke(obj,1,4);
System.out.println(result);
}
}
class methodClass {
public final int fuck = 3;
public int add(int a,int b) {
return a+b;
}
public int sub(int a,int b) {
return a+b;
}
}