Java中的反射机制

来源:互联网 发布:平面设计软件分类 编辑:程序博客网 时间:2024/06/11 15:02

Java中的反射机制

JAVA反射机制是在运行状态中,对于任意一个类 (class文件),都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
动态获取类中信息,就是java反射 。可以理解为对类的解剖。要想要对字节码文件进行解剖,必须要有字节码文件对象.那么如何获取字节码文件对象呢?

获取字节码文件(.class文件)的三种方式:
1.Object类中的getClass()方法,想要用这种方法必须明确具体的类,并且创建对象,相对麻烦。

package cn.ruicai.bean;public class Person {    private int age;    private String name;    public Person(String name,int age) {        super();        this.age = age;        this.name = name;         System.out.println("Person param run..."+this.name+":"+this.age);    }    public Person() {        super();        System.out.println("person run");       }    public void show(){        System.out.println(name+"...show run..."+age);    }    private void privateMethod(){        System.out.println(" method run ");    }    public void paramMethod(String str,int num){        System.out.println("paramMethod run....."+str+":"+num);    }    public static void staticMethod(){        System.out.println(" static method run......");    }}Person p=new Person();Class clazz=p.getClass();//取得字节码文件

2.任何数据类型都具备一个静态的属性.class来获取其对应的Class对象。相对简单,但是还是要明确用到类中的静态成员,还是不够扩展

Class clazz=Person.class;

3.只要通过给定的类的 字符串名称就可以获取该类,更为扩展。可是用Class类中的方法完成。该方法就是forName.这种方式只要有名称即可,更为方便,扩展性更强。

String className="cn.ruicai.bean.Person";    //包.类名称Class clazz=Class.forName(className);

获取Class对象中的构造函数
早期,在new的时候,先根据被new的类的名称找寻该类的字节码文件,并加载进内存,创建该字节码文件对象,并接着创建该字节文件的对应的Person对象

    cn.ruicai.bean.Person p = new cn.ruicai.bean.Person();    Person p=new Person();

现在通过反射,在Class类中的forName()方法中,传入包.类名称,得到该类的class对象,通过该对象调用newInstance()方法即可实例化新的对象。

String name = "cn.ruicai.bean.Person";Class clazz = Class.forName(name);Object obj  = clazz.newInstance();        

注意:以上这种方法,只适合于,类中有无参构造的类。如果类中没有无参构造,就通过字节码文件对象,可以取得该类的构造函数:使用getConstructor(paramterTypes)方法

String name = "cn.ruicai.bean.Person";Class clazz=Class.forName(name);Constructor constructor = clazz.getConstructor(String.class,int.class);Object obj = constructor.newInstance("小明",38);       //获取字节码文件中的字段String name="cn.itcast.bean.Person";Class clazz=Class.forName(name);Field field=null;   //clazz.getField();注意:此方法只能获取非私有字段field=clazz.getDeclaredField("age");//只会取本类的字段,包括私有的//对私有字段的访问权限取消。暴力访问field.setAccessible(true);Object obj=clazz.newInstance();//通过clazz实例一个对象field.set(obj,89);Object o=field.get(obj);    //取得字段的值,必需要传入一个对象,       //获取字节码文件中的方法String name="cn.itcast.bean.Person";Class clazz=Class.forName(name);Method[] methods=clazz.getMethods();    //取得所有的公共的方法,返回的是Method数组//取得无参函数Method method=clazz.getMethod("show",null);//获取指定方法,传入方法名,对应方法无参则传null//取得方法后要想调用,则要创建一个对象,创建对象则要取得构造函数,这里取得有参数构造,方便属性输出Constructor cons=clazz.getConstructor(String.class,int.class);Object obj=cons.newInstance("小明",22);//通过obj这个对象,调用method 方法,invoke()方法里面传入对象和参数,无参则传nullmethod.invoke(obj,null);   //取得有参函数String name="cn.itcast.bean.Person";Class clazz=Class.forName(name);Method method=clazz.getMethod("paramMethod",String.class,int.class);Object obj=clazz.newInstance();  //调用次方法则通过类中的无参构造实例化一个对象method.invoke(obj,"小强",20);//调用方法,并传入相应的参数

利用反射增强程序扩展性应用
电脑开机后,主板运行,主板里可以插各种扩展性的卡,如果有声卡,则声卡打开,然后关闭,如果有网卡,则网卡打开然后关闭
1.主板类

public class MainBoard {    public void run(){       System.out.println("主板运行");    }    public void usePCI(PCI p){       if(p!=null){           p.open();           p.close();       }    }}

2.PCI扩展接口类

public interface PCI{    public void open();    public void close();}

3.声卡类

public class SoundCard implements PCI {    @Override    public void open() {       System.out.println("声卡打开。。。。");    }    @Override    public void close() {       System.out.println("声卡关闭");    }}

4.网卡类

public class NetCard implements PCI {    @Override    public void open() {       System.out.println("网卡打开");    }    @Override    public void close() {       System.out.println("网卡关闭");    }}

5.创建pci.properties配置文件:在项目工程右键,新建文件,取名为pci.properties

pci1=com.ruicai.test.SoundCardpci2=com.ruicai.test.NetCard    //包.类名称

6.main类

public class Test {    public static void main(String[] args) throws Exception {       MainBoard mb=new MainBoard();       mb.run();       File file=new File("pci.properties");       //创建配置文件       Properties pro=new Properties();        //创建属性       InputStream is=new FileInputStream(file);//创建输入流读取文件       pro.load(is);                           //通过输入流加载配置文件       for(int i=0;i<pro.size();i++){           String name=pro.getProperty("pci"+(i+1));       //通过名字取得property           Class clazz=Class.forName(name);           PCI pci=(PCI)clazz.newInstance();           mb.usePCI(pci);       }       is.close();    }}

如果后期,pci接口上还有其他扩展性的功能,只需写好该功能的类,然后在配置文件pci.properties中写入类名,就可以了,已写好的代码不需要做任何修改,很好的符合了开闭原则。

原创粉丝点击