zoukankan      html  css  js  c++  java
  • java反射机制

    java反射机制

    java语言允许通过程序化的方式间接对Class的对象实例操作,Class文件由类加载器装载后,在JVM中将形成一份描述class结构的元信息对象,通过该元信息对象可以获知class的结构信息,通过该源信息对象可以获知class的结构信息,如构造函数、属性和方法等

    举一个反射的小例子:

    car类主要包含三个属性,和一个无参构造函数与一个带参构造函数

    public class Car {
      private String brand;
      private String color;
      private int maxspeed;
    
      
      public Car() {
        System.out.println("init car");
      }
    
      public Car(String brand, String color, int maxspeed) {
        this.brand = brand;
        this.color = color;
        this.maxspeed = maxspeed;
      }
      
      public void introduce(){
        System.out.println("品牌:"+brand+"颜色:"+color+"最大速度:"+maxspeed);
      }
      public String getBrand() {
        return brand;
      }
    
      public void setBrand(String brand) {
        this.brand = brand;
      }
    
      public String getColor() {
        return color;
      }
    
      public void setColor(String color) {
        this.color = color;
      }
    
      public int getMaxspeed() {
        return maxspeed;
      }
    
      public void setMaxspeed(int maxspeed) {
        this.maxspeed = maxspeed;
      }
    }

    这里利用反射获取构造器实例化对象

    public class ReflectTest {
      //通过默认构造方法初始化car对象
      public static Car initDefaultConst() throws Throwable{
        //1.通过类装载器获取Car类对象
        ClassLoader loader = Thread.currentThread().getContextClassLoader();
        Class clazz =loader.loadClass("com.xiongda.spring.reflect.Car");
        
        //2.获取类的默认构造器对象并实例化Car
        Constructor cons =clazz.getDeclaredConstructor(null);
        Car car =(Car) cons.newInstance();
        
        //3.通过反射方法设置属性
        Method setBrand =clazz.getMethod("setBrand", String.class);
        setBrand.invoke(car, "奔驰");
        Method setColor =clazz.getMethod("setColor", String.class);
        setColor.invoke(car, "黑色");
        Method setMaxspeed =clazz.getMethod("setMaxspeed", int.class);
        setMaxspeed.invoke(car, 200);
        
        return car;
      }
      //通过带参构造方法初始化car对象
      public static Car initParamConst() throws Throwable{
      //1.通过类装载器获取Car类对象
        ClassLoader loader = Thread.currentThread().getContextClassLoader();
        Class clazz =loader.loadClass("com.xiongda.spring.reflect.Car");
        
        //2.获取类的带参构造器对象并实例化Car
        Constructor cons =clazz.getDeclaredConstructor(String.class,String.class,int.class);
        Car car =(Car) cons.newInstance("宝马","红色",180);
        
        return car;
      }
      
      
      public static void main(String[] args) throws Throwable {
        Car car1 =ReflectTest.initDefaultConst();
        Car car2 =ReflectTest.initParamConst();
        car1.introduce();
        car2.introduce();
      }
    }

    在传统方法中,我们一般是使用构造函数设置属性或者set方法设置属性

    类装载器ClassLoader
    类装载器就是寻找类的字节码文件并构造出类在JVM内部表示的对象组件,主要工作由ClassLoader及其子类负责,ClassLoader是一个重要的java运行时系统组件,它负责在运行时查找和装入class字节码文件

    工作机制:
    1.装载:查找和导入class文件
    2.链接:执行校验,准备和解析步骤
    3.初始化:对类的静态变量、静态代码块执行初始化工作

    重要方法:
    1.Class loadClass(String name)
    2.Class defineClass(String name,byte[] b, int off, int len)
    3.Class findSystemClass(String name)
    4.Class findLoadedClass(String name)
    5.ClassLoader getParent()

    Class反射对象描述类语义结构,可以从Class对象中获取构造函数,成员变量,方法等类元素的反射对象,并以编程的方式通过这些反射对象对目标对象进行操作。这些反射对象类在java.reflect包中定义

    三个最主要的反射类:
    Constructor
    Method
    Field

    在Spring中,通过IOC可以将实现类、参数信息等配置在其对应的配置文件中,那么当需要更改实现类或参数信息时,,只需要修改配置文件即可,我们还可以对其对象所需要的其它对象进行注入,这种注入都是在配置文件中做的

    Spring的IOC的实现原理利用的就是java的反射机制,Spring的工厂类会帮我们完成配置文件的读取、利用反射机制注入对象等工作,我们可以通过bean的名称获取对应的对象

    基本的javabean

    public class JavaBean {
      private String username;
      private String password;
      public String getUsername() {
        return username;
      }
      public void setUsername(String username) {
        this.username = username;
      }
      public String getPassword() {
        return password;
      }
      public void setPassword(String password) {
        this.password = password;
      }
      
    }

    读取配置文件,然后通过Java反射机制实例化javabean

    public class BeanFactory {
      private Map<String, Object> beanMap = new HashMap<>();
      
      /**
       * bean工厂的初始化
       * @param xml
       */
      public void init(String sxml){
        InputStream ins= null;
        Document doc = null;
          try {
            //1.创建读取配置文件的reader对象
            SAXReader reader =new SAXReader();
            //2.获取当前线程中的类装载器对象
            ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
            //3.从class目录下获取指定的xml文件
             ins = classLoader.getResourceAsStream(sxml);
             if(ins == null){
               System.out.println("获取流失败");
             }
             doc = reader.read(ins);
            Element root = doc.getRootElement();
            Element foo;
            
            //4.遍历xml文件中的Bean实例
            for(Iterator i =root.elementIterator("bean");i.hasNext();){
              foo=(Element) i.next();
              
              //5.针对每一个bean实例,获取bean的属性id和class
              Attribute id =foo.attribute("id");
              Attribute cls=foo.attribute("class");
              
              
              //6.利用java反射机制,通过class的名称获取class对象
              Class bean = Class.forName(cls.getText());
              
              //7.获取对应class的信息
              java.beans.BeanInfo info = java.beans.Introspector.getBeanInfo(bean);
              
              //8.获取其属性描述
              java.beans.PropertyDescriptor pd[] =info.getPropertyDescriptors();
              
              //9.创建一个对象,并在接下来的代码中为对象的属性赋值
              Object obj = bean.newInstance();
              
              //10.遍历该bean的property属性
              for(Iterator ite = foo.elementIterator("property");ite.hasNext();){
                Element foo2 = (Element) ite.next();
                
                //11.获取该property的name属性
                Attribute name = foo2.attribute("name");
                String value = null;
                
                //12.获取该property的子元素value的值
                for(Iterator ite1 =foo2.elementIterator("value");ite1.hasNext();){
                  Element node = (Element) ite1.next();
                  value = node.getText();
                 
                  break;
                }
                
                //13.利用java的反射机制调用对象的某个set方法,并将值设置进去
                for(int k=0;k<pd.length;k++){
                  if(pd[k].getName().equalsIgnoreCase(name.getText())){
                    Method mset = null;
                    mset = pd[k].getWriteMethod();
                    mset.invoke(obj, value);
                  }
                }
              }
              
              //14.将对象放入beanMap中,其中key为id值,value为对象
              beanMap.put(id.getText(), obj);
            }
          } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | IllegalArgumentException
              | InvocationTargetException | DocumentException | IntrospectionException e) {
            // TODO Auto-generated catch block
            if(doc ==null){
              System.out.println("获取失败");
            }
            e.printStackTrace();
          } 
      }
      
      public Object getBean(String beanName){
        Object obj =beanMap.get(beanName);
        return obj;
      }
      
      public static void main(String[] args) throws Throwable {
        BeanFactory factory = new BeanFactory();
        factory.init("config.xml");
        JavaBean  javabean =(JavaBean)factory.getBean("javaBean");
        System.out.println("username  "+javabean.getUsername());
        System.out.println("password  "+javabean.getPassword());
        
      }
    }

    xml文件

    <?xml version="1.0" encoding="UTF-8"?>
    <beans>
        <bean id="javaBean" class="com.xiongda.spring.reflect.JavaBean">
            <property name="username">
                <value>极客学院</value>
            </property>
            <property name="password">
                <value>1234567890</value>
            </property>
        </bean>
    </beans>

    注意:如果你是用eclipse的话,你这个xml文件一定要放在bin目录里面,否则会报出一个空指针异常。但是后来我发现,用IDEA的话就不存在这个问题。(解决这东西花了不少时间,至今还未明白为啥会存在这种区别)

    (备注:使用SAXReader需要导包dom4j)

  • 相关阅读:
    Codeforces Round #437 (Div. 2, based on MemSQL Start[c]UP 3.0
    Codeforces 294C 组合数学
    Educational Codeforces Round 40 (Rated for Div. 2)
    第13届景驰-埃森哲杯广东工业大学ACM程序设计大赛
    天梯赛和蓝桥杯省赛训练
    莫队算法
    牛客练习赛13
    51NOD-1391 预处理dp
    AtCoder Regular Contest 092
    大二下学期赛季
  • 原文地址:https://www.cnblogs.com/xtuxiongda/p/9222090.html
Copyright © 2011-2022 走看看