一、反射
1、概念
JAVA反射机制是在运行状态中,对于任意一个类(class文件),都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。
简而言之,动态获取类中信息就是反射。
2、应用
如果想要对指定名称的字节码文件进行加载并获取其中的内容并调用,这时就使用到了反射技术。
3、获取字节码文件对象的3种方式
想要对一个类文件进行解剖,只要获取到该类的字节码文件对象即可。
获取方式1:使用Object类中的getClass()方法
public static void getClassObject1(){
Person p=new Person();//创建对象
Class clazz=p.getClass();
Person p1=new Person();
Class clazz1=p1.getClass();
System.out.println(clazz==clazz1);
}
使用这种方式,必须明确具体的类,并且创建对象,较为麻烦
获取方式2:使用数据类型的静态属性.class
public static void getClassObject2(){
Class clazz=Person.class;//.class属性
Class clazz1=Person.class;
System.out.println(clazz==clazz1);
}
比上一种方式简单,但还是要用到类中的静态方法,不够扩展
获取方式3:Java中提供的类描述字节码文件的类Class中的静态方法forName(String name);
public static void getClassObject3() throws ClassNotFoundException{
String className="bean.Person";
Class c=Class.forName(className);
System.out.println(c);
}
此方法只要给出类的字符串名称就可以获取该类的字节码文件对象,扩展性非常好。
4、 获取字节码文件中的构造函数、字段、一般函数。
(1)、获取Class对象所表示的类的对象(构造函数Constructor )
早期:
Person p=new Person:
分析:new时,先根据New时类的名称寻找该类的字节码文件对象,并加载进内存,创建该字节码文件对象,并接着创建该字节文件对应的Person对象。
现在:利用java提供的CLass类,根据类的名称直接获取字节码文件对象,并使用Class类中的方法创建该字节码文件对象表示的类的对象。
A.构造函数无参数的情况
public static void getObject1() throws ClassNotFoundException, InstantiationException, IllegalAccessException{
//例1:Person p=new Person();
String name="bean.Person";//只需知道类名(包名.类名)
//找到该文件对应的字节码文件,并加载进内存,并产生class对象
Class clazz=Class.forName(name);
//产生字节码文件对应的类的对象
Object obj=clazz.newInstance();
}
B.构造函数有参数的情况
public static void getObject2()throws Exception{
String name="bean.Person";
//找到该文件对应的字节码文件,并加载进内存,并产生class对象
Class clazz=Class.forName(name);
//获取指定的构造函数
Constructor c=clazz.getConstructor(String.class,int.class);
//通过构造器对象的newInstance()方法进行对象的初始化
Object obj=c.newInstance("小明",29);
}
2、获取字段(Field)
public static void getFieldDemo()throws Exception{
String name="bean.Person";
Class clazz=Class.forName(name);
Field field=clazz.getDeclaredField("age");//只获取本类中的,但包括私有的
Object obj=clazz.newInstance();//类文件对象
field.setAccessible(true);//修改字段的访问权限
field.set(obj,89);//设置obj对象的字段的新值
Object o=field.get(obj);//获取Obj对象上的值
System.out.println(o);
}
(3)、获取方法(Method)
//获取公共方法
public static void getMethodDemo1() throws Exception{
Class clazz=Class.forName("bean.Person");
Method[] methods=clazz.getMethods();// 本类继承类的所有公共方法
//Method[] methods=clazz.getDeclaredMethods();//只获取本类中的所有方法
for(Method method:methods)
{
System.out.println(method);
}
}
//获取指定公共成员方法
public static void getMethodDemo2() throws Exception{
Class clazz=Class.forName("bean.Person");
Method method=clazz.getMethod("show", null);//获取无参方法
//使用构造函数进行传值
Constructor cos=clazz.getConstructor(String.class,int.class);
Object obj=cos.newInstance("xiaoming",21);
//Object obj=clazz.newInstance();
method.invoke(obj, null);//运行method对象的底层方法
}
//运行带参方法
public static void getMethodDemo3() throws Exception{
Class clazz=Class.forName("bean.Person");
Method method=clazz.getMethod("show", String.class,int.class);
Object obj=clazz.newInstance();
method.invoke(obj, "xiaoming",21);
}
5、反射应用示例
//主板
public class MainBoard {
public void run(){
System.out.println("mianboard run");
}
public void usePCI(PCI p){
if(p!=null){
p.open();
p.close();
}
}
}
//主板对外提供的接口
public interface PCI {
public void open();
public void close();
}
//声卡实现PCI 接口
public class SoundCard implements PCI {
public void open(){
System.out.println("soundcard open");
}
public void close(){
System.out.println("soundcard close");
}
}
//网卡实现PCI 接口
public class NetCard implements PCI {
public void open() {
System.out.println("netCard run");
}
public void close() {
System.out.println("netCard close");
}
}
import java.io.*;
import java.util.Properties;
public class ReflectTest {
public static void main(String[] args) throws Exception {
MainBoard mb=new MainBoard();
mb.run();
/*
//每次添加一个设备都要修改代码传递一个新创建的对象,能不能不修改代码就可以完成这个动作
mb.usePCI(new SoundCard());
不用new来完成,而是只获取其CLASS文件,在内部实现创建对象的动作
*/
File config=new File("pci.properties");
FileInputStream fis=new FileInputStream(config);
Properties p=new Properties();
p.load(fis);
for(int x=0;x<p.size();x++)
{
String pciName=p.getProperty("pci"+(x+1));
Class clazz=Class.forName(pciName);//用class去加载这个pci子类
PCI pci=(PCI)clazz.newInstance();
mb.usePCI(pci);
}
fis.close();
}
}
配置文件pci.properties:
pci1=mainDemo.SoundCard
pci2=mainDemo.NetCard