1.什么是反射
是指在运行状态中,对任意一个类,都能够知道这个类的所有属性及方法;对于任意一个对象,都能调用他的任意一个属性和方法。
下面是获取class文件对象的三种方式
package cn.itcast.demo1;
public class ReflectDemo {
public static void main(String[] args) throws ClassNotFoundException {
//1.对象获取
Person p = new Person();
//调用Person父类的方法getClass,此方法也是属于Object基础类中的方法
Class c = p.getClass();
System.out.println(c);
//2.类名获取
//class是每个类型(基本或者引用)都会赋予的静态属性
Class c1 = Person.class;
System.out.println(c);
//3.Class类的静态获取
//方法forName(String className),注意类名必须是完整的路径,包括包名
Class c2 = Class.forName("cn.itcast.demo1.Person");
System.out.println(c2);
}
}
Class类有很多方法,例如
(1)可以获取空参构造方法
package cn.itcast.demo1;
import java.lang.reflect.Constructor;
public class ReflectDemo1 {
public static void main(String[] args) throws Exception {
Class c = Class.forName("cn.itcast.demo1.Person");
//使用文件对象获得所有公共权限的构造方法
/* Constructor[] cons = c.getConstructors();
for(Constructor con : cons ){
System.out.println(con);
}*/
//获取空参构造器
Constructor con = c.getConstructor();
//运行空参构造方法
Object obj = con.newInstance();
System.out.println(obj);
}
}
(2)反射获取有参的构造法并赋值
package cn.itcast.demo1;
import java.lang.reflect.Constructor;
public class ReflectDemo2 {
public static void main(String[] args) throws Exception {
Class c = Class.forName("cn.itcast.demo1.Person");
//获取带有参数的构造方法并运行
//注意这里参数列表的类型要加.class
Constructor con =c.getConstructor(String.class,int.class);
// System.out.println(con);
//方法newInstance,创建此 Class 对象所表示的类的一个新实例。
Object obj = con.newInstance("张三",18);
System.out.println(obj);
}
}
(3)反射获得成员方法并运行
package cn.itcast.demo1;
//反射获得成员方法并运行
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class ReflectDemo5 {
public static void main(String[] args) throws Exception {
Class c = Class.forName("cn.itcast.demo1.Person");
Object obj = c.newInstance();
/*Method[] me = c.getMethods();
for (Method method : me) {
System.out.println(method);
}*/
//获取指定方法
Method m = c.getMethod("eat");
//调用指定的方法
m.invoke(obj);
}
}
这里内容比较多…感兴趣可以看看API的Class类,对后期维护好像很有帮助。
2.泛型擦除案例
定义一个泛型是String类型的集合,本来只能存储String类型,通过泛型擦除,可以实现向集合中添加其他类型元素。
package cn.itcast.demo2;
import java.lang.reflect.Method;
import java.util.ArrayList;
/*
* 定义集合类,泛型String
* 向集合添加Integer类型
*/
public class ReflectTest {
public static void main(String[] args) throws Exception {
ArrayList<String> arr = new ArrayList<String>();
arr.add("a");
//反射方式调用add方法
//获得arr的class对象
Class c = arr.getClass();
//通过class对象获取arr的add方法
Method m = c.getMethod("add", Object.class);
System.out.println(m);
//向集合中添加Integer类型的元素,这里泛型已经被擦除
m.invoke(arr, 5);
System.out.println(arr);
}
}
3.反射通过配置文件运行的步骤
(1)准备配置文件,键值对的方式
(2)IO流读取配置文件(用完记得随手关!!!)
(3)将文件中的键值对存储到集合(properties)中,集合中保存配置文件的键值对,即类名和方法
(4)反射获得指定类的class文件对象
(5)通过文件对象,获取指定的方法
配置文件:键值对的形式存储着类名及方法
className=cn.itcast.demo3.Person
methodName=eat
Person类
package cn.itcast.demo3;
public class Person {
public void eat(){
System.out.println("人吃饭");
}
}
测试类
package cn.itcast.demo3;
import java.io.FileReader;
import java.lang.reflect.Method;
import java.util.Properties;
/*
* 调用三个对象的功能
* 类不清楚,方法也不清楚
*
*/
public class Test {
public static void main(String[] args) throws Exception {
//IO流读取配置文件
FileReader fr = new FileReader("config.properties");
//创建集合对象,这是存储键值对的集合
Properties pro = new Properties();
//从输入流中读取属性列表(键和元素对)。
pro.load(fr);
//关闭流释放资源
fr.close();
//用指定的键获取与键对应的值
String className = pro.getProperty("className");
System.out.println(className);
String methodName = pro.getProperty("methodName");
System.out.println(methodName);
//反射获取指定类的class文件对象
Class c = Class.forName(className);
//创建对象的实例
Object obj = c.newInstance();
//获取class对象的方法
Method m = c.getMethod(methodName);
//调用方法,需要对象的支持
m.invoke(obj);
}
}
通过这种方式,我们只需要修改键值对即可使用不同类的不同方法了。