1、反射:反射就是把java类中的各个成分映射成相应的java类。
java反射机制是在运行状态,对任意一个类,都能够知道这个类的所有属性和方法,对于任意一个对象,都能够调用它的任意一个方法和属性,这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。
简单理解:反射技术可以对类进行解剖。
2、反射的做用:实现框架的功能。
在开发中我们往往是基于某个框架的基础上进行开发,这样可以提高开发的效率,反射技术能让我们在框架的基础上方便我们添加新的功能。
3、什么是框架?
一个框架是一个可复用的设计构件,它规定了应用的体系结构,阐明了整个设计、协作构件之间的依赖关系、责任分配和控制流程,表现为一组抽象类以及其实例之间协作的方法,它为构件复用提供了上下文关系。因此构件库的大规模重用也需要框架。
4、获取Class的三种方式:
方式一:通过对象的getclass()方法获取。这种方式需要创建对象。
例如:new Person().getClass()
方式二:通过任意类型调用获取。这种方式不需要创建对象。
例如:class,System.class.
方式三:通过class类的forName(类名)方法获取。
例如:Class.forName("java.util.Date");
5、class类:
java程序中的各个java类属于同一事物,描述这类事物的类就是Class。也就是用于描述字节码文件对象的类,这个类的实例表示正在运行的java应用程序中的类和接口,这个类的实例不需要用new来创建。
6、创建对象的过程。
new Person()对象的过程:
1、查找并加载Person.class文件进内存,并将该文件封装成Class对象。
2、再依据Class对象创建该类的Person实例。
3、调用构造函数对对象进行初始化。
直接创建对象代码示例:
Person p = new Person();
用反射对象创建Person对象的过程:
1、查找并加载指定名字的字节码文件进内存,并封装成Class对象。
2、通过Class对象newInstance方法创建对应字节码文件的实例。
3、使用构造函数对对象进行初始化。
反射创建对象代码示例:
String className = "cn.itcast.bean.Person";
Class clazz = Class.forName(className);
Object obj = clazz.newInstance();
7、Class类中的方法:
forName(String className):获取字节码文件对象。
创建对象:
T newInstance():创建此Class对象表示的类的一个新实例。
获取Field对象:
Field getField(String name):只能获取公有,和父类公有的。
Field getDeclaredField(String name):只能获取本类中的,包括似有的。
Field[] getFields():能获取Class中的所有字段对象,包括继承,不包括似有。
Field[] getDeclaredFields():能获取所有字段,包括似有,不包括继承。
获取Method对象:
Method getMethod(String name,Class<?>... parameterTypes):(参数时方法名,参数类型)只获取公共的,包括父类公共的。
Method DeclaredMethod(String name,Class<?>... parameterTypes):获取所有,包括似有。不包括父类。
method[] getMethods():获取所有公有的Method方法对象,包括父类。
method[] getDeclaredMethods():获取所有包括似有的Method对象,不包括父类。
获取构造器:
getConstructor(Class<?>... parameterTypes):返回指定Class,指定参数的构造器。
getConstructor():返回所有的公共的构造器。
getDeclaredConstructor(Class<?>... parameterTypes):返回指定Class,指定参数的构造器,包括似有。
Field类中的方法:
给字段赋值:
void set(Object obj,Object value):明确了是哪个Field对象,设置指定值。
获取字段值:
Object get(Object obj):返回指定对象上此 Field 表示的字段的值。
AccessibleObject类:
void setAccessible(boolean):对该对象进行权限设置。(可以对似有属性的进行暴力访问)
Method类:
invoke(Object obj, Object... args): 调用方法,参数明确的是具体对象和传入的实际参数。
相当于调用方法,并传入相应的实际参数。
数组与Object的关系以及反射类型:数组的父类都是Object。
具有相同维数和元素类型的数组属于同一个类型,即具有相同的Class实例对象。也就是说他们的字节码都是同一份。
int[] a1 = new int[3];
int[] a2 = new int[4];
int[] a3 = new int[2][3];
System.out.println(a1.getClass() == a2.getClass());//结果为true.
System.out.println(a1.getClass() == a3.getClass());//结果为false.
System.out.println(al.getClass().getSuperclass().getName());//获取父类名,是Object.
System.out.println(a3.getClass().getSuperclass().getName());//获取父类名,是Object
数组反射的应用:
Array工具类用于完成对数组的反射操作,该类供了动态创建和访问 Java 数组的方法。
我们可以用Array来对数组的内容进行设置和获取。
public static void printObject(Object obj){
Class clazz = obj.getClass();
//是数组就遍历,不是就打印对象。
if(clazz.isArray()){
int len = Array.getLength(obj);
for(int i=0;i<len;i++){
System.out.println(Array.get(obj,i));
}
}else{
System.out.println(obj);
}
}
List asList(T... a);jdk1.5后的参数。
List aslist(Object o);jdk1.4的方法。
代码示例:
获构造器,并根据相应的构造器创建对象。
publicclass GetConstructorDemo2 {
publicstaticvoid main(String[] args)throws Exception {
//获取字节码文件并加载进内存。
String className = "cn.itcast.bean.Person";
Class clazz = Class.forName(className);
getConstructor_1(clazz);
getConstructor_2(clazz);
}
//根据空参数的构造方法创建对象。
publicstaticvoid getConstructor_1(Class clazz)throws Exception{
Object obj = clazz.newInstance();
System.out.println(obj);
}
//根据带参数name和age的构造器创建对象。
publicstaticvoidgetConstructor_2(Class clazz) throws Exception{
//获取构造器。
Constructorconstructor =clazz.getConstructor(String.class,int.class);//明确参数类型。
Person p = (Person)constructor.newInstance("list",23);//创建对象并并传实参。
//因为不知道是根据哪个对象的构造方法创建的对象,所以创建的对象的类型是Object的,需要强转。
p.setAge(55);//自己写的Person中的方法设置值。
p.getAge();//获取值。
System.out.println(p);
}
}
获取字段对象,获取age字段值,并设置值和获取值。
publicclass GetFieldDemo3 {
publicstaticvoid main(String[] args)throws Exception {
String className = "cn.itcast.bean.Person";
Class clazz = Class.forName(className);
getField(clazz);
// getFields(clazz);
}
publicstaticvoid getField(Class clazz)throws Exception{
Object obj = clazz.newInstance();
// Field ageField = clazz.getField("age");
Field ageField = clazz.getDeclaredField("age");//获取似有age字段对象。
//暴力访问。
ageField.setAccessible(true);
ageField.set(obj, 23);
Object o = ageField.get(obj);
System.out.println(o);
}
//获取所有Field对象。
publicstaticvoid getFields(Class clazz)throws Exception{
Object obj = clazz.newInstance();
Field[] fiels = clazz.getFields();
for(Field f : fiels){
System.out.println(f);
}
}
}
获取Method对象,并掉用各个方法。(空参数,带参数,静态)
publicclass GetMethodDemo4 {
publicstaticvoid main(String[] args)throws Exception {
String className = "cn.itcast.bean.Person";
Class clazz = Class.forName(className);
getMethod_1(clazz);
getMethod_2(clazz);
getMethod_3(clazz);
}
//获取空参数的Method对象,并调用空参数的方法。
publicstaticvoid getMethod_1(Class clazz)throws Exception{
Object obj = clazz.newInstance();
Method method = clazz.getMethod("method",null);//获取method空参数的方法。
method.invoke(obj, null);
}
//获取带参数的Method对象,调用方法,并传实参。
publicstaticvoid getMethod_2(Class clazz)throws Exception{
Constructor constructor =clazz.getConstructor(String.class,int.class);
Object obj = clazz.newInstance();
Method method = clazz.getMethod("method", String.class,int.class);//明确方法名,参数。
method.invoke(obj, "小强",32);
}
//获取静态空参数Method对象,并调用静态方法。
publicstaticvoid getMethod_3(Class clazz)throws Exception{
//调用静态方法不用创建对象。
Method method = clazz.getMethod("staticMethod",null);
method.invoke(null,null);
}
}
数组的反射
publicclass ArrayReflectDemo {
publicstaticvoid main(String[] args) {
int[] a1 =newint[]{5,6,7};
int[]a2 =newint[4];
int[][] a3 =newint[2][3];
String[] a4 = new String[]{"a","b","c"};
//父类引用接收子类对象。
Object obj1 = a1;//可以接收。
Object obj2 = a4;
// Object[] obj3 = a1;//不行。编译会出错。
Object[] obj4 = a3;
Object[] obj5 = a4;
System.out.println(Arrays.asList(a1));//asList(T... a)使用的是jdk1.5版本来接收参数。将参数当成一个对象。
System.out.println(Arrays.asList(a4));//asList(Object[] o)使用的是jdk1.4版本的方法。将参数当成一个数组,以可以打印出所有元素。
}
代码演示:
读取配置文件:利用反射来创建容器对象。将容器在api中的目录,存放到配置文件中,然后读取配置文件。
publicclass ReflectTest {
publicstaticvoid main(String[] args)throws Exception {
// Collection coll = new ArrayList();
//第一种读取配置文件方式:加载config.Properties文件。用流来读取。(这种方式即可读,也可以写到硬盘上保存)
// InputStream ips = new FileInputStream("config.properties");
//第二种读取方式:用类加载器来加载配置文件。
// InputStream ips = ReflectTest.class.getClassLoader().getResourceAsStream("cn/itcast/p4/test/config.properties");//使用的是类加载器中的方法。相当于在在classPath指定的跟目录下逐个查找config文件。
InputStream ips = ReflectTest.class.getResourceAsStream("config.properties");//相对于ReflecTest文件所在包下的目录config.properties。
//config.properties相当于classPath的跟目录。
//创建一个properties容器。
Properties props = new Properties();
//将流中的数据读取到容器中。
props.load(ips);
ips.close();
String className = props.getProperty("className1");
Collection coll = (Collection)Class.forName(className).newInstance();
// Collection<ReflectPoint>coll = new HashSet<ReflectPoint>();
ReflectPoint pt1 = new ReflectPoint(3,3);
ReflectPoint pt2 = new ReflectPoint(4,4);
ReflectPoint pt3 = new ReflectPoint(5,5);
ReflectPoint pt4 = new ReflectPoint(3,3);
coll.add(pt1);
coll.add(pt2);
coll.add(pt3);
coll.add(pt4);
System.out.println(coll.size());
}
}