Java中的反射机制

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()方法里面传入对象和参数,无参则传null
method.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.SoundCard
pci2=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中写入类名,就可以了,已写好的代码不需要做任何修改,很好的符合了开闭原则。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值