精华内容
下载资源
问答
  • JAVA反反射射机机制制实实例例详详解解 这篇文章主要介绍了JAVA反射机制,以实例形式较为详细的分析讲解了Java反射机制的具体概念功能与使用技巧, 具 一定参考借鉴价值,需要的朋友可以参考下 本文实例分析了JAVA反射...
  • void innerMethod){ void innerMethod){ JAVA 反射机制之 Class 类 API 实例介绍 - AJava JAVA 反射机制之 Class 类 API 实例介绍 核心提示本文针对 jdk6.0 中 java.lang.Class 类的 API 进 行了简单的实例应用 例子...
  • JAVA反射机制及其原理实现

    千次阅读 2020-03-10 23:08:34
    JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;public、protected、private。 OO(面向对象),private私有的,不能访问。...

     

    9.1 概念

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

    OO(面向对象),private私有的,不能访问。这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。**

    反射就是把java类中的各种成分映射成一个个的Java对象 例如:一个类有:成员变量、方法、构造方法、包等等信息,利用反射技术可以对一个类进行解剖,把各个组成部分映射成一个个对象。

    物理:有个反射的概念,通过镜子,可以知道物体的存在。看到一个镜像或名字等,知道物体在哪里。

    (其实:一个类中这些成员方法、构造方法、在加入类中都有一个类来描述) 如图是类的正常加载过程:反射的原理在与class对象。 熟悉一下加载的时候:Class对象的由来是将class文件读入内存,并为之创建一个Class对象。

    Student.java--->Student.class 经过编译成了一个字节码文件。

     

    img

    9.2 作用

    在日常的第三方应用开发过程中,经常会遇到某个类的某个成员变量、方法或是属性是私有的或是只对系统应用开放,这时候就可以利用Java的反射机制通过反射来获取所需的私有成员或是方法。当然,也不是所有的都适合反射,之前就遇到一个案例,通过反射得到的结果与预期不符。阅读源码发现,经过层层调用后在最终返回结果的地方对应用的权限进行了校验,对于没有权限的应用返回值是没有意义的缺省值,否则返回实际值起到保护用户的隐私目的。

    反射是框架设计的灵魂

    (使用的前提条件:必须先得到代表的字节码的Class,Class类用于表示.class文件(字节码))

    9.2.1 反编译:.class-->.java

    9.2.2通过反射机制访问java对象的属性,方法,构造方法等;

    User user=new User();--》形成的java文件-->XXX.class

    将来赋值的时候,不是User类,是不是就报错了啊。存在紧耦合的状态,我们做OO的目的就是高内聚、松耦合,说白了,就是模块内部实现特定功能,模块与模块之间,关联度不大。

    这种方式,是编译时

    我们以后写程序,更多的应该是运行时给值。

     

    9.3 反射机制的相关类

    与Java反射相关的类如下:

    类名用途
    Class类代表类的实体,在运行的Java应用程序中表示类和接口
    Field类代表类的成员变量(成员变量也称为类的属性)
    Method类代表类的方法
    Constructor类代表类的构造方法

    9.3.1 查看Class类在java中的api

    img

    Class 类的实例表示正在运行的 Java 应用程序中的类和接口。也就是jvm中有N多的实例每个类都有该Class对象。(包括基本数据类型) Class 没有公共构造方法。Class 对象是在加载类时由 Java 虚拟机以及通过调用类加载器中的defineClass 方法自动构造的。也就是这不需要我们自己去处理创建,JVM已经帮我们创建好了。

    没有公共的构造方法,方法共有64个太多了。下面用到哪个就详解哪个吧 img

    9.3.2 根据一个字符串得到一个类

    类名方法含义
    StringgetClass表示此对象运行时类的 Class 对象
    ClassforName具有指定名的类的 Class 对象
    包装类属性Type

    参考代码:

             String str="今天是反射课程";
             Class clz=str.getClass();//得到当前正在运行的类;
             System.out.println(clz);
             Class clz2=Integer.TYPE; //包装类型,不同;包装类.Type
             System.out.println(clz2);
             System.out.println(Boolean.TYPE);
             System.out.println(Double.TYPE);
             System.out.println(Character.TYPE);
     ​

    9.3.3 获取Class对象的 三种方式

    • Object:getClass

    • 任何数据类型(包含基本数据类型)都有一个"静态"的class属性,这时候可以通过类名.属性访问.

    • 通过Class类的静态方法:forName(string className路径)

    参考代码

    //1.使用第一种方式来获取User的Class对象;
             User user=new User(); //弄了一个User对象,在内存里面;
             Class clz1=user.getClass(); //对象.getClass
             System.out.println(clz1); //clz1:是什么类呢?com.aaa.chapter07.User;路径+类名;
             //2.使用第二种方式;
             Class clz2=User.class;      //类名.class 这个静态属性.
             System.out.println(clz2);
             //这时候,我们是不是考虑一下,之前讲的那个原理图。证明原理图,里面,正在运行的Class是一个。
             System.out.println(clz1==clz2);
             //3.Class.forName(类路径方式)
             try {
                 Class clz3=Class.forName("com.aaa.chapter07.User");
                 System.out.println(clz3);
                 System.out.println(clz2==clz3);
             } catch (ClassNotFoundException e) {
                 e.printStackTrace();
             }

    提问?最常用哪种?一般用第三个。松耦合方式。

    9.3.4 通过反射来获取构造方法

    调用方法:

    1.获取构造方法:

    1).批量的方法: public Constructor[] getConstructors():所有"公有的"构造方法 public Constructor[] getDeclaredConstructors():获取所有的构造方法(包括私有、受保护、默认、公有)

    2).获取单个的方法,并调用: public Constructor getConstructor(Class... parameterTypes):获取单个的"公有的"构造方法: public Constructor getDeclaredConstructor(Class... parameterTypes):获取"某个构造方法"可以是私有的,或受保护、默认、公有;

    例如:

    调用构造方法: Constructor-->newInstance(Object... initargs)

    package com.aaa.chapter07;
    
    import java.lang.reflect.Constructor;
    import java.lang.reflect.Field;
    import java.lang.reflect.InvocationTargetException;
    import java.sql.Connection;
    
    /**
     * Created by 张晨光 on 2020/3/10 10:24
     */
    public class Constructors {
        public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
            Class clz=Class.forName("com.aaa.chapter07.User");
            //2.获取所有公共字段;
    //        Field[] fields = clz.getFields();
    //        for(Field f:fields){
    //            System.out.println(f);
    //        }
            //2.获取所有共有 私有字段;
    //        Field[] fields = clz.getDeclaredFields();
    //        for(Field f:fields){
    //            System.out.println(f);
    //        }
            Field field=clz.getField("country");
            System.out.println(field);
            Object obj=clz.getConstructor().newInstance();
            field.set(obj,"中国");
            User u=(User)obj;
            System.out.println(u.getCountry());
        }
    }
    

    2、newInstance是 Constructor类的方法(管理构造函数的类) api的解释为: newInstance(Object... initargs) 使用此 Constructor 对象表示的构造方法来创建该构造方法的声明类的新实例,并用指定的初始化参数初始化该实例。 它的返回值是T类型,所以newInstance是创建了一个构造方法的声明类的新实例对象。并为之调用

     

    package com.aaa.chapter07;
    
    import java.lang.reflect.Constructor;
    import java.lang.reflect.InvocationTargetException;
    
    /**
     * Created by 张晨光 on 2020/3/10 22:29
     */
    public class InstanceDemo {
        public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
            Class clz=Class.forName("com.aaa.chapter07.User");
            //1.调用第一个默认构造方法,没有参数,创建实例之后,再次使用setter赋值。
    //        Constructor constructor = clz.getConstructor();//Alt+Enter,
    //        Object obj=constructor.newInstance();
    //        User user=(User)obj;
    //        user.setName("张老师");
    //        System.out.println(obj);
            //2.调用第二个有3个参数的构造方法,公共的构造方法,注意里面参数的使用方式.
    //        Constructor constructor2 = clz.getConstructor(String.class,char.class,Integer.class);
    //        Object obj2=constructor2.newInstance("张晨光",'男',18);//类似于之前的构造方法,填充值;
    //        User user2=(User)obj2;
    //        System.out.println(user2);
            //3.调用第三个私有构造方法,这个构造方法,我们说外部无法访问.
            Constructor declaredConstructor = clz.getDeclaredConstructor(String.class);
            //设置私有构造方法,可以访问,强制(暴力)访问.
            declaredConstructor.setAccessible(true);
            Object obj=declaredConstructor.newInstance("登徒子");
    
            User user3=(User)obj;
            System.out.println(user3);
        }
    }
    

    9.3.5 获取成员变量并调用

    获取成员变量并调用:

    1.批量的

    1).Field[] getFields():获取所有的"公有字段"

    2).Field[] getDeclaredFields():获取所有字段,包括:私有、受保护、默认、公有;

    2.获取单个的:

    1).public Field getField(String fieldName):获取某个"公有的"字段;

    2).public Field getDeclaredField(String fieldName):获取某个字段(可以是私有的)

    设置字段的值:

    Field --> public void set(Object obj,Object value):

    参数说明:

    1.obj:要设置的字段所在的对象;

    2.value:要为字段设置的值;

    展开全文
  • Java反射机制实现原理

    千次阅读 2016-05-14 22:10:57
    本文介绍Android反射机制实现原理,在介绍之前,要和Java进行比较,所以先看下Java中的反射相关知识: 一、反射的概念及在Java中的类反射  反射主要是指程序可以访问、检测和修改它本身状态或行为的一种能力。在...

    本文介绍Android反射机制实现与原理,在介绍之前,要和Java进行比较,所以先看下Java中的反射相关知识:
    一、反射的概念及在Java中的类反射
      反射主要是指程序可以访问、检测和修改它本身状态或行为的一种能力。在计算机科学领域,反射是一类应用,它们能够自描述和自控制。这类应用通过某种机制来实现对自己行为的描述和检测,并能根据自身行为的状态和结果,调整或修改应用所描述行为的状态和相关的语义。
      在Java中的反射机制,被称为Reflection(大家看到这个单词,第一个想法应该就是去开发文档中搜一下了)。它允许运行中的Java程序对自身进行检查,并能直接操作程序的内部属性或方法。Reflection机制允许程序在正在执行的过程中,利用Reflection APIs取得任何已知名称的类的内部信息,包括:package、 type parameters、 superclass、 implemented interfaces、 inner classes、 outer classes、 fields、 constructors、 methods、 modifiers等,并可以在执行的过程中,动态生成Instances、变更fields内容或唤起methods。
      好,了解这些,那我们就知道了,我们可以利用反射机制在Java程序中,动态的去调用一些protected甚至是private的方法或类,这样可以很大程度上满足我们的一些比较特殊需求。你当然会问,反射机制在Android平台下有何用处呢?
      我们在进行Android程序的开发时,为了方便调试程序,并快速定位程序的错误点,会从网上下载到对应版本的Android SDK的源码(这里给大家提供一个2.3.3版本的下载链接)。你会发现很多类或方法中经常加上了“@hide”注释标记,它的作用是使这个方法或类在生成SDK时不可见,那么我们的程序可能无法编译通过,而且在最终发布的时候,就可能存在一些问题。
      那么,对于这个问题,第一种方法就是自己去掉Android源码中的”@hide”标记,然后重新编译生成一个SDK。另一种方法就是使用Java反射机制了,可以利用这种反射机制访问存在访问权限的方法或修改其域。
      废话半天,该入正题了,在进入正题之前,先给上一个反射测试类的代码,该代码中定义了我们需要进行反射的类,该类并没有实际的用途,仅供做为测试类。提示:本文提供的代码,并不是Android平台下的代码,而是一个普通的Java程序,仅仅是对Java反射机制的Demo程序,所以大家不要放在Android下编译啊,否则出现问题,别追究我的责任啦!
    Android反射机制实现与原理 - Nelson - NelsonReflectionTest.java
    package crazypebble.reflectiontest;

    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.io.Serializable;

    public class ReflectionTest extends Object implements ActionListener,Serializable{
    // 成员变量
    private int bInt;
    public Integer bInteger = new Integer(4);
    public String strB = “crazypebble”;
    private String strA;

    // 构造函数
    public ReflectionTest() {
    
    }
    
    protected ReflectionTest(int id, String name) { 
    
    }
    
    // 成员方法
    public int abc(int id, String name) {
        System.out.println("crazypebble ---> " + id + "-" + name);
        return 0;
    }
    
    protected static void edf() {
    
    }
    
    @Override
    public void actionPerformed(ActionEvent e) {
        // TODO Auto-generated method stub
    
    }
    

    }

    二、反射机制中需要使用到的类
      我把需要使用的类列在下表中,其中对我们特别有用的类,通过着重标记显示出来,并将在后面的使用中逐步解释:
    Android反射机制实现与原理 - Nelson - Nelson

    三、Class类
      首先向大家说明一点,Class本身就是一个类,Class是该类的名称。看下面这个类的定义:
      public class MyButton extends Button {…}
      注意到上面的class的首字母是小写,它表示的是一种类类型,但是我们的Class是一个类,相当于上面定义的MyButton类。所以,千万不要把这里的Class做为一个类类型来理解。明白这一点,我们继续。
      Class类是整个Java反射机制的源头,Class类本身表示Java对象的类型,我们可通过一个Object对象的getClass()方法取得一个对象的类型,此函数返回的就是一个Class类。获取Class对象的方法有很多种:
    Android反射机制实现与原理 - Nelson - Nelson
      在平时的使用,要注意对这几种方法的灵活运用,尤其是对Class.forName()方法的使用。因为在很多开发中,会直接通过类的名称取得Class类的对象。

    四、获取类的相关信息
    1、获取构造方法
      Class类提供了四个public方法,用于获取某个类的构造方法。
        Constructor getConstructor(Class[] params) 根据构造函数的参数,返回一个具体的具有public属性的构造函数
        Constructor getConstructors() 返回所有具有public属性的构造函数数组
        Constructor getDeclaredConstructor(Class[] params) 根据构造函数的参数,返回一个具体的构造函数(不分public和非public属性)
        Constructor getDeclaredConstructors() 返回该类中所有的构造函数数组(不分public和非public属性)
      由于Java语言是一种面向对象的语言,具有多态的性质,那么我们可以通过构造方法的参数列表的不同,来调用不同的构造方法去创建类的实例。同样,获取不同的构造方法的信息,也需要提供与之对应的参数类型信息;因此,就产生了以上四种不同的获取构造方法的方式。
    Android反射机制实现与原理 - Nelson - Nelsonget_Reflection_Constructors()
    /**
    * 获取反射类中的构造方法
    * 输出打印格式:”Modifier修饰域 构造方法名(参数类型列表)”
    */
    public static void get_Reflection_Constructors(ReflectionTest r) {

        Class temp = r.getClass();
        String className = temp.getName();        // 获取指定类的类名
    
        try {
            Constructor[] theConstructors = temp.getDeclaredConstructors();           // 获取指定类的公有构造方法
    
            for (int i = 0; i < theConstructors.length; i++) {
                int mod = theConstructors[i].getModifiers();    // 输出修饰域和方法名称
                System.out.print(Modifier.toString(mod) + " " + className + "(");
    
                Class[] parameterTypes = theConstructors[i].getParameterTypes();       // 获取指定构造方法的参数的集合
                for (int j = 0; j < parameterTypes.length; j++) {    // 输出打印参数列表
                    System.out.print(parameterTypes[j].getName());
                    if (parameterTypes.length > j+1) {
                        System.out.print(", ");
                    }
                }
                System.out.println(")");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    

    2、获取类的成员方法
      与获取构造方法的方式相同,存在四种获取成员方法的方式。
        Method getMethod(String name, Class[] params) 根据方法名和参数,返回一个具体的具有public属性的方法
        Method[] getMethods() 返回所有具有public属性的方法数组
        Method getDeclaredMethod(String name, Class[] params) 根据方法名和参数,返回一个具体的方法(不分public和非public属性)
        Method[] getDeclaredMethods() 返回该类中的所有的方法数组(不分public和非public属性)
    Android反射机制实现与原理 - Nelson - Nelsonget_Reflection_Method()
    /**
    * 获取反射类的方法
    * 打印输出格式:”RetType FuncName(paramTypeList)”
    */
    public static void get_Reflection_Method(ReflectionTest r) {

        Class temp = r.getClass();
        String className = temp.getName();
    
        /*
         * Note: 方法getDeclaredMethods()只能获取到由当前类定义的所有方法,不能获取从父类继承的方法
         * 方法getMethods() 不仅能获取到当前类定义的public方法,也能得到从父类继承和已经实现接口的public方法
         * 请查阅开发文档对这两个方法的详细描述。
         */
        //Method[] methods = temp.getDeclaredMethods();
        Method[] methods = temp.getMethods();
    
        for (int i = 0; i < methods.length; i++) {
    
            // 打印输出方法的修饰域
            int mod = methods[i].getModifiers();
            System.out.print(Modifier.toString(mod) + " ");
    
            // 输出方法的返回类型
            System.out.print(methods[i].getReturnType().getName());    
    
            // 获取输出的方法名
            System.out.print(" " + methods[i].getName() + "(");
    
            // 打印输出方法的参数列表
            Class[] parameterTypes = methods[i].getParameterTypes();
            for (int j = 0; j < parameterTypes.length; j++) {
                System.out.print(parameterTypes[j].getName());
                if (parameterTypes.length > j+1) {
                    System.out.print(", ");
                }
            }
            System.out.println(")");
        }
    }
    

      在获取类的成员方法时,有一个地方值得大家注意,就是getMethods()方法和getDeclaredMethods()方法。
        getMethods():用于获取类的所有的public修饰域的成员方法,包括从父类继承的public方法和实现接口的public方法;
        getDeclaredMethods():用于获取在当前类中定义的所有的成员方法和实现的接口方法,不包括从父类继承的方法。
      大家可以查考一下开发文档的解释:
    getMethods() - Returns an array containing Method objects for all public methods for the class C represented by this Class. Methods may be declared in C, the interfaces it implements or in the superclasses of C. The elements in the returned array are in no particular order.
    getDeclaredMethods() - Returns a Method object which represents the method matching the specified name and parameter types that is declared by the class represented by this Class.
      因此在示例代码的方法get_Reflection_Method(…)中,ReflectionTest类继承了Object类,实现了actionPerformed方法,并定义如下成员方法:
        Android反射机制实现与原理 - Nelson - Nelson
      通过这两个语句执行后的结果不同:
      a、Method[] methods = temp.getDeclaredMethods()执行后结果如下:
        Android反射机制实现与原理 - Nelson - Nelson
      b、Method[] methods = temp.getMethods()执行后,结果如下:
         Android反射机制实现与原理 - Nelson - Nelson
    3、获取类的成员变量(成员属性)
      存在四种获取成员属性的方法
        Field getField(String name) 根据变量名,返回一个具体的具有public属性的成员变量
        Field[] getFields() 返回具有public属性的成员变量的数组
        Field getDeclaredField(String name) 根据变量名,返回一个成员变量(不分public和非public属性)
        Field[] getDelcaredField() 返回所有成员变量组成的数组(不分public和非public属性)
    Android反射机制实现与原理 - Nelson - Nelsonget_Reflection_Field_Value()
    /**
    * 获取反射类中的属性和属性值
    * 输出打印格式:”Modifier Type : Name = Value”
    * Note: 对于未初始化的指针类型的属性,将不输出结果
    */
    public static void get_Reflection_Field_Value(ReflectionTest r) {

        Class temp = r.getClass();    // 获取Class类的对象的方法之一
    
        try {
            System.out.println("public 属性");
            Field[] fb = temp.getFields();
            for (int i = 0; i < fb.length; i++) {
    
                Class cl = fb[i].getType();    // 属性的类型
    
                int md = fb[i].getModifiers();    // 属性的修饰域
    
                Field f = temp.getField(fb[i].getName());    // 属性的值
                f.setAccessible(true);
                Object value = (Object)f.get(r);
    
                // 判断属性是否被初始化
                if (value == null) {
                    System.out.println(Modifier.toString(md) + " " + cl + " : "      + fb[i].getName());
                }
                else {
                    System.out.println(Modifier.toString(md) + " " + cl + " : "      + fb[i].getName() + " = " + value.toString());
                }
            }
    
            System.out.println("public & 非public 属性");
            Field[] fa = temp.getDeclaredFields();
            for (int i = 0; i < fa.length; i++) {
    
                Class cl = fa[i].getType();    // 属性的类型
    
                int md = fa[i].getModifiers();    // 属性的修饰域
    
                Field f = temp.getDeclaredField(fa[i].getName());    // 属性的值
                f.setAccessible(true);    // Very Important
                Object value = (Object) f.get(r);
    
                if (value == null) {
                    System.out.println(Modifier.toString(md) + " " + cl + " : "      + fa[i].getName());
                }
                else {
                    System.out.println(Modifier.toString(md) + " " + cl + " : "  + fa[i].getName() + " = " + value.toString());
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    

    4、获取类、属性、方法的修饰域
      类Class、Method、Constructor、Field都有一个public方法int getModifiers()。该方法返回一个int类型的数,表示被修饰对象( Class、 Method、 Constructor、 Field )的修饰类型的组合值。
      在开发文档中,可以查阅到,Modifier类中定义了若干特定的修饰域,每个修饰域都是一个固定的int数值,列表如下:
        Android反射机制实现与原理 - Nelson - Nelson
      该类不仅提供了若干用于判断是否拥有某中修饰域的方法boolean isXXXXX(int modifiers),还提供一个String toString(int modifier)方法,用于将一个表示修饰域组合值的int数转换成描述修饰域的字符串。
        Android反射机制实现与原理 - Nelson - Nelson

    五、如何调用类中的private方法
      在介绍之前,先放一个代码吧,这段代码是参考其他文章的代码拷贝过来的,代码不算长,但是动态调用类的成员方法的过程讲解的通俗易懂。
    Android反射机制实现与原理 - Nelson - NelsonLoadMethod.java
    package crazypebble.reflectiontest;

    import java.lang.reflect.Constructor;
    import java.lang.reflect.Method;

    public class LoadMethod {

    /**
     * 在运行时加载指定的类,并调用指定的方法
     * @param cName            Java的类名
     * @param MethodName    方法名
     * @param types            方法的参数类型
     * @param params        方法的参数值
     * @return
     */
    public Object Load(String cName, String MethodName, String[] types, String[] params) {
    
        Object retObject = null;
    
        try {
            // 加载指定的类
            Class cls = Class.forName(cName);    // 获取Class类的对象的方法之二
    
            // 利用newInstance()方法,获取构造方法的实例
            // Class的newInstance方法只提供默认无参构造实例
            // Constructor的newInstance方法提供带参的构造实例
            Constructor ct = cls.getConstructor(null);
            Object obj = ct.newInstance(null);    
            //Object obj = cls.newInstance();
    
            // 构建 方法的参数类型
            Class paramTypes[] = this.getMethodTypesClass(types);
    
            // 在指定类中获取指定的方法
            Method meth = cls.getMethod(MethodName, paramTypes);
    
            // 构建 方法的参数值
            Object argList[] = this.getMethodParamObject(types, params);
    
            // 调用指定的方法并获取返回值为Object类型
            retObject = meth.invoke(obj, argList);
    
        } catch (Exception e) {
            System.err.println(e);
        }
    
        return retObject;
    }
    
    /**
     * 获取参数类型,返回值保存在Class[]中
     */
    public Class[] getMethodTypesClass(String[] types) {
        Class[] cs = new Class[types.length];
    
        for (int i = 0; i < cs.length; i++) {
            if (types[i] != null || !types[i].trim().equals("")) {
                if (types[i].equals("int") || types[i].equals("Integer")) {
                    cs[i] = Integer.TYPE;
                } 
                else if (types[i].equals("float") || types[i].equals("Float")) {
                    cs[i] = Float.TYPE;
                }
                else if (types[i].equals("double") || types[i].equals("Double")) {
                    cs[i] = Double.TYPE;
                }
                else if (types[i].equals("boolean") || types[i].equals("Boolean")) {
                    cs[i] = Boolean.TYPE;
                }
                else {
                    cs[i] = String.class;
                }
            }
        }
        return cs;
    }
    
    /**
     * 获取参数Object[]
     */
    public Object[] getMethodParamObject(String[] types, String[] params) {
    
        Object[] retObjects = new Object[params.length];
    
        for (int i = 0; i < retObjects.length; i++) {
            if(!params[i].trim().equals("")||params[i]!=null){  
                if(types[i].equals("int")||types[i].equals("Integer")){  
                    retObjects[i]= new Integer(params[i]);  
                }
                else if(types[i].equals("float")||types[i].equals("Float")){  
                    retObjects[i]= new Float(params[i]);  
                }
                else if(types[i].equals("double")||types[i].equals("Double")){  
                    retObjects[i]= new Double(params[i]);  
                }
                else if(types[i].equals("boolean")||types[i].equals("Boolean")){  
                    retObjects[i]=new Boolean(params[i]);  
                }
                else{  
                    retObjects[i] = params[i];  
                }  
            } 
        }
    
        return retObjects;
    }
    

    }

      要调用一个类的方法,首先需要一个该类的实例(当然,如果该类是static,就不需要实例了,至于原因,你懂得!)。
    1、创建一个类的实例
      在得到一个类的Class对象之后,我们可以利用类Constructor去实例化该对象。Constructor支持泛型,也就是它本身应该是Constructor。这个类有一个public成员函数:T newInstance(Object… args),其中args为对应的参数,我们通过Constructor的这个方法来创建类的对象实例。
      在代码LoadMethod.java和LoadMethodEx.java中,分别给出了两种实例化Class类的方法:一种是利用Constructor类调用newInstance()方法;另一种就是利用Class类本身的newInstance()方法创建一个实例。两种方法实现的效果是一样的。
    // 利用newInstance()方法,获取构造方法的实例

    // Class的newInstance方法,仅提供默认无参的实例化方法,类似于无参的构造方法

    // Constructor的newInstance方法,提供了带参数的实例化方法,类似于含参的构造方法

    Constructor ct = cls.getConstructor(null);

    Object obj = ct.newInstance(null);

    Object obj = cls.newInstance();
    2、行为
      Method类中包含着类的成员方法的信息。在Method类中有一个public成员函数:Object invoke(Object receiver, Object… args),参数receiver指明了调用对象,参数args指明了该方法所需要接收的参数。由于我们是在运行时动态的调用类的方法,无法提前知道该类的参数类型和返回值类型,所以传入的参数的类型是Object,返回的类型也是Object。(因为Object类是所有其他类的父类)
      如果某一个方法是Java类的静态方法,那么Object receiver参数可以传入null,因为静态方法从不属于对象。
    3、属性
      对类的成员变量进行读写,在Field类中有两个public方法:
        Object get(Object object),该方法可用于获取某成员变量的值
        Void set(Object object, Object value),该方法设置某成员变量的值
      其中,Object参数是需要传入的对象;如果成员变量是静态属性,在object可传入null。

    六、对LoadMethod.java的优化处理
      在上一节中给出的LoadMethod.java中,类LoadMethod对固定参数类型的方法进行了调用,并且参数类型是通过一个String[]数组传入,然后经过方法 getMethodTypesClass() 解析之后,才得到了参数的具体的类型。同时在getMethodTypesClass()和getMethodParamObject()方法中,通过对传入的字符串参数进行过滤后,再处理那些可以匹配中的参数类型,其他不能匹配的参数都做为String对象来处理。如果我们调用的方法所需要的参数不是简单类型的变量,而是自定义的类对象,或者List列表,再如果我们只知道类名和方法名,不知道方法的参数类型,那我们该如何处理这些情况呢?
      因此,我对LoadMethod类进行了一定的优化处理。先附上代码:
    Android反射机制实现与原理 - Nelson - NelsonLoadMethodEx.java
    package crazypebble.reflectiontest;

    import java.lang.reflect.Constructor;
    import java.lang.reflect.Method;

    public class LoadMethodEx {

    /**
     * 在运行时加载指定的类,并调用指定的方法
     * @param cName            Java的类名
     * @param MethodName    方法名
     * @param params        方法的参数值
     * @return
     */
    public Object Load(String cName, String MethodName, Object[] params) {
    
        Object retObject = null;
    
        try {
            // 加载指定的类
            Class cls = Class.forName(cName);    // 获取Class类的对象的方法之二
    
            // 利用newInstance()方法,获取构造方法的实例
            // Class的newInstance方法只提供默认无参构造实例
            // Constructor的newInstance方法提供带参的构造实例
            Constructor ct = cls.getConstructor(null);
            Object obj = ct.newInstance(null);    
            //Object obj = cls.newInstance();
    
            // 根据方法名获取指定方法的参数类型列表
            Class paramTypes[] = this.getParamTypes(cls, MethodName);
    
            // 获取指定方法
            Method meth = cls.getMethod(MethodName, paramTypes);
            meth.setAccessible(true);
    
            // 调用指定的方法并获取返回值为Object类型
            retObject = meth.invoke(obj, params);
    
        } catch (Exception e) {
            System.err.println(e);
        }
    
        return retObject;
    }
    
    /**
     * 获取参数类型,返回值保存在Class[]中
     */
    public Class[] getParamTypes(Class cls, String mName) {
        Class[] cs = null;
    
        /*
         * Note: 由于我们一般通过反射机制调用的方法,是非public方法
         * 所以在此处使用了getDeclaredMethods()方法
         */
        Method[] mtd = cls.getDeclaredMethods();    
        for (int i = 0; i < mtd.length; i++) {
            if (!mtd[i].getName().equals(mName)) {    // 不是我们需要的参数,则进入下一次循环
                continue;
            }
    
            cs = mtd[i].getParameterTypes();
        }
        return cs;
    }
    

    }

     我们通过前面几节的一系列分析,只要我们知道了一个类的类名(包括其包的路径),那我们就可以通过Class类的一系列方法,得到该类的成员变量、构造方法、成员方法、以及成员方法的参数类型和返回类型、还有修饰域等信息。
    

      如果我们已经知道某个类名和需要动态调用的方法名,怎样才能不用传入方法的参数类型就可以调用该方法呢?
    在已知类名的情况下,我们可以打印输出该类的所有信息,当然包括类的成员方法;然后通过给定的方法名,对打印输出的方法名进行筛选,找到我们需要的方法;再通过该方法的Method对象,得到该方法的参数类型、参数数量、和返回类型。那么我们在外部动态调用该方法时,就不需要关心该类需要传入的参数类型了,只需要传入类名、方法名、参数值的信息即可。笔者实现了一个类LoadMethodEx,先从两个类的同一个方法需要的参数方面做一个对比:
        Android反射机制实现与原理 - Nelson - Nelson
        Android反射机制实现与原理 - Nelson - Nelson
      1、LoadMethodEx类,少了一个参数(方法参数类型列表),本文直接从类LoadMethod内部获取该参数类型列表,不需要用户传入该信息,好处其实也不言而喻了。
      2、方法的参数值:类LoadMethod是将所有的方法参数都做为一个String来传入,在传入再进行解析;而本文则直接使用Object类型做为参数类型,因为invoke(Object obj, Object…args)方法本身所需要的参数类型就是Object,避免了不必要的参数类型变换。
      在调用LoadMethod的Load()方法时,用户只需要知道类名、方法名,并且将已经初始化的参数先向上转型为Object,然后传递给Load()方法即可。方法的返回值为Object,这个肯定是由用户根据自己的需要,再转换成自己所需的类型。
    Android反射机制实现与原理 - Nelson - Nelson执行结果
    属性:
    public 属性
    public class java.lang.Integer : bInteger = 4
    public class java.lang.String : strB = crazypebble
    public & 非public 属性
    private int : bInt = 0
    public class java.lang.Integer : bInteger = 4
    public class java.lang.String : strB = crazypebble
    private class java.lang.String : strA

    构造方法:
    public crazypebble.reflectiontest.ReflectionTest()
    protected crazypebble.reflectiontest.ReflectionTest(int, java.lang.String)

    父类/接口:
    父类: java.lang.Object
    接口0: java.awt.event.ActionListener
    接口1: java.io.Serializable

    成员方法:
    public int abc(int, java.lang.String)
    public void actionPerformed(java.awt.event.ActionEvent)
    public final native void wait(long)
    public final void wait()
    public final void wait(long, int)
    public boolean equals(java.lang.Object)
    public java.lang.String toString()
    public native int hashCode()
    public final native java.lang.Class getClass()
    public final native void notify()
    public final native void notifyAll()

    反射机制调用方法:LoadMethod
    crazypebble —> 1-hello, android-1!

    反射机制调用方法:LoadMethodEx
    crazypebble —> 2-hello, android-2?
    返回结果:0

    七、总结
      关于反射机制,其实还有一个比较敏感的话题,就是反射机制带来我们的安全性问题。由于我在这方面研究的不是很深入,所以讲不好。大家有空可以跟踪一下在本文最后提供的两个链接,里面有一些介绍。
      我们介绍了Java的反射机制,但是在Android平台下,反射机制具体有没有什么用途呢?答案是肯定的。推荐大家看一篇文章《利用Java反射技术阻止通过按钮关闭对话框》,这篇文章为CSDN推荐为精品文章,所以还是很值得一看的。我特地从CSDN转载过来供大家一起学习。
      原链接:http://blog.csdn.net/nokiaguy/archive/2010/07/27/5770263.aspx
      转载链接:http://www.cnblogs.com/crazypebble/archive/2011/04/13/2014297.html
    程序实现的源码:
    Android反射机制实现与原理 - Nelson - NelsonAndroidReflection
    package crazypebble.androidreflection;

    import java.lang.reflect.Field;

    import android.app.Activity;
    import android.app.AlertDialog;
    import android.content.DialogInterface;
    import android.os.Bundle;
    import android.view.View;
    import android.view.View.OnClickListener;
    import android.widget.Button;

    public class MainActivity extends Activity {
    /* Called when the activity is first created. /
    private static Button btnHandler = null;
    private static Button btnShowing = null;
    AlertDialog alertDialog = null;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
    
        btnHandler = (Button)findViewById(R.id.btn_mHandler);
        btnHandler.setOnClickListener(new ButtonListener());
    
        btnShowing = (Button)findViewById(R.id.btn_mShowing);
        btnShowing.setOnClickListener(new ButtonListener());
    
        alertDialog = new AlertDialog.Builder(this)
                .setTitle("abc")
                .setMessage("Content")
                .setIcon(R.drawable.icon)
                .setPositiveButton("确定", new PositiveClickListener())
                .setNegativeButton("取消", new NegativeClickListener())
                .create();
    }
    
    private class ButtonListener implements OnClickListener {
    
        @Override
        public void onClick(View v) {
            switch (v.getId()) {
            case R.id.btn_mHandler:
                modify_mHandler();
                alertDialog.show();
                break;
            case R.id.btn_mShowing:
                alertDialog.show();
                break;
            default:
                break;
            }
        }
    }
    
    private class PositiveClickListener implements android.content.DialogInterface.OnClickListener {
    
        @Override
        public void onClick(DialogInterface dialog, int which) {
            // 方法二时启用
            modify_dismissDialog(false);
        }
    }
    
    private class NegativeClickListener implements android.content.DialogInterface.OnClickListener {
    
        @Override
        public void onClick(DialogInterface dialog, int which) {
            // 方法一时启用
            //dialog.dismiss();
    
            // 方法二时启用
            modify_dismissDialog(true);
        }
    }
    
    /*
     * 第一种方法:修改AlertController类的private成员变量mHandler的值
     */
    public void modify_mHandler() {
        try {
            Field field = alertDialog.getClass().getDeclaredField("mAlert");
            field.setAccessible(true);
            // 获取mAlert变量的值
            Object obj = field.get(alertDialog);
            field = obj.getClass().getDeclaredField("mHandler");
            field.setAccessible(true);
            // 修改mHandler变量的值,使用新的ButtonHandler类
            field.set(obj, new MyButtonHandler(alertDialog));
    
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    /*
     * 第二种方法:修改dismissDialog()方法
     */
    public void modify_dismissDialog(boolean flag) {
        try {
            Field field = alertDialog.getClass().getSuperclass().getDeclaredField("mShowing");
            field.setAccessible(true);
            // 将mShowing变量设为false,表示对话框已经关闭
            field.set(alertDialog, flag);
            alertDialog.dismiss();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    

    }

    Android反射机制实现与原理 - Nelson - NelsonMyButtonHandler.java
    package crazypebble.androidreflection;

    import java.lang.ref.WeakReference;

    import android.content.DialogInterface;
    import android.os.Handler;
    import android.os.Message;

    public class MyButtonHandler extends Handler{

    // Button clicks have Message.what as the BUTTON{1,2,3} constant
    private static final int MSG_DISMISS_DIALOG = 1;
    
    private WeakReference<DialogInterface> mDialog;
    
    public MyButtonHandler(DialogInterface dialog) {
        mDialog = new WeakReference<DialogInterface>(dialog);
    }
    
    @Override
    public void handleMessage(Message msg) {
        switch (msg.what) {
    
            case DialogInterface.BUTTON_POSITIVE:
            case DialogInterface.BUTTON_NEGATIVE:
            case DialogInterface.BUTTON_NEUTRAL:
                ((DialogInterface.OnClickListener) msg.obj).onClick(mDialog.get(), msg.what);
                break;
        }
    }
    

    }
      看完上面这篇文章之后,希望大家明确一点的是:反射机制通过void setAccessible(boolean flag)方法可以得到一个类的private的方法和属性,使用这些private的方法和属性,已经可以做一些超越限制的事情了。所以在使程,还需谨慎啊!

    展开全文
  • Java反射机制原理和用途

    万次阅读 多人点赞 2017-09-07 11:19:14
    看了好多关于Java反射机制的文章,大多都太过官方,消化起来比较稍显费劲,本篇,我会依据自己的理解去阐述什么是Java的反射机制,反射用在什么地方,以及怎么来使用? 开篇前,我们还是要了解一下,什么是Java的...

    看了好多关于Java反射机制的文章,大多都太过官方,消化起来比较稍显费劲,本篇,我会依据自己的理解去阐述什么是Java的反射机制,反射用在什么地方,以及怎么来使用?

     

    开篇前,我们还是要了解一下,什么是Java的反射机制:

     

     

    “程序运行时,允许改变程序结构或变量类型,这种语言称为动态语言”。从这个观点看,Perl、Python看过我写的Python3学习系列的博文,不止一次突出Python动态语言的特点)、Ruby是动态语言,C++、Java、C#不是动态语言。但是JAVA有着一个非常突出的动态相关机制——Reflection(反射),用在Java身上指的是可以于运行时加载探知使用编译期间完全未知的classes。换句话说,Java程序可以加载一个运行时才得知名称的class,获悉其完整构造(但不包括methods定义),并生成其对象实体(newInstance)或对其fields设值,或唤起(invoke)其methods方法。

    注意 方法的声明和定义不是一回事,
    声明:public string Method(string parm1,int param2,...)
    定义:public string Method(string parm1,int param2,...)
              {
                    // do something
              }


    反射用在什么地方?


    由于,我们还不清楚反射究竟是什么玩意,怎么用,是不是我们平时写代码的时候会用得上? 这些,都不知道的话,我们也没法定论,这个Java反射机制,用在什么地方比较和合适(注意,一项技术的诞生,一定是为了方便另一项技术的使用,否则会失去本身存在的意义!)


    因此,我们先来说一下,反射怎么用?

     



    一、反射的应用



           我们可能听过,Java编写的程序,一次编译,到处运行。这也是Java程序为什么是无关平台的所在,原因在于,java的源代码会被编译成.class文件字节码,只要装有Java虚拟机JVM的地方(Java提供了各种不同平台上的虚拟机制,第一步由Java IDE进行源代码编译,得到相应类的字节码.class文件,第二步,Java字节码由JVM执行解释给目标计算机,第三步,目标计算机将结果呈现给我们计算机用户;因此,Java并不是编译机制,而是解释机制),.class文件畅通无阻。

           Java的反射机制,操作的就是这个.class文件,首先加载相应类的字节码(运行eclipse的时候,.class文件的字节码会加载到内存中),随后解剖(反射 reflect)出字节码中的构造函数、方法以及变量(字段),或者说是取出,我们先来定义一个类Animal,里面定义一些构造函数,方法,以及变量:




    Animal.java:

     

    package com.appleyk.reflect;
    
    public class Animal {
    
    	public String name ="Dog";
    	private int   age  =30 ;
    	
    	//默认无参构造函数
    	public Animal(){
    		System.out.println("Animal");
    	}
    	
    	//带参数的构造函数 
    	public Animal(String name , int age){
    		System.out.println(name+","+age);
    	}
    	
    	//公开 方法  返回类型和参数均有
    	public String sayName(String name){
    		return "Hello,"+name;
    	}
    	
    }
    

     


     



    我们再定义一个测试类:

    ReflectTest.java

     

    package com.appleyk.test;
    
    public class ReflectTest {
     
    	public static void main(String args[]) throws Exception{
    		
    		//do something 
    	}
      
    }
    




     




    我们运行一下我们的项目,会发现如下:



     


    对应内存中就是:




     


     

    我们借助javap命令查看一下,这个Animal.class里面的内容是什么:

     

    F:\Java\ReflectClass\bin\com\appleyk\reflect>javap -c Animal.class
    Compiled from "Animal.java"
    public class com.appleyk.reflect.Animal {
      public java.lang.String name;
    
      public com.appleyk.reflect.Animal();
        Code:
           0: aload_0
           1: invokespecial #12                 // Method java/lang/Object."<init>":
    ()V
           4: aload_0
           5: ldc           #14                 // String Dog
           7: putfield      #16                 // Field name:Ljava/lang/String;
          10: aload_0
          11: bipush        30
          13: putfield      #18                 // Field age:I
          16: getstatic     #20                 // Field java/lang/System.out:Ljava/
    io/PrintStream;
          19: ldc           #26                 // String Animal
          21: invokevirtual #28                 // Method java/io/PrintStream.printl
    n:(Ljava/lang/String;)V
          24: return
    
      public com.appleyk.reflect.Animal(java.lang.String, int);
        Code:
           0: aload_0
           1: invokespecial #12                 // Method java/lang/Object."<init>":
    ()V
           4: aload_0
           5: ldc           #14                 // String Dog
           7: putfield      #16                 // Field name:Ljava/lang/String;
          10: aload_0
          11: bipush        30
          13: putfield      #18                 // Field age:I
          16: getstatic     #20                 // Field java/lang/System.out:Ljava/
    io/PrintStream;
          19: new           #39                 // class java/lang/StringBuilder
          22: dup
          23: aload_1
          24: invokestatic  #41                 // Method java/lang/String.valueOf:(
    Ljava/lang/Object;)Ljava/lang/String;
          27: invokespecial #47                 // Method java/lang/StringBuilder."<
    init>":(Ljava/lang/String;)V
          30: ldc           #49                 // String ,
          32: invokevirtual #51                 // Method java/lang/StringBuilder.ap
    pend:(Ljava/lang/String;)Ljava/lang/StringBuilder;
          35: iload_2
          36: invokevirtual #55                 // Method java/lang/StringBuilder.ap
    pend:(I)Ljava/lang/StringBuilder;
          39: invokevirtual #58                 // Method java/lang/StringBuilder.to
    String:()Ljava/lang/String;
          42: invokevirtual #28                 // Method java/io/PrintStream.printl
    n:(Ljava/lang/String;)V
          45: return
    
      public java.lang.String sayName(java.lang.String);
        Code:
           0: new           #39                 // class java/lang/StringBuilder
           3: dup
           4: ldc           #64                 // String Hello,
           6: invokespecial #47                 // Method java/lang/StringBuilder."<
    init>":(Ljava/lang/String;)V
           9: aload_1
          10: invokevirtual #51                 // Method java/lang/StringBuilder.ap
    pend:(Ljava/lang/String;)Ljava/lang/StringBuilder;
          13: invokevirtual #58                 // Method java/lang/StringBuilder.to
    String:()Ljava/lang/String;
          16: areturn
    }

     




    我们发现,字节码里面包含了类Animal的构造函数、变量以及方法,但注意,全都是public类型的,我们的定义的类的私有变量 private int   age  =30 哪去了?当然,既然是类的私有部分,肯定不会暴露在外面的,但是不阻碍我们通过反射获得字节码中的私有成员(本篇只举例说明私有变量(字段field),其他私有类成员同理)。

    我们的类Animal在Anima.java中定义,但在Animal.class文件中,我们的Animal类阐述如下:



     




    下面,我们来写一段demo,来演示一下,如何使用反射机制,将.class文件中的类加载出来,并解剖出字节码中对应类的相关内容(构造函数、属性、方法):

    看代码前,我们学两个小技巧:



    (1)获得类的完全限定名:




     

    copy以后,直接paste

     




    (2)自动生成返回值对象

     




     

     

    ReflectTest.java:

     

    package com.appleyk.test;
    
    import java.lang.reflect.Constructor;
    
    import com.appleyk.reflect.Animal;
    
    public class ReflectTest {
     
    	public static void main(String args[]) throws Exception{
    		
    		//do something 
    		//1、加载类 ,指定类的完全限定名:包名+类名
    		 Class c1 = Class.forName("com.appleyk.reflect.Animal");
    		 System.out.println(c1);//打印c1,发现值和字节码中的类的名称一样
    		
    		 //2、解刨(反射)类c1的公开构造函数,且参数为null 
    		 Constructor ctor1= c1.getConstructor();
    		 
    		//3、构造函数的用途,就是创建类的对象(实例)的
    		//除了私有构造函数外(单列模式,禁止通过构造函数创建类的实例,保证一个类只有一个实例)
    		//ctor1.newInstance()默认生成一个Object对象,我们需要转化成我们要的Animal类对象
    		// Object a1 = ctor1.newInstance();
    		 Animal a1 = (Animal)ctor1.newInstance(); 
    		
    		//4、证明一下a1确实是Animal的实例,我们通过访问类中的变量来证明
    		 System.out.println(a1.name);
    	}
      
    }
    

     





    我们看下,上述demo 的执行结果:



     

     


     

     

    我们接着走,获得类中的变量(字段)和方法,两种方式,一个是getXXX,一个是getDeclaredXXX,二者是有区别的,下面demo注释的很详细,并且,我们使用反射出的字段和方法,去获取相应实例的字段值和唤起方法(相当于执行某实例的方法),我们看下完整版demo:

     

    加强版的 ReflectTest.java

     

    package com.appleyk.test;
    
    import java.lang.reflect.Constructor;
    import java.lang.reflect.Field;
    import java.lang.reflect.Method;
    
    import com.appleyk.reflect.Animal;
    
    public class ReflectTest {
    
    	public static void main(String args[]) throws Exception {
    
    		// do something
    
    		System.out.println("A(无参构造函数)--加载类、反射类的构造函数、利用构造函数new一个Animal实例instance--");
    
    		// 1、加载类 ,指定类的完全限定名:包名+类名
    		Class c1 = Class.forName("com.appleyk.reflect.Animal");
    		System.out.println(c1);// 打印c1,发现值和字节码中的类的名称一样
    
    		// 2.a、解刨(反射)类c1的公开构造函数,且参数为null
    		Constructor ctor1 = c1.getConstructor();
    
    		// 3、构造函数的用途,就是创建类的对象(实例)的
    		// 除了私有构造函数外(单列模式,禁止通过构造函数创建类的实例,保证一个类只有一个实例)
    		// ctor1.newInstance()默认生成一个Object对象,我们需要转化成我们要的Animal类对象
    		// Object a1 = ctor1.newInstance();
    		Animal a1 = (Animal) ctor1.newInstance();
    
    		// 4、证明一下a1确实是Animal的实例,我们通过访问类中的变量来证明
    		System.out.println(a1.name);
    
    		System.out.println("A(有参构造函数)--加载类、反射类的构造函数、利用构造函数new一个Animal实例instance--");
    		// 2.b、 解刨(反射)类c1的公开构造函数,参数为string和int
    		Constructor ctor2 = c1.getConstructor(String.class, int.class);
    		Animal a2 = (Animal) ctor2.newInstance("Cat", 20);
    
    		System.out.println("B--获得本类中的所有的字段----------------------------");
    
    		// 5、获得类中的所有的字段 包括public、private和protected,不包括父类中申明的字段
    		Field[] fields = c1.getDeclaredFields();
    		for (Field field : fields) {
    			System.out.println(field);
    
    		}
    
    		System.out.println("C--获得本类中的所有公有的字段,并获得指定对象的字段值-----");
    
    		// 6、获得类中的所有的公有字段
    		fields = c1.getFields();
    		for (Field field : fields) {
    			System.out.println(field + ", 字段值 = " + field.get(a1));
    			// 注意:私有变量值,无法通过field.get(a1)进行获取值
    			// 通过反射类中的字段name,修改name的值(注意,原值在类中name="Dog")
    			// 如果,字段名称等于"name",且字段类型为String,我们就修改字段的值,也就是类中变量name的值
    			if (field.getName() == "name" && field.getType().equals(String.class)) {
    				String name_new = (String) field.get(a1);// 记得转换一下类型
    				name_new = "哈士奇";// 重新给name赋值
    				field.set(a1, name_new);// 设置当前实例a1的name值,使修改后的值生效
    			}
    		}
    
    		System.out.println("利用反射出的字段,修改字段值,修改后的name = " + a1.name);
    		System.out.println("D--获取本类中的所有的方法--------------------");
    
    		// 7、获取本类中所有的方法 包括public、private和protected,不包括父类中申明的方法
    		Method[] methods = c1.getDeclaredMethods();
    		for (Method m : methods) {
    			System.out.println(m);// 我们在类Animal中只定义了一个public方法,sayName
    		}
    
    		System.out.println("E--获取本类中的所有的公有方法,包括父类中和实现接口中的所有public方法-----------");
    
    		// 8、获取类中所有公有方法,包括父类中的和实现接口中的所有public 方法
    		methods = c1.getMethods();
    		for (Method m : methods) {
    			System.out.println(m);// 我们在类Animal中只定义了一个public方法,sayName
    		}
    
    		System.out.println("F--根据方法名称和参数类型获取指定方法,并唤起方法:指定所属对象a1,并给对应参数赋值-----------");
    
    		// 9、唤起Method方法(执行) getMethod:第一个参数是方法名,后面跟方法参数的类
    		Method sayName = c1.getMethod("sayName", String.class);
    		System.out.println(sayName.invoke(a1, "Tom"));
    
    	}
    
    }
    

     


    我们看下对应的执行结果:

     

     

     


     

    如果,你对上述执行的结果,一次性接收不了的话,建议将上述测试demo自己亲自敲一遍,先别急着一次性敲完,一点点来,按照序号来,你会发现,反射的机制,无非就是先加载对应字节码中的类,然后,根据加载类的信息,一点点的去解剖其中的内容,不管你是public的还是private的,亦或是本类的还是来自原继承关系或者实现接口中的方法,我们java的反射技术 reflect,均可以将其从字节码中拉回到现实,不仅可以得到字段的名字,我们还可以获得字段的值和修改字段的值,不仅可以得到方法的申明我们还可以拿到方法的定义和唤起方法(执行方法),当然,你会有一个这样的疑惑

     

    为什么new一个对象那么简单,非要用反射技术中的newInstance?

    为什么,我可以直接对象a1. 变量访问变量,却非要用反射那么费劲的获得name字段呢?

    为什么,我几行代码就能搞定的事情,非要用反射呢?

     

     

     

     


     

     

    回到最开始我们讲的地方:

     

     


     

    ok,解密答案之前,我们先来思考一个问题?

     

    假设我们定义了很多类,有Animal、Person、Car..... ,如果我想要一个Animal实例,那我就new Animal(),如果另一个人想要一个Person实例,那么他需要new Person(),当然,另一个说,我只要一个Car实例,于是它要new Car()......这样一来就导致,每个用户new的对象需求不相同,因此他们只能修改源代码,并重新编译才能生效。这种将new的对象写死在代码里的方法非常不灵活,因此,为了避免这种情况的方法,Java提供了反射机制,典型的应用如下:

     

     

     


     

    我们知道Spring的IOC吧,即“控制反转”(通过第三方配置文件实现对 对象的控制)。简单说是将我们设计好的对象交给容器控制,而不是直接交给程序内部进行对象的控制。

     

    比如,在Spring中,我们经常看到:

     

     


     

    针对上述的配置,我们Spring是怎么帮助我们实例化对象,并放到容器中去了呢? 没错,就是通过反射!!!!

     

    我们看下,下面的伪代码实现过程:

     

     

    //解析<bean .../>元素的id属性得到该字符串值为"sqlSessionFactory" 
    	    String idStr = "sqlSessionFactory";  
    	    //解析<bean .../>元素的class属性得到该字符串值为"org.mybatis.spring.SqlSessionFactoryBean"  
    	    String classStr = "org.mybatis.spring.SqlSessionFactoryBean";  
    	    //利用反射知识,通过classStr获取Class类对象  
    	    Class cls = Class.forName(classStr);  
    	    //实例化对象  
    	    Object obj = cls.newInstance();  
    	    //container表示Spring容器  
    	    container.put(idStr, obj);  
    		
    	    //当一个类里面需要用另一类的对象时,我们继续下面的操作
    	    
    	    //解析<property .../>元素的name属性得到该字符串值为“dataSource”  
    	    String nameStr = "dataSource";  
    	    //解析<property .../>元素的ref属性得到该字符串值为“dataSource”  
    	    String refStr = "dataSource";  
    	    //生成将要调用setter方法名  
    	    String setterName = "set" + nameStr.substring(0, 1).toUpperCase()  
    	            + nameStr.substring(1);  
    	    //获取spring容器中名为refStr的Bean,该Bean将会作为传入参数  
    	    Object paramBean = container.get(refStr);  
    	    //获取setter方法的Method类,此处的cls是刚才反射代码得到的Class对象  
    	    Method setter = cls.getMethod(setterName, paramBean.getClass());  
    	    //调用invoke()方法,此处的obj是刚才反射代码得到的Object对象  
    	    setter.invoke(obj, paramBean);  
    		

     


     

     

    是不是很熟悉,虽然是伪代码,但是和我们本篇讲的反射机制的使用是相同的,现在知道我们的反射机制用在哪了吧,没错就是我们经常提到的Java web框架中,里面就用到了反射机制,只要在代码或配置文件中看到类的完全限定名(包名+类名),其底层原理基本上使用的就是Java的反射机制

     

     

    因此,如果你不做框架的话,基本上是用不到反射机制的,我们大多时候是使用框架的一方,而反射机制都已经在底层实现过了,因此,我们不必担心,我们会写那么复杂的代码。但是,我们必须要理解这种机制的存在!

     

     

     

     

     

     

     

     

    展开全文
  • java反射机制原理1

    2009-05-14 10:46:01
    java反射机制原理1java反射机制原理1java反射机制原理1java反射机制原理1
  • java反射机制原理和反射机制总结!!! java反射机制原理和反射机制总结!!!
  • java反射机制原理

    2018-03-19 11:45:45
    什么是java的反射:1....反射的作用:java程序可以加载一个运行时才得知名称的class,通过class的全限定名,利用java反射机制就可以获取该类的全部信息,可以动态的创建对象和编译。三、反射的原理JAVA语言编译...

    什么是java的反射:

    1.在运行状态中,对于任何一个类,都能够知道这个类的所有方法和属性。

    2.对任意一个对象都能调用它的任何方法和属性。

    这种动态获取信息和动态调用一个对象的方法和属性的机制就是java反射。


    反射的作用:java程序可以加载一个运行时才得知名称的class,通过class的全限定名,利用java反射机制就可以获取该类的全部信息,可以动态的创建对象和编译。


    三、反射的原理

    JAVA语言编译之后会生成一个.class文件,反射就是通过字节码文件找到某一个类、类中的方法以及属性等。

    反射的实现主要借助以下四个类:

    Class:类的对象

    Constructor:类的构造方法

    Field:类中的属性对象

    Method:类中的方法对象


    1、获取类对象:

    通过类名获取Class对象,Class<T> c = Class.forName("类的完全路径");

    通过Class对象获取具体的类对象:Object o = (Object) c.newInstance();

    也可以通过构造函数来实例化该类:

    Constructor<?> con = c.getConstructor(String.class,int.class);
     DemoTest dt = (DemoTest)con.newInstance("xiaoming",12);
    
    


    四、代码演示

    复制代码
     1 package reflection;
     2 
     3 import java.io.Serializable;
     4 
     5 public class DemoTest implements Serializable
     6 {
     7     /**
     8      * 注释内容
     9      */
    10     private static final long serialVersionUID = 1L;
    11 
    12     public String name;
    13     public int age;
    14     
    15     public DemoTest()
    16     {
    17     }
    18 
    19     public DemoTest(String name, int age)
    20     {
    21         this.name = name;
    22         this.age = age;
    23     }
    24     
    25     public void sayHello(String param)
    26     {
    27         System.out.println("hello " + param);
    28     }
    29 
    30     public String getName()
    31     {
    32         return name;
    33     }
    34 
    35     public void setName(String name)
    36     {
    37         this.name = name;
    38     }
    39 
    40     public int getAge()
    41     {
    42         return age;
    43     }
    44 
    45     public void setAge(int age)
    46     {
    47         this.age = age;
    48     }
    49 }
    复制代码

    测试类:

    复制代码
     1 package reflection;
     2 
     3 import java.lang.reflect.Constructor;
     4 import java.lang.reflect.Field;
     5 import java.lang.reflect.Method;
     6 
     7 public class Test
     8 {
     9     public static void main(String[] args) throws Exception
    10     {
    11         //获取类DemoTest的Class对象
    12         Class<?> c = Class.forName("reflection.DemoTest");
    13         //打印该Class对象对表示的类的名称
    14         System.out.println(c.getName());
    15         //获取该类的实例
    16         System.out.println(c.newInstance());
    17         
    18         System.out.println("-------------------------------------------");
    19         //获取该类实现的接口
    20         Class<?>[] interfaces = c.getInterfaces();
    21         System.out.println(interfaces[0].getName());
    22         
    23         System.out.println("-------------------------------------------");
    24         //获取有参构造函数
    25         Constructor<?> con = c.getConstructor(String.class,int.class);
    26         DemoTest dt = (DemoTest)con.newInstance("xiaoming",12);
    27         System.out.println(dt.getAge());
    28         
    29         System.out.println("-------------------------------------------");
    30         //获取类的成员变量
    31         Field f2 = c.getField("age");
    32         System.out.println(f2);
    33         //获取指定对象上该字段表示的值
    34         System.out.println(f2.get(dt));
    35         
    36         System.out.println("-------------------------------------------");
    37         //获取指定的方法
    38         Method m = c.getMethod("sayHello", String.class);
    39         //反射调用方法,非常重要
    40         m.invoke(dt, "hangzhou");
    41     }
    42 }
    复制代码

    测试结果:

    复制代码
    reflection.DemoTest
    reflection.DemoTest@15db9742
    -------------------------------------------
    java.io.Serializable
    -------------------------------------------
    12
    -------------------------------------------
    public int reflection.DemoTest.age
    12
    -------------------------------------------
    hello hangzhou

    展开全文
  • java反射原理,反射机制原理,以及java反射机制实现实例!希望能给大家一点帮助!
  • java反射机制,详细解释了,java反射机制原理
  • JAVA反射机制,反射机制常用方法,反射机制学习
  • 主要介绍了Java 反射机制原理与用法,结合实例形式详细分析了Java反射机制的相关概念、原理、基本使用方法及操作注意事项,需要的朋友可以参考下
  • Java中的反射机制,被称为Reflection。(大家看到这个单词,第一个想法应该就是去开发文档中搜一下了。)它允许运行中的Java程序对自身进行检查,并能直接操作程序的内部属性或方法。Reflection机制允许程序在正在...
  • 主要介绍了Java反射机制概念、原理与用法,较为详细的分析了java反射机制的概念、原理,并结合实例形式总结分析了java反射机制的具体使用方法与相关注意事项,需要的朋友可以参考下
  • java反射机制原理及在Android下的简单应用
  • java反射机制原理

    2007-11-15 08:24:55
    java反射机制原理
  • 浅谈Java反射实现原理

    千次阅读 2017-04-30 10:54:54
    Java反射实现原理
  • Java反射机制-PDF文档,详述了反射机制的原理和使用方法,通俗易懂。
  • 这是『Java学习指南系列』的第18篇教程 ,是Java开发的高级课程,介绍反射机制、注解和框架设计的一般性原理。 二、主要内容  本篇包含以下内容: * 使用反射机制,读取Class中的字段信息 * 使用反射机制,对...
  • Java反射机制原理及作用

    千次阅读 2017-04-19 17:44:58
    灵活掌握Java反射机制,对大家以后学习框架技术有很大的帮助。 那么什么是Java的反射呢?  大家都知道,要让Java程序能够运行,那么就得让Java类要被Java虚拟机加载。Java类如果不被Java虚拟机加载,是不能正常...
  • java反射机制实现原理 (一)

    万次阅读 2011-05-12 13:39:00
    http://zhidao.baidu.com/question/151090808.html<br />    反射机制:... Java反射机制实现要借助于4个类:class,Constructor,Field,Method;其中class代表的时类对 象,Constructor
  • 一、什么是Java反射机制 当程序运行时,允许改变程序结构或变量类型,这种语言称为动态语言。我们认为java并不是动态语言,但是它却有一个非常突出的动态相关机制,俗称:反射。 IT行业里这么说,没有反射也就没有...
  • java反射机制原理

    2013-04-19 21:00:26
    java反射机制原理 这种原理行的概述,讲解详细!
  • Java反射机制详解

    2020-09-03 01:54:51
    主要介绍了Java反射机制,首先简单介绍了反射机制的预备知识,进一步分析了Java反射机制原理实现技巧与应用方法,需要的朋友可以参考下
  • java反射机制

    2017-10-19 16:52:01
    Java反射机制API,介绍如何使用Java反射机制,以及反射机制的原理
  • Java 反射机制是在运行状态中,对于任意一个类,都能够获得这个类的所有属性和方法,对于任意一个对象都能够调用它的任意一个属性和方法。这种在运行时动态的获取信息以及动态调用对象的方法的功能称为 Java反射...
  • 深入分析 Java 方法反射实现原理

    千次阅读 2017-07-16 19:51:58
    博主说:Java 反射机制是在运行状态中,对于任意一个类,...在本文中,占小狼分析了 Java 反射机制实现原理(源码),感兴趣的同学可以通过本文花上几分钟了解了解。 正文方法反射实例public class ReflectCase { pu

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 74,775
精华内容 29,910
关键字:

java反射机制实现原理

java 订阅