Java的内省与反射

今天安全编程上机,本来以为就是简单的几个Java的小实验,但是在今天这个上机的时候,我第一次听说了JavaBean的内省机制,第一次听说,感觉很新奇,然后就查阅了相关资料发现这个与反射机制有些相关联,所以就想简单的总结一下今天上机的收获。学无止境,果然,学无止境。

个人博客:大碗稀饭
在讲解Java的内省机制之前,然我们来看看Java的反射机制。

反射机制

反射机制的优点:

可以实现动态的创建对象和编译,使代码更加灵活多变,比如在javaWeb方面。在开发的时候我们使用的MySQL,但是如果线上环境需要我们使用Orcale,如果我们实现了反射机制,那么我们只需要修改配置文件就可以了,而不用重新将代码编译一次。

反射机制的缺点:

对性能的影响。使用反射机制基本上是一种解释操纵,我们可以告诉JVM,我们希望做什么并且它满足我们的要求。这类操作总是慢于只直接执行相同的操作。

内省机制

什么是内省机制(或者说使用内省机制的好处):

  • 内省的出现有利于了对类对象属性的操作,减少了代码的数量。

  • 在计算机科学中,内省是指计算机程序在运行时(Run time)检查对象(Object)类型的一种能力,通常也可以称作运行时类型检查。不应该将内省和反射混淆。相对于内省,反射更进一步,是指计算机程序在运行时(Run time)可以访问、检测和修改它本身状态或行为的一种能力。

内省机制与反射的区别:

反射式在运行状态把Java类中的各种成分映射成相应的Java类,可以动态的获取所有的属性以及动态调用任意一个方法,强调的是运行状态。内省机制是通过反射来实现的,BeanInfo用来暴露一个bean的属性、方法和事件,以后我们就可以操纵该JavaBean的属性。

内省技术操作javabean更简单,方便,比如Apache提供的BeanUtils就是和内省技术的原理差不多,而且内省是基于反射的,只是在反射的基础之上封装了,很易于我们操作。

满足内审机制的条件:

  • 执行java.io.Serializable 接口
  • 提供无参数的构造器
  • 提供getter 和 setter方法访问它的属性

内省机制的操作方式:

  • 通过Introspector类获得Bean对象的 BeanInfo

  • 然后通过 BeanInfo 来获取属性的描述器(PropertyDescriptor)

  • 通过这个属性描述器就可以获取某个属性对应的 getter/setter方法

  • 然后通过反射机制来调用这些方法

  • 通过PropertyDescriptor来操作Bean对象

代码实现:

①使用传统的方式:

//普通的Bean
public class Bean {
    private String name;
    private Integer age;

    public String getName () {
        return name;
    }

    public Integer getAge () {
        return age;
    }

    public void setName (String name) {
        this.name = name;
    }

    public void setAge (Integer age) {
        this.age = age;
    }

    @Override
    public String toString () {
        return "Bean{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

//操作展示
public class Demo {
    public static void main (String[] args){}

    private static void demo2 () throws Exception {
        Bean bean = new Bean();
        BeanInfo beanInfo = Introspector.getBeanInfo(Bean.class);
        PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();

        //遍历全部方法
        for (PropertyDescriptor prop : propertyDescriptors){
            if("age".equals(prop.getName())){

                Method writeMethod = prop.getWriteMethod();
                writeMethod.invoke(bean,100);

            }else if("name".equals(prop.getName())){

                Method writeMethod = prop.getWriteMethod();
                writeMethod.invoke(bean,"哈哈哈");

            }
        }

        System.out.println(bean);
    }

    private static void demo1 () throws Exception {
        Bean bean = new Bean();

        PropertyDescriptor propertyDescriptor =
                new PropertyDescriptor("name", bean.getClass());

        System.out.println(bean);

        //相当于使用setName方法
        Method writeMethod = propertyDescriptor.getWriteMethod();
        writeMethod.invoke(bean,"你好世界");
        System.out.println(bean);

        //相当于使用getName方法
        Method readMethod = propertyDescriptor.getReadMethod();
        Object obj = readMethod.invoke(bean);
        System.out.println("Bean: "+obj);
    }
}

②使用Beanutils来操作

<!--Maven的相关依赖-->
<dependency>
   <groupId>commons-beanutils</groupId>
   <artifactId>commons-beanutils</artifactId>
   <version>1.9.3</version>
</dependency>
<!--需要使用引入commons-logging不然会报错-->
<dependency>
    <groupId>commons-logging</groupId>
    <artifactId>commons-logging</artifactId>
    <version>1.2</version>
</dependency>
//普通的Bean
import java.util.Date;
public class Bean {
    private String name;
    private Integer age;
    private Date date;

    public String getName () {
        return name;
    }

    public Integer getAge () {
        return age;
    }

    public void setName (String name) {
        this.name = name;
    }

    public void setAge (Integer age) {
        this.age = age;
    }

    public Date getDate () {
        return date;
    }

    public void setDate (Date date) {
        this.date = date;
    }

    @Override
    public String toString () {
        return "Bean{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", date.time=" + date.getTime() +
                '}';
    }
}

import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.beanutils.PropertyUtils;
import java.util.Date;

public class Demo {
    public static void main (String[] args) throws Exception {
    }

    private static void demo3 () throws Exception {
        Bean bean = new Bean();
        BeanUtils.setProperty(bean,"date",new Date());
        BeanUtils.setProperty(bean,"name",12);
        System.out.println(bean);

        //对于PropertyUtils.setProperty而言,类型不匹配就会报错
        //PropertyUtils.setProperty(bean,"name",12);
        //System.out.println(bean);

        PropertyUtils.setProperty(bean,"age",100);
        System.out.println(bean);
        //BeanUtils它以字符串的形式对javabean进行转换,
        // 而PropertyUtils是以原本的类型对javabean进行操作。
        //如果类型不对,就会有argument type mismatch异常。
    }

    private static void demo2 () throws Exception {
        //BeanUtils也支持级联操作
        Bean bean = new Bean();

        //相当于setDate
        BeanUtils.setProperty(bean,"date",new Date());
        System.out.println(bean);

        //级联操作
        BeanUtils.setProperty(bean,"date.time",1000);
        System.out.println(bean);
        //之所以可以 BeanUtils.setProperty(point, "birth.time", 10000);
        // 这样写,那是因为Date类中有getTime()和setTime()方法,
        // 即Date类中相当于有time这个属性。
    }

    private static void demo1 () throws Exception {
        Bean bean = new Bean();
        //相当于setName
        BeanUtils.setProperty(bean,"name","你好呀世界");
        //相当于setAge
        BeanUtils.setProperty(bean,"age",100);
        System.out.println(bean);

        //相当于getName
        System.out.println(BeanUtils.getProperty(bean,"name"));
        //相当于getAge
        System.out.println(BeanUtils.getProperty(bean,"age"));

        System.out.println(BeanUtils.getProperty(bean,"age").getClass().getName());
        //我们看到虽然属性x的类型是Integer,但是我们设置的时候无论是Integer还是String,
        // BeanUtils的内部都是当成String来处理的。
    }
}

总结

我觉的内省机制其实,是在反射机制上面进一步的封装,让我们在操作JavaBean的时候,使用内省机制,将会进一步简化我们的代码,让操作变得更加简洁,高效。

参考资料

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值