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

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

一、获取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");
    }



}
posted @ 2017-07-30 19:07  测试开发分享站  阅读(94)  评论(0编辑  收藏  举报