1、反射,可以理解为在运行是获取对象类型信息的操作,反射是有smith在1982年首次提出的。
2、反射就是加载类,并解剖出类的各个组成部分。
3、编程时什么情况下才需要加载类,并解剖出类的各个组成部分呢?
做框架时,经常需要写配置文件,内部机制要通过反射机制来获取。
4、Java反射机制提供的功能:
1) 在运行时判断任意一个对象所属的类。
2) 在运行时构造任意一个类的对象。
3) 在运行时判断任意一个类所具有的成员变量和方法。
4) 在运行时调用任意一个对象的方法。通过反射甚至可以调用到private的方法。
5) 生成动态代理。
5、Java反射所需要的类主要有:java.lang.Class类和java.lang.reflect包中的Field、Constructor、Method、Array类。
1)Class类:Class类的实例表示正在运行的Java应用程序中的类和接口。
2)Field类:提供有关类或接口的属性信息,以及它的动态访问权限。反射的字段可能是一个类属性或实例属性,可以理解为一个封装反射类的属性的类。
3)Constructor类:提供关于类的单个构造方法的信息以及对它的访问权限。Field类不同,4)Field类封装了反射类的属性,而Constructor类则封装了反射类的构造方法。
5)Method类:提供关于类或接口中单独某个方法的信息。反映的方法可能是类方法或实例方法(包括抽象方法)。是用来封装反射类方法的一个类。
6)Array类:提供了动态创建数组和访问数组的静态方法。类中的所有方法都是静态方法。
注意:Class类是Java反射的起源,针对任何一个你想探勘的类,只有先为它产生一个Class类的对象,接下来才能通过Class对象获取其他想要的信息。
6、Class类
1)Java程序运行时,系统会对所有对象进行运行时类型标识,用来保存类型信息的类就是Class类。Class类封装一个对象或接口运行时的状态。
2)为什么说要想获取类或接口的相应信息,需要先获取这个Class对象?
JVM为每种类型管理着一个独一无二的Class对象----每个类(型)都有一个Class对象。
Java程序运行过程中,当需要创建某个类的实例时,JVM首先检查所要加载的类对应的Class对象是否存在。如果不存在,JVM就会根据类名查找对应的字节码文件并加载,接着创建对应的Class对象,最后才创建出这个类的实例。
Java基本数据类型(boolean、byte、char、short、int、long、float和 double)和关键字void也都对应一个 Class对象;每个数组属性也被映射为 Class对象,所有具有相同类型和维数的数组都共享该 Class对象。
7、加载类
获取class对象的三种方法:
1) 调用Object类的getClass()方法来得到Class对象,这也是常见的产生Class对象的方法。
2) 使用Class类的forName()静态方法获得与字符串对应的Class对象。(参数字符创必须是类或接口的完全限定名)
3) 使用“类型名.Class”来获取该类型对应的Class对象。
代码说明:
packagecom.hbsi.reflect;
publicclass Demo1 {
publicstaticvoid main(String [] args)throws ClassNotFoundException
{
//获取class的三种方法
//1、forName()方法
Class clazz= Class.forName("com.hbsi.reflect.Person");
System.out.println(clazz.getName());//getName()获取名字
//2、类名.class
Class clazz1=Person.class;
System.out.println(clazz1.getName());
//3.对象.getClass()
Person p=new Person();
Class clazz2=p.getClass();
System.out.println(clazz2.getName());
}
}
8、解剖类
Class对象提供了如下常用方法:
1)Public ConstructorgetConstructor(Class<?>... parameterTypes):返回一个Constructor
对象,它反映此Class
对象所表示的类的指定公共构造方法。(获取出来的构造方法都是public构造方法)
2)public ConstructorgetDeclaredConstructor(Class...parameterTypes):返回一个Constructor
对象,该对象反映此Class
对象所表示的类或接口的指定构造方法。(获取出来的构造方法可以是静态的构造方法)
3)Constructor<?>[] getDeclaredConstructors()获取此 Class对象的所有构造方法。
4)Constructor<?>[] getConstructors():获取此 Class对象所表示的实体的所有public构造方法。
5)public T newInstance():创建此Class对象所表示类的一个新实例。使用的是不带参数的构造方法。(class.newInstance方法内部是反射类无参的构造函数创建的对象,所以利用此种方式创建类对象时,类必须有一个无参的构造函数。)
6)String getName():获取此Class对象所表示实体的完全限定名。
代码说明:(initargs用于指定构造函数接收的参数,newInstance方法,用于创建类的对象)
packagecom.hbsi.reflect;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import org.junit.Test;
publicclass Demo2 {
@Test
//反射出无参构造方法,并创建一个person对象
publicvoid test1()throws ClassNotFoundException,SecurityException, NoSuchMethodException, IllegalArgumentException,InstantiationException, IllegalAccessException, InvocationTargetException
{
//加载类
Class clazz=Class.forName("com.hbsi.reflect.Person");
//反射出构造方法
Constructor c=clazz.getConstructor(null);
//创建对象所表示的类的一个新实例,调用无参构造方法
Person p=(Person)c.newInstance(null);
//输出Person里面的相关信息
System.out.println(p.getName());
}
@Test
//反射一个参数的构造方法
publicvoid test2()throws ClassNotFoundException, SecurityException,NoSuchMethodException, IllegalArgumentException, InstantiationException,IllegalAccessException, InvocationTargetException
{
//加载类
Class clazz=Class.forName("com.hbsi.reflect.Person");
//反射出构造方法,传入参数类型的对象
Constructor c=clazz.getConstructor(String.class);
//创建对象所表示的类的一个新实例,调用构造方法
Personp=(Person)c.newInstance("lisi");
//输出Person里面的相关信息
System.out.println(p.getName());
}
@Test
//反射两个参数的构造方法
publicvoid test3()throws ClassNotFoundException, SecurityException,NoSuchMethodException, IllegalArgumentException, InstantiationException,IllegalAccessException, InvocationTargetException
{
//加载类
Class clazz=Class.forName("com.hbsi.reflect.Person");
//反射出构造方法,传入参数类型的对象
Constructor c=clazz.getConstructor(String.class,int.class);
//创建对象所表示的类的一个新实例,调用构造方法
Person p=(Person)c.newInstance("lisi",23);
//输出Person里面的相关信息
System.out.println(p.getName());
}
@Test
//反射出私有构造方法
publicvoid test4()throws ClassNotFoundException, SecurityException,NoSuchMethodException, IllegalArgumentException, InstantiationException,IllegalAccessException, InvocationTargetException
{
//加载类
Class clazz=Class.forName("com.hbsi.reflect.Person");
//反射出构造方法,传入参数类型的对象
Constructor c=clazz.getDeclaredConstructor(int.class);
//乳沟是privat,必须设置访问权限,设为允许访问
c.setAccessible(true);
//创建对象所表示的类的一个新实例,调用构造方法
Person p=(Person)c.newInstance(24);
//输出Person里面的相关信息
System.out.println(p.getName());
}
@Test
//利用newInstance()调用无参构造方法
publicvoid test5()throws ClassNotFoundException,InstantiationException, IllegalAccessException
{
//加载类
Class clazz=Class.forName("com.hbsi.reflect.Person");
//使用newInstance()方法
Person p=(Person)clazz.newInstance();
//输出Person里面的相关信息
System.out.println(p.getName());
}
}
9、Method执行方法
1)Public MethodgetMethod(String name,Class<?>... parameterTypes) :返回一个包含某些Method
对象的数组,这些对象反映此Class
对象所表示的类或接口(包括那些由该类或接口声明的以及从超类和超接口继承的那些的类或接口)的公共member方法。
2)Method[] getMethods():获取此Class对象所表示实体的所有public方法
3)public MethodgetDeclaredMethod(String name,Class...parameterTypes): 返回一个Method
对象,该对象反映此Class
对象所表示的类或接口的指定已声明方法。
4)Method[] getDeclaredMethods():获取此Class对象所表示实体的所有方法
Method对象提供了如下方法,用于执行它所代表的方法:
publicObject invoke(Object obj,Object... args)
代码说明:
packagecom.hbsi.reflect;
importjava.lang.reflect.InvocationTargetException;
importjava.lang.reflect.Method;
importorg.junit.Test;
publicclass Demo3 {
//普通方法:不带参数
@Test
publicvoid test1()throws ClassNotFoundException, SecurityException,NoSuchMethodException, IllegalArgumentException, IllegalAccessException,InvocationTargetException{
//定义对象
Person p=new Person();
//加载类
Class clazz=Class.forName("com.hbsi.reflect.Person");
//获取方法 getMethod(方法名,方法是否有参数写参数类型)
Method m=clazz.getMethod("run",null);
//调用相应的run方法 invoke(调用对象,参数值)
m.invoke(p,null);
}
//普通方法:带一个参数
@Test
publicvoid test2()throws ClassNotFoundException, SecurityException,NoSuchMethodException, IllegalArgumentException, IllegalAccessException,InvocationTargetException{
//定义对象
Person p=new Person();
//加载类
Class clazz=Class.forName("com.hbsi.reflect.Person");
//获取方法
Method m=clazz.getMethod("run",String.class);
//调用相应的run方法
m.invoke(p,"zhangsan");
}
//有返回参数的普通方法
@Test
publicvoid test3()throws ClassNotFoundException, SecurityException,NoSuchMethodException, IllegalArgumentException, IllegalAccessException,InvocationTargetException{
//定义对象
Person p=new Person();
//加载类
Class clazz=Class.forName("com.hbsi.reflect.Person");
//获取方法
Method m=clazz.getMethod("sum",int.class,int.class);
//调用相应的sum方法,返回object类型对象,强转,有拆箱动作
int value=(Integer)m.invoke(p,12,2);
System.out.println(value);
}
//私有普通方法
@Test
publicvoid test4()throws ClassNotFoundException, SecurityException,NoSuchMethodException, IllegalArgumentException, IllegalAccessException,InvocationTargetException{
Person p=new Person();
Class clazz=Class.forName("com.hbsi.reflect.Person");
//获取方法
Method m=clazz.getDeclaredMethod("sum1",null);
//设置访问权限
m.setAccessible(true);
m.invoke(p,null);
}
//静态方法(可以不传实例对象)
@Test
publicvoid test5()throws ClassNotFoundException, SecurityException,NoSuchMethodException, IllegalArgumentException, IllegalAccessException,InvocationTargetException{
Class clazz=Class.forName("com.hbsi.reflect.Person");
Method m=clazz.getMethod("sum2",null);
//静态不需要传对象
m.invoke(null,null);
}
}
10、利用Field访问属性
1)Field[] getFields():获取此Class对象所表示实体的所有public字段
2)Field[] getDeclaredFields():获取此Class对象所表示实体的所有字段。
3)Public FieldgetField(String name) :返回一个Field
对象,它反映此Class
对象所表示的类或接口的指定公共成员字段
4)public FieldgetDeclaredField(String name) :返回一个 Field对象,该对象反映此 Class对象所表示的类或接口的指定已声明字段。
Field对象提供了如下方法,用于设置、获取对象属性的值:
public void set(Object obj,Object value)
public Object get(Object obj)
代码说明:
packagecom.hbsi.reflect;
importjava.lang.reflect.Field;
importorg.junit.Test;
publicclass Demo4 {
@Test
publicvoid test1()throws ClassNotFoundException, SecurityException,NoSuchFieldException, IllegalArgumentException, IllegalAccessException{
//定义对象
Person p=new Person();
//加载类
Class clazz=Class.forName("com.hbsi.reflect.Person");
//获取公有字段 获取私有字段:getDeclaredFields()
Field f=clazz.getField("sex");
//获取字段值,获取值为Object类型,要强转
Stringsex=(String)f.get(p);
//设置值 set(设值对象,设置的值)
f.set(p, "nv");
//获取字段类型,返回类型为class
//Class type=f.getType();
//输出设完值之后要重新获取 p.sex
System.out.println(p.sex);
//System.out.println(type);
}
}
其他方法:
1)Constructor<T> getConstructor(Class<?>...parameterTypes):获取此Class 对象特定的构造方法。
2)public class getSuperClass():获取此Classs对象所表示实体的父类Class
3)public class [] getInterfaces():获取此Class对象所表示实体实现的所有接口Class列表
4)public Annotation[] getAnnotations():获取此元素上存在的所有注释。
5)public Annotation[] getDeclaredAnnotations();获取此元素上直接存在的所有注释