Java反射及 IoC原理、内省机制

JAVA反射及IoC原理、JAVA内省

1. 反射

反射是框架设计的灵魂,使用前提:必须先得到代表的字节码的Class,Class类用于表示.class文件(字节码文件)。

1.1 反射概述

主要指程序可以访问,检测和修改它本身状态或行为的一种能力,并能根据自身行为的状态和结果,调整或修改应用所描述行为的状态和相关的语义。

Java反射机制:在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性。

1.2 反射机制的作用

  • 在运行时判断任意一个对象所属的类
  • 在运行时获取类的对象
  • 在运行时访问java对象的属性,方法,构造方法等

1.3 反射机制的优缺点

  • 优点:运行时确定类型,再绑定(创建)对象,体现多态性,可降低类之间的耦合性。
  • 缺点:对性能有一定影响,使用反射可认为一种解释操作,告诉JVM想要进行何种操作,这类操作总是慢于直接执行相同的操作(如直接创建(new)对象)。

1.4 反射的使用

  • 获取Class对象
  • 获取类的构造方法
  • 获取类的成员变量
  • 获取类的成员方法

1.4.1 获取Class对象

    package Reflect;

    /*示例类Reflect.Domo,以下例子均用该类*/
    class Demo{
      private String name;

      public Demo(){}
      public Demo(String name){
        this.name = name;
      }
      public String getName(){
        return name;
      }
      public void setName(String name){
        this.name = name;
      }
      @override
      public String toString(){
        return "["+this.name+"]";
      }

      private String show(String name){
        return name;
      }
    }
    /**
     *获取Class对象的三种方法
     *1. Object-->getClass()方法;
     *2. 任何数据类型(包括基本数据类型)都有一个“静态”的class属性
     *3. 通过Class类的静态方法:forName(String className);
     *4. 一般采用第三种方式获取
     */

    class Hello{
      public static void main(String[] args){
        Class<?> demo = null;
        demo = class.forName("Reflect.Domo");
        System.out.println("demo.getName()");
      }
    }

    //[运行结果]:Reflect.Demo
    /**
     *通过Class实例化其他类的对象
     *经过以上步骤获取了一个Demo类的Class实例
     */

    class Hello{
      public static void main(String[] args){
        Class<?> demo = null;
        demo = class.forName("Reflect.Demo");
        Demo d = null;
        d = (Demo)d.newInstance();
        d.setName("leo");
        System.out.println(d);
      }
    }

    //[运行结果]:[leo]

  • 在运行期间,一个类,只有一个Class对象产生
  • 若需要反射的类只定义了一个有参数的构造函数之后,会出现错误,即使用不到,也应该编写一个无参的构造函数

1.4.2 获取构类的造方法

    class Hello{
      public static void main(String[] args){
        Class<?> demo = null;
        demo = class.forName("Reflect.Domo");
        //取得全部构造函数
        Constructor<?> cons[] = demo.getConstructors();

        Demo d1 = null;
        Demo d2 = null;
        d1 = cons[0].newInstance();
        d2 = cons[1].newInstance("leo");
      }
    }

    //[运行结果]:
    //[null]
    //[leo]

1.4.3 获取类的成员变量

    /**
     *获取类的成员变量并调用
     *1. 批量的
     *1.1) Field[] getFields():获取所有的“公有字段”
     *1.2) Field[] getDeclareFields():获取所有的字段,包括:私有、受保护、默认、公有
     *2. 获取单个的
     *2.1) public Field getField(String fieldName):获取某个公有字段
     *2.2) public Field getDeclaredField(String fieldName):获取某个字段(可以是私有的)
     *
     *
     *设置字段的值
     *Field-->public void set(Object obj, object value)
     *参数说明:
     *1.obj:要设置的字段所在的对象
     *2.value:要为字段设置的值
     */

    class Hello{
      public static void main(String[] args){
        Class<?> demo = null;
        demo = class.forName("Reflect.Domo");
        //获取字段
        Field[] fieldArray = demo.getFields();
        for(Field f:fieldArray){
           System.out.println(f);
        }

        //获取公有字段并调用,假设Demo类的name字段为公有
        Field f = demo.getField("name");
           System.out.println(f);

        //获取对象并为对象内字段设置值
        Demo d = (Demo)demo.getConstructor().newInstance();
        f.set(d,"leo");
      }
    }

1.4.4 获取类的成员方法

    /**
     *获取类的成员变量并调用
     *1. 批量的
     *1.1) public Method[] getMethods():获取所有公有方法(包含父类的方法也包含Object类)
     *1.2) public Method[] getDeclareMethods():获取所有的成员方法,包括私有的(不包括继承的)
     *2. 获取单个的
     *2.1) public Method getMethod(String name,Class<?>...parameterTypes):
     *参数说明:
     *name:方法名
     *Class...:形参的Class类型对象
     *2.2) public Method getDeclareMethod(String name,Class<?>...parameterTypes)
     *
     *
     *调用方法:
     *Method-->puvlic Object invoke(Object obj,Object...args)
     *参数说明:
     *obj:要调用方法的对象
     *args:调用方式时所传递的实参
     *
     */

    class Hello{
      public static void main(String[] args){
        Class<?> demo = null;
        demo = class.forName("Reflect.Domo");
        //获取所有共有方法
        Method[] methodArray = demo.getMethods();
        for(Method m:methodArray){
          System.out.println(m);
        }

        //获取公有的toString()方法
        Method m = demo.getMethod("toString",String.class);
          System.out.println(m);

        //获取私有的show()方法
        m = demo.getDeclareMethod("show",String.class);
        m.setAccessible(true); //解除私有限定

        //获取一个对象
        Demo d = demo.getConstructor().newInstance();
        Object result = m.invoke(d,"Yooo");
        System.out.println("["+result+"]")
        //[运行结果]:Yooo
      }
    }

1.5 IoC原理

Ssoring中的IoC的实现原理就是工厂模式加反射机制。

1.不使用反射机制的工厂模式

    /**
     *工厂模式
     */
    interface fruit{
      public abstract void eat();
    }

    class Apple implements fruit{
      public void eat(){
        System.out.println("Apple");
      }
    }

    class Orange implements fruit{
      public void eat(){
        System.out.println("Orange");
      }
    }
    // 构造工厂类
    // 也就是说以后如果我们在添加其他的实例的时候只需要修改工厂类就行了
    class Factory{
        public static fruit getInstance(String fruitName){
          fruit f=null;
          if("Apple".equals(fruitName)){
            f=new Apple();
          }
          if("Orange".equals(fruitName)){
            f=new Orange();
          }
          return f;
        }
    }

    class hello{
      public static void main(String[] a){
        fruit f=Factory.getInstance("Orange");
        f.eat();
      }
    }

当我们在添加一个子类的时候,就需要修改工厂类了。如果我们添加太多的子类的时候,改的就会很多。

2.利用反射机制的工厂模式

    package Reflect;

    interface fruit{
      public abstract void eat();
    }

    class Apple implements fruit{
      public void eat(){
        System.out.println("Apple");
      }
    }

    class Orange implements fruit{
      public void eat(){
        System.out.println("Orange");
        }
    }

    class Factory{
      public static fruit getInstance(String ClassName){
        fruit f=null;
        try{
            f=(fruit)Class.forName(ClassName).newInstance();
        }catch (Exception e) {
            e.printStackTrace();
        }
        return f;
      }
    }

    class hello{
      public static void main(String[] a){
        fruit f=Factory.getInstance("Reflect.Apple");
        if(f!=null){
            f.eat();
        }
      }
    }

现在就算我们添加任意多个子类的时候,工厂类就不需要修改。

使用反射机制的工厂模式可以通过反射取得接口的实例,但是需要传入完整的包和类名。而且用户也无法知道一个接口有多少个可以使用的子类,所以我们通过属性文件的形式配置所需要的子类。

3.使用反射机制并结合属性文件的工厂模式(即IoC)
先创建一个fruit.properties的资源文件

    apple=Reflect.Apple
    orange=Reflect.Orange

然后编写主类代码

    package Reflect;

    import java.io.*;
    import java.util.*;

    interface fruit{
      public abstract void eat();
    }

    class Apple implements fruit{
      public void eat(){
        System.out.println("Apple");
      }
    }

    class Orange implements fruit{
      public void eat(){
        System.out.println("Orange");
      }
    }
    //操作属性文件类
    class init{
      public static Properties getPro() throws FileNotFoundException, IOException{
        Properties pro=new Properties();
        File f=new File("fruit.properties");
        if(f.exists()){
            pro.load(new FileInputStream(f));
        }else{
            pro.setProperty("apple", "Reflect.Apple");
            pro.setProperty("orange", "Reflect.Orange");
            pro.store(new FileOutputStream(f), "FRUIT CLASS");
        }
        return pro;
      }
    }

    class Factory{
      public static fruit getInstance(String ClassName){
        fruit f=null;
        try{
            f=(fruit)Class.forName(ClassName).newInstance();
        }catch (Exception e) {
            e.printStackTrace();
        }
        return f;
      }
    }

    class hello{
      public static void main(String[] a) throws FileNotFoundException, IOException{
        Properties pro=init.getPro();
        fruit f=Factory.getInstance(pro.getProperty("apple"));
        if(f!=null){
            f.eat();
        }
      }
    }
    //[运行结果]:Apple

2. 内省

2.1 内省概述

可参看本页#3.1反射和内省的区别#。

在Java内省中,用到以上及各类。通过BeanInfo这个类可以获取到类中方法和属性。即通过类Introspector的getBeanInfo方法获取某个对象的BeanInfo信息,然后通过BeanInfo来获取属性的描述器(PropertyDescriptor),通过这个属性描述器可以获取某个属性对应的Getter/Setter方法,然后我们可以通过反射机制在调用这些方法,即为内省机制。

2.2 JDK内省类库

  • java.beans.Introspector:Introspector 类为通过工具学习有关受目标 Java Bean 支持的属性、事件和方法的知识提供了一个标准方法。
  • java.beans.BeanInfo接口:希望提供有关其 bean 的显式信息的 bean 实现者可以提供某个 BeanInfo 类,该类实现此 BeanInfo 接口并提供有关其 bean 的方法、属性、事件等显式信息。
  • java.beans.PropertyDescriptor:PropertyDescriptor 描述 Java Bean 通过一对存储器方法导出的一个属性。

2.3 内省类库测试代码示例

    //被测类
    public class User{
      private String name;

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

    public class IntrospectorTest {

      private User user ;

      public void init() {
        user = new User() ;
        user.setName("张三") ;
      }

      public void getBeanPropertyInfo() throws Exception {
        //获取User-BeanInfo对象:beanInfo是对一个Bean的描述,可以通过它取得Bean内部的信息
        /**
         *获取User-BeanInfo对象
         *1.Introspector类
         *     是一个工具类,提供了一系列取得BeanInfo的方法;
         *2.BeanInfo接口
         *     对一个JavaBean的描述,可以通过它取得Bean内部的信息;
         *3.PropertyDescriptor属性描述器类
         *     对一个Bean属性的描述,它提供了一系列对Bean属性进行操作的方法
         */
        BeanInfo userBeanInfo = Introspector.getBeanInfo(User.class) ;
        PropertyDescriptor[] pds = userBeanInfo.getPropertyDescriptors() ;
        for (PropertyDescriptor pd : pds) {
            Method method = pd.getReadMethod() ;
            String methodName = method.getName() ;
            Object result = method.invoke(user) ;
            System.out.println(methodName + "-->" + result);
        }
    }

      public void getBeanPropertyByName() throws Exception {
        //获取name属性的属性描述器
        PropertyDescriptor pd = new PropertyDescriptor("name", user.getClass()) ;

        //得到name属性的getter方法
        Method readMethod = pd.getReadMethod() ;

        //执行getter方法,获取返回值,即name属性的值
        String result = (String) readMethod.invoke(user) ;
        System.out.println("user.name" + "-->" + result);

        //得到name属性的setter方法
        Method writeMethod = pd.getWriteMethod() ;

        //执行setter方法,修改name属性的值
        writeMethod.invoke(user, "李四") ;
        System.out.println("user.name" + "-->" + user.getName());
      }

    }

总结:内省操作非常繁琐,所以Apache开发了一套简单、易用的API来操作Bean属性——BeanUtils工具包。

3. 反射和内省的区别

反射

反射就是Java运行状态吧Java类中的各种成分映射成相应的Java类,可以动态地获取所有的属性以及动态调用任意一个方法(包括成员变量、成员方法、构造器等),强调的是运行状态。

内省

内省(IntroSpector)是Java语言对Bean类属性、事件的一种缺省处理方法。

JavaBean:一种特殊的类,用于传递数据信息,这种类的方法主要用于访问私有的字段,切方法名符合某种命名规则,即Getter和Setter方法。用于两个模块之间传递信息的JavaBean称为“值对象”(Value Object,"VO")。

内省机制通过反射来实现,用来暴露一个Bean的属性、方法和事件。

原文地址:http://blog.51cto.com/13801495/2130813

时间: 2024-08-10 14:36:46

Java反射及 IoC原理、内省机制的相关文章

【Java笔记】Java——远程监控、反射、代理、内省机制

远程控制的基本原理 远程控制(RemoteControl)拥有控制端和被控端双方. 控制方通过请求,取得对远端的操作,实现远端的事件回放功能,同时,应该看得到远端桌面的画面.而被控方必须在建立ServerSocket之后进行对外来请求的鉴听. 1 /** 2 * 客户端发送事件 3 * @param e 4 */ 5 public void sendEvent(InputEvent e){ 6 try { 7 SinglClient.getInstance().getOos().writeObj

Java反射机制及IoC原理

一. 反射机制概念 主要是指程序可以访问,检测和修改它本身状态或行为的一种能力,并能根据自身行为的状态和结果,调整或修改应用所描述行为的状态和相关的语义.在java中,只要给定类的名字, 那么就可以通过反射机制来获得类的所有信息. 反射是Java中一种强大的工具,能够使我们很方便的创建灵活的代码,这些代码可以再运行时装配,无需在组件之间进行源代码链接.但是反射使用不当会成本很高! 类中有什么信息,利用反射机制就能可以获得什么信息,不过前提是得知道类的名字. 二. 反射机制的作用 在运行时判断任意

Java反射机制详解(3) -java的反射和代理实现IOC模式 模拟spring

IOC(Inverse of Control) 可翻译为“控制反转”,但大多数人都习惯将它称为“依赖注入”.在Spring中,通过IOC可以将实现类.参数信息等配置在其对应的配置文件中,那么当 需要更改实现类或参数信息时,只需要修改配置文件即可,这种方法在上例的基础上更进一步的降低了类与类之间的耦合.我们还可以对某对象所需要的其它对象进 行注入,这种注入都是在配置文件中做的,Spring的IOC的实现原理利用的就是Java的反射机制, Spring还充当了工厂的角色,我们不需要自己建立工厂类.S

Java反射机制剖析(四)-深度剖析动态代理原理及总结

动态代理类原理(示例代码参见java反射机制剖析(三)) a)  理解上面的动态代理示例流程 a)  理解上面的动态代理示例流程 b)  代理接口实现类源代码剖析 咱们一起来剖析一下代理实现类($Proxy0)的源代码和整个动态代理的流程. $Proxy0生成的代码如下: import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; impo

Java反射机制的原理及在Android下的简单应用

花了几天时间,研究了一下Java的反射机制.在这里总结一下这几天学习的成果,一来分享自己的学习过程和在学习中遇到的问题,二来是给像我一样不太了解Java反射机制的同学做一个简单的介绍.在文章后面会链接一个Android反射机制的应用程序. 一.反射的概念及在Java中的类反射 反射主要是指程序可以访问.检测和修改它本身状态或行为的一种能力.在计算机科学领域,反射是一类应用,它们能够自描述和自控制.这类应用通过某种机制来实现对自己行为的描述和检测,并能根据自身行为的状态和结果,调整或修改应用所描述

Java反射机制学习

Java 反射是Java语言的一个很重要的特征,它使得Java具体了“动态性”. 在Java运行时环境中,对于任意一个类,能否知道这个类有哪些属性和方法?对于任意一个对象,能否调用它的任意一个方法?答案是肯定的.这种动态获取类的信息以及动态调用对象的方法的功能来自于Java 语言的反射(Reflection)机制. Java 反射机制主要提供了以下功能: 在运行时判断任意一个对象所属的类. 在运行时构造任意一个类的对象. 在运行时判断任意一个类所具有的成员变量和方法. 在运行时调用任意一个对象的

java 反射机制(我的第一篇博客)

JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法和属性:这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制. JAVA反射(放射)机制:“程序运行时,允许改变程序结构或变量类型,这种语言称为动态语言”.从这个观点看,Perl,Python,Ruby是动态语言,C++,Java,C#不是动态语言.但是JAVA有着一个非常突出的动态相关机制:Reflection,用在Java身上指的是我们可以于运行时

面试题之------Java 反射机制

一.反射机制概述 Java 反射机制是在运行状态中,对于任意一个类,都能够获得这个类的所有属性和方法,对于任意一个对象都能够调用它的任意一个属性和方法.这种在运行时动态的获取信息以及动态调用对象的方法的功能称为Java 的反射机制. Class 类与java.lang.reflect 类库一起对反射的概念进行了支持,该类库包含了Field,Method,Constructor类(每个类都实现了Member 接口).这些类型的对象时由JVM 在运行时创建的,用以表示未知类里对应的成员. 这样你就可

Java反射机制大神必学系列之 ,高级与低级的差别在哪里?

Java反射机制大神必学系列之 ,高级与低级的差别在哪里?java学习爱好者 2019-05-20 19:08前言今天介绍下Java的反射机制,以前我们获取一个类的实例都是使用new一个实例出来.那样太low了,今天跟我一起来学习学习一种更加高大上的方式来实现. 正文Java反射机制定义 Java反射机制是指在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法和属性:这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制.