java反射机制

匿名 (未验证) 提交于 2019-12-02 21:53:52

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)

转载请标明出处:java反射机制
文章来源: java反射机制
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!