反射与内省

反射与内省

什么是反射

java反射机制是在运行状态中,对任意类都能知道它的所有属性和方法,对于任意对象都能调用它的任意方法,这种动态获取信息以及动态调用对象的方法的功能就称为java语言的反射机制。

Class类的作用

Class类是java反射机制的起源和入口,用于获取与类相关的各种信息,提供了获取类信息的相关方法。Class类继承与Object。
Class类是所有类的图纸。每个类都有自己的对象,就好比图纸和实物的关系;每个类也可以看做一个对象,有共同的图纸Class,存放类的结构信息,能够通过相应的方法取出相应的信息。比如:类的名字、属性、方法、构造方法、父类和接口。

Class类实例化的三种方式(常用的)

1. 通过对象.getClass()实例化
    Person p = new Person();
	Class clazz = p.getClass();
2. 通过类名.Class实例化
    Class clazz = p.Class;
3. 通过调用Class类的forName()方法获取
    Class.forName("全类名");//全类名即包名.类名

通过Class取得类的完整信息和调用类中的属性和方法

//通过反射调用类的无参构造方法
Class.newInstance();
//获取类的公有属性,只获取本类的共有方法
Class.getFields();
//获取类的公有方法,获取本类的和父类的
Class.getMethods();
//获取类的所有属性,只获取本类的所有属性,class是每一个类都会有的属性是static修饰的
Class.getDeclaredFields();
//获取类的所有方法,只获取本类中的所有方法
Class.getDeclaredMethods();

例子:
    public class Person {
    private String name;
    private int age;
    public int sex;
    public int height;

    public Person() {
    }
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    private void print(){
        System.out.println("name"+name);
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public void say(String name){
        System.out.println(name+"fanlenile");
    }
    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", sex=" + sex +
                ", height=" + height +
                '}';
    }
}

---
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
public class ReflectTest2 {
    public static void main(String[] args) {
        Person person = new Person("小花花",22);
        Class clazz = person.getClass();
        //---------获取公有-----------
        //获取共有属性,只获取本类的共有属性
        Field[] fields = clazz.getFields();
        for (Field field : fields) {
            System.out.print(field.getName()+" ");
            System.out.println(field.getModifiers());
            System.out.println(Modifier.toString(field.getModifiers()));
        }
        System.out.println("---------------");
        //获取共有方法,获取本类的和父类的共有属性
        Method[] methods = clazz.getMethods();
        for (Method method : methods) {
            System.out.print(method.getName()+" ");
            System.out.println(method.getModifiers());
            System.out.println(Modifier.toString(method.getModifiers()));
            System.out.println("---------------------------");
        }

        //获取所有
        //获取所有的属性,只能获取本类的所有属性
        Field[] declaredFields = clazz.getDeclaredFields();
        for (Field declaredField : declaredFields) {
            System.out.println(declaredField.getName());
        }
        System.out.println("---------------------");
        //获取所有的方法,只能获取本类中的所有方法
        Method[] declaredMethods = clazz.getDeclaredMethods();
        for (Method declaredMethod : declaredMethods) {
            System.out.println(declaredMethod.getName());
        }
        try {
            //调用本类中的私有方法,需要使用到setAccessible(true),否则不能调用私有的方法
            Method print = clazz.getDeclaredMethod("print");
            print.setAccessible(true);
            print.invoke(person);
        } catch (Exception e) {
            e.printStackTrace();
        }
        //调用本类中的共有方法
        try {
            Method getName = clazz.getDeclaredMethod("say",String.class);
            getName.invoke(person,"白白");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

九大预定义的Class对象:

八大基本数据类型和void

JavaBean的概念

什么是JavaBean?
    Bean能够理解为组件的意思,JavaBean就是java组价,在广泛的理解里就是一个类。对于组件来说,关键在于具有“能够被IDE构件工具侦测其属性和事件”的能力,通常在Java中:
    一个JavaBean要具备这样的命名规则:
    1. 对于一个名称为XXX的属性,通常你要写两个方法getXxx()setXxx()。任何浏览这些方法的工具,都会把get和set的最后面一个 字母自动转换为大写。
    2. 对于布尔型属性,可以使用以上get和set的方法,不过也可以把get替换成is
    3. Bean的普通方法不必遵循以上的命名规则,不过他们必须是public

内省

内省是java语言对Bean类属性、事件的一中缺省处理方法。例如类A中有属性name,那我们可以通过getName()setName()来得到值或者设置新的值。
通过getName()/setName来访问name属性,这就是默认的规则。
    
Java中提供了一套API用来访问某个属性的getter/setter方法,这些API存放在java.beans包中,一般的做法是通过类Introspector的getBeanInfo方法来获取某个对象的beaninfo信息,然后通过BeanInfo来获取属性的描述器(PropertyDescriptor),通过这个属性描述器就可以获取到某个属性的getter和setter方法,然后我们就可以通过反射机制来调用这些方法。

Introspector相关API
1.Introspector类:提供getBeanInfo(Class)方法
2.BeanInfo类:该类实现此BeanInfo接口并提供有关其Bean的方法、属性、事件等显示信息。该类提供getMethodDescriptors()getPropertyDescriptors()方法,分别用来获取类中的方法、属性。
3.PropertyDescriptor类:描述JavaBean通过一对存储器方法导出了一个属性。getReadMethod():获得应该用于读取属性值的方法。getWriteMethod()获得应该用于写入属性值的方法。
4.MethodDescriptor类:描述一种特殊方法,即JavaBean支持从其他组件对其进行外部访问。getMethod():获得此MethodDescriptors封装的方法。

内省例子

配置文件:
name=introspectordemo.Cat
cat.id=20
cat.name=波斯猫
cat.price=2000.0f
--Cat类
public class Cat {
    private int id;
    private String name;
    private float price;
    public Cat() {
    }
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public float getPrice() {
        return price;
    }
    public void setPrice(float price) {
        this.price = price;
    }
    @Override
    public String toString() {
        return "Cat{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", price=" + price +
                '}';
    }
}
---CatFactory类
import java.beans.*;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.Properties;

public class CatFactory {
    private static Properties properties;
    //加载配置文件
    static{
        //实例化配置文件
        properties = new Properties();
        //导入配置文件
        try {
            properties.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("introspectordemo/bean.properties"));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    //设置猫类
    public static Cat getCat(String name){
        Cat cat = null;
        if(name =="cat"){
            //获取类信息
            String cname = properties.getProperty("name");
            try {
                Class aClass = Class.forName(cname);
                //实例化无参的构造器
                cat = (Cat) aClass.newInstance();
                //得到一个BeanInfo
                BeanInfo beanInfo = Introspector.getBeanInfo(aClass);
                //得到属性描述器
                PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
                for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {
                    System.out.println(propertyDescriptor.getName());
                    //给属性赋值
                    if("name".equals(propertyDescriptor.getName())){
                        Method writeMethod = propertyDescriptor.getWriteMethod();
                        writeMethod.invoke(cat,properties.getProperty("cat.name"));
                    }else if("id".equals(propertyDescriptor.getName())){
                        Method writeMethod = propertyDescriptor.getWriteMethod();
                        writeMethod.invoke(cat,Integer.parseInt(properties.getProperty("cat.id")));
                    }else if("price".equals(propertyDescriptor.getName())){
                        Method writeMethod = propertyDescriptor.getWriteMethod();
                        writeMethod.invoke(cat,Float.parseFloat(properties.getProperty("cat.price")));
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return cat;
    }
}
---Test测试类
public class Test {
    public static void main(String[] args) {
        String name  = "cat";
        Cat cat = CatFactory.getCat(name);
        System.out.println(cat);
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值