(104)反射:获取Class的对象、构造函数、字段、方法。反射实例练习

来源:互联网 发布:access sql limit 编辑:程序博客网 时间:2024/05/19 14:15

反射机制:动态获取类中的信息。可以理解为对类的解剖
这里写图片描述
在一个已经做好的应用程序中,没有源码,只有对外提供的接口,所以不能创建新的对象。
在反射机制中,只要实现接口,然后在配置文件中写注明该类,在应用程序中就能自动加载
这里写图片描述

一、获取Class对象的方式:
方式1,Object类中的getClass()方法,想要用这种方式,必须要明确具体的类,并创建对象

        car c=new car();        Class clazz=c.getClass();        car c1=new car();        Class clazz=c1.getClass();        Class clazz1=c1.getClass();//返回运行时类        System.out.println(clazz1==clazz);//true

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

        Class clazz=car.class;        Class clazz1=car.class;        System.out.println(clazz1==clazz);//true

方式3,只要通过给定的类的字符串名称就可以获取该类,扩展性强
可以用Class类中方法来完成:forName,只要指定名称即可

        String className="com.Car.car";//必须指定包名的类,        Class clazz=Class.forName(className);//该方法抛异常        System.out.println(clazz);

二、获取Class中的构造函数

       //早期:new 时,先根据被new的类的名称找到该类的字节码文件,加载进内存并创建该字节码文件对象,然后创建该字节码文件对应的person对象        //com.Car.person p=new com.Car.person();        //现在:        String className="com.Car.person";        Class clazz=Class.forName(className);//获取到了class字节码文件对象        //Object obj=clazz.newInstance(); //创建该字节码文件对应的person对象,获取的是无参的构造函数对应的对象        Constructor constructor=clazz.getConstructor(String.class,int.class);//创建该字节码对应的person对象,获取含参的构造函数对象        //通过该构造器的newInstance创建person对象含参的实例        constructor.newInstance("张三",15);

三、获取Class中的字段

//创建对象        Class clazz=Class.forName("com.Car.person");        Object obj=clazz.newInstance();        //获取公共字段        Field f=clazz.getField("sex");//只能获取公共字段        System.out.println(f);//public java.lang.String com.Car.person.sex        //获取指定字段属性的值        Object objField=f.get(obj);        System.out.println(objField);        //获取任Object何权限的字段        Field f1=clazz.getDeclaredField("age");        System.out.println(f1);//private int com.Car.person.age        //获取特定对象的该字段值        //Object objField1=f1.get(obj);//java.lang.IllegalAccessException私有字段,不能访问java.lang.IllegalAccessException        //若非要访问,则可以通过父类继承过来的方法,对私有字段的访问权限取消检查(暴力访问)        f1.setAccessible(true);        Object objField1=f1.get(obj);        System.out.println(objField);        //设置字段的值        f1.set(obj, 60);//在指定对象上字段设置值        System.out.println(f1.get(obj));

四、获取Class中的方法

Class clazz=Class.forName("com.Car.person");        //Object obj=clazz.newInstance();        //获取包括父类的所有公共方法        Method [] method=clazz.getMethods();        for(Method m:method)        {            //System.out.println(m);        }        //获取本类中写的所有方法,不包含父类继承        Method[] method1=clazz.getDeclaredMethods();        for(Method m:method1)        {            //System.out.println(m);        }        //获取一个方法(无参)        Method method2=clazz.getMethod("run", null);        //System.out.println(method2);//public void com.Car.person.run()        //想要让run中的值是某个对象的值        Constructor construct=clazz.getConstructor(String.class,int.class);        Object obj=construct.newInstance("小强",20);        //想要运行这个方法        method2.invoke(obj, null);//没返回值,直接在方法中输出了        //获取一个方法含参        Method method3=clazz.getMethod("show", int.class,int.class);        method3.invoke(obj,80,63);

五、反射练习
在主板中可以有声卡等插件,在以前的学习中的做法是如下这样的:

package com.Car1;public class mainBoard {    public void run()    {        System.out.println("main.......run");    }    public void useSoundCard(soundCard sc)    {        sc.open();        sc.close();    }    public static void main(String[] args) {        mainBoard mb=new mainBoard();        mb.useSoundCard(new soundCard());        //这样做法的坏处就是要加网卡的话,还要修改网卡的代码,扩展性差    }}package com.Car1;public class soundCard {    public void open()    {        System.out.println("sound...open");    }    public void close()    {        System.out.println("sound...close");    }}

利用反射实现:
1)主板可以插入声卡网卡等,声卡等要实现个接口(PCI),这个接口是和主板关联的,比如主板中有public void usePCI(PCI p)方法,那么这个方法就能实现PCI中的功能(为简单起见,这个接口只有open、close功能)。
2)需要读配置文件用Properties类中的load方法加载文件到集合中,配置文件中放的是设备:类名,这样就可以通过遍历这个集合,将类名取出,利用类名创建对象p,然后再用主板的usePIC(p),就可以将这个设备运行起来了。
特别提示:若配置文件为空,则集合.size()==-1,则主板上没有可运行的,只能运行主板或者其他的接口。若需要添加PCI设备,只需要在配置文件中加入类名即可,不用修改主板代码(因为集合长度+1了),提高了程序的扩展性

package com.Car1;import java.io.*;import java.util.*;public class mainBoard {    public void run()    {        System.out.println("main.......run");    }    public void usePCI(PCI p)//无论是插入什么设备,只要是设备符合PCI这个接口,都有两个方法可用    {        p.open();        p.close();    }    public static void main(String[] args)throws Exception {        mainBoard mb=new mainBoard();        mb.run();        FileInputStream fis=new FileInputStream("e:\\pci.prop");//配置文件,格式是设备:类名        Properties prop=new Properties();        prop.load(fis);//将流中对象加载进集合        for(int x=0;x<prop.size();x++)        {            String className=prop.getProperty("pci"+(x+1));//获取类名               Class clazz=Class.forName(className);               PCI  p=(PCI)clazz.newInstance();               mb.usePCI(p);        }        fis.close();    }}package com.Car1;public interface PCI {    public void open() ;    public void close();}package com.Car1;public class soundCard implements PCI{    public void open()    {        System.out.println("sound...open");    }    public void close()    {        System.out.println("sound...close");    }}package com.Car1;public class netBoard implements PCI {    public void open()    {        System.out.println("net...open");    }    public void close()    {        System.out.println("net...close");    }}
阅读全文
0 0