zoukankan      html  css  js  c++  java
  • JavaSE-22 反射

    学习要点

    • 反射概念
    • 反射的应用

    反射概述

    1  反射机制

    定义

    Java反射机制是指在程序在运行状态中,动态获取信息以及动态调用对象方法的功能。

    Java反射的动态性质:运行时生成对象实例、运行期间调用方法、运行时更改属性。

    Java程序执行过程

    反射执行过程

     

    1)  Java反射机制是在编译时并不确定哪个类被加载了,而是在程序运行的时候才加载、探知、使用。

    2)  Java反射机制能够知道类的基本结构,这种对Java类结构的探知能力,称为Java类的“自审”。例如开发环境eclipse或者myeclipse中的代码自动提示功能,就是利用了Java的反射机制,对所创建对象的探知和自审。

    3)  通过Java反射,可以实现以下功能:

    • 在运行时判断任意一个对象所属的类。
    • 在运行时构造任意一个类的对象。
    • 在运行时判断任意一个类所具有的方法和属性。
    • 在运行时调用任意一个对象的方法。

      

    2  Java反射常用API

    ava反射常用核心类位于java.lang.reflect包,常用类:

    1)  Class类—可获取类和类的成员信息

    2)  Field类—可访问类的属性 

    3)  Method类—可调用类的方法

    4)  Constructor类—可调用类的构造方法

    使用反射的基本步骤

    1)  导入java.lang.reflect.*

    2)  获得需要操作的类的Java.lang.Class对象

    3)  调用Class的方法获取Field、Method等对象

    4)  使用反射API进行操作 (设置属性﹑调用方法)

     

    反射的应用

    1  获取类的信息

    Java类加载机制

    Class文件由类装载器装载后,在JVM中将形成一份描述Class结构的元信息对象,通过该元信息对象可以获知Class的结构信息:如构造函数,属性和方法等,Java允许用户借由这个Class相关的元信息对象间接调用Class对象的功能。

    虚拟机把描述类的数据从class文件加载到内存,并对数据进行校验,转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型,这就是虚拟机的类加载机制。

    获取Class对象

    1)  调用对象的getClass( )方法

    定义学生信息类

    /** 学生信息类 */
    
    public class Student {
    
       private int sid;// 学号
    
       private String sname;// 姓名
    
       private char sgender;// 性别
    
       private int sage;// 年龄
    
       //构造函数(略)
    
       //属性封装(略)
    
    }

    定义测试类获得学生信息类的Class对象

    Student student=new Student();
    
    Class clazz=student.getClass();
    

      

    2)  调用类的Class属性(推荐使用:类型安全、性能高)

    Class clazz = Student.class;
    

    3)        使用Class类的forName()静态方法

    Class clazz = Class.forName("com.etc.demo.Student");// 参数是类全名
    

      

    从Class对象获取信息

    1)  访问Class对象对应类所包含的构造方法

    方法

    说明

    Constructor getConstructor(Class[] params)

    返回指定参数的public构造方法

    Constructor[] getConstructors()

    返回所有public构造方法

    Constructor getDeclaredConstructor(Class[] params)

    返回指定参数的构造方法,与访问级别无关

    Constructor[] getDeclaredConstructors()

    返回所有构造方法,与访问级别无关

    示例代码

    Constructor constructors[] =
    
    clazz.getDeclaredConstructors();//返回所有构造方法
    
    Constructor constructors[] =
    
    clazz.getConstructors();//返回所有public构造方法
    
    //返回指定参数的构造方法,与访问修饰符无关
    
    Constructor con = clazz.getDeclaredConstructor
    
    (new Class[]{int.class,String.class,char.class,int.class});
    
    //简要输出构造方法信息
    
    System.out.println(con.toString());
    

      

     

    2)  访问Class对象对应类所包含的方法

    方法

    说明

    Method getMethod(String name,Class[] params)

    返回方法名为name的指定参数列表的public方法

    Method[] getMethods()

    返回所有public方法

    Method getDeclaredMethod(String name,

    Class[] params)

    返回方法名为name的指定参数列表的所有方法

    Method[] getDeclaredMethods()

    返回所有方法

    3)  访问Class对象对应类所包含的属性

    方法

    说明

    Field getField(String name)

    返回public指定名称为name的属性

    Field getFields()

    返回全部public属性

    Field getDeclaredField(String name)

    返回指定名称属性

    Field[] getDeclaredFields()

    返回全部属性

    4)  访问Class对象对应类所包含的注解

    方法

    说明

    <A extends Annotation>A getAnnotation

    (Class<A>  annotationClass)

    返回该Class对象所表示类上指定类型的注释,若没有,则返回null

    Annotation[] getAnnotations()

    返回所有注释

    Annotation[] getDeclaredAnnotations()

    返回直接存在于此元素上的所有注释

    5)  访问Class对象对应类的其他信息

    方法

    说明

    Class[] getDeclaredClasses()

    返回Class对象对应类的全部内容类

    Class[] getDeclaringClass()

    返回Class对象对应类的全部外部类

    Class[] getInterfaces()

    返回Class对象对应类全部实现的接口

    int getModifiers()

    返回此类或接口的所有修饰符。使用Modifer工具类方法解码返回值获得访问修饰符

    Package getPackage()

    获得此类的包

    String getName()

    返回类的名称

    String getSimpleName()

    返回类的简称

    Class getSuperclass()

    返回基类Class对象

    示例代码

         

     Class clazz = Student.class;
    
            System.out.println("------类的字段------------");
    
            Field fields[] = clazz.getDeclaredFields();
    
            for (Field field : fields)
    
                System.out.println(field.getName() + " " + field.getType());
    
            System.out.println("-------类的方法-----------");
    
            Method methods[] = clazz.getDeclaredMethods();
    
            for (Method method : methods)
    
                System.out.println(method.getName());
    
            System.out.println("-------类的构造方法-----------");
    
            Constructor constructors[] = clazz.getDeclaredConstructors();
    
            for (Constructor constructor : constructors) {
    
                System.out.println(constructor);
    
            }
    
            System.out.println("--------类所在包、完整名称、父类----------");
    
            System.out.println(clazz.getPackage().getName());
    
            System.out.println(clazz.getName());
    
    System.out.println(clazz.getSuperclass());
    

      

    2  创建对象

    通过反射创建对象有两种形式:

    • 使用Class对象的newInstance()方法创建对象
    • 使用Constructor对象创建对象

    使用newInstance()创建对象

    要求Class对象对应的类有默认构造方法。

    示例代码

     

    Class clazz=Student.class;
    
    Student student=(Student)clazz.newInstance();
    
    student.setSname("张三");
    
    student.setSage(21);
    
    student.sayHello();
    

      

    使用Constructor对象指定构造方法创建对象

    示例代码

    Class clazz=Student.class;
    
    Constructor constructor=
    
    clazz.getConstructor(int.class,String.class,char.class,int.class);
    
    Student student=(Student) constructor.newInstance(1001,"张三",'男',22);
    
    student.sayHello();
    

       

    3  访问类的属性

    使用Field对象可以获取对象的属性。通过Field对象可以对属性进行取值或赋值操作。主要方法如下:

    方法

    说明

    Xxx getXxx(Object obj)

    Xxx对应Java的8个基本数据类型,如int。obj为该属性所在的对象。

    Object get(Object obj)

    获得引用类型属性值。

    void setXxx(Object obj,Xxx val)

    将obj对象该属性设置为val值。

    void set(Object obj,objcet val)

    将obj对象该属性设置为val值。针对引用类型。

    void setAccessible(bool flag)

    对获取到的属性设置访问权限。参数为true,可以对私有属性取值和赋值。

    示例代码

    /** 人类 */
    
    class Person {
    
       private String name;// 姓名
    
       private int age;// 年龄
    
       /** 重写toString()方法 */
    
       public String toString() {
    
           return "my name is" + name + ",age is" + age;
    
       }
    
    }
    
     
    
    /** 测试代码 */
    
        Person p = new Person();// 创建Person对象
    
        Class clazz = Person.class;// 获取Person对应的Class对象
    
        // 获取Person类的name属性,使用getDeclaredField()方法获取各种访问级别的属性
    
        Field nameField = clazz.getDeclaredField("name");
    
        // 设置通过反射访问该Field时取消权限检查
    
        nameField.setAccessible(true);
    
        // 使用set方法为p对象指定Field设置值
    
        nameField.set(p, "andy");
    
        //同理设置age属性
    
        Field ageField=clazz.getDeclaredField("age");
    
        ageField.setAccessible(true);
    
        ageField.setInt(p,21);
    
        //输出结果
    
    System.out.println(p.toString());
    

    4  访问类的方法

    使用Method对象可以调用对象的方法。在Method类中包含一个invoke()方法,方法的定义如下:

    Object invoke(Object obj,Object… args);

    obj:执行该方法的对象

    args:执行该方法时传入该方法的参数列表

    示例代码

    /** 计算器类 */
    
    public class Calculator {
    
    /** 加法 */
    
    public int add(int a, int b) {
    
         return a + b;
    
    }
    
     
    
    /** 减法 */
    
    private int sub(int a, int b) {
    
         return a - b;
    
    }
    
    }
    
     
    
           /** 测试代码 */
    
            // 获取Calculator对应的Class对象
    
            Class clazz = Calculator.class;
    
            // 创建Calculator对象
    
            Calculator calculator = new Calculator();
    
            // add方法调用
    
            Method methodAdd = clazz.getMethod("add", int.class, int.class);
    
            int result1 = (int) methodAdd.invoke(calculator, 10, 12);
    
            System.out.println("10+12=" + result1);
    
            // sub方法的调用
    
            Method methodSub = clazz.getMethod("sub", int.class, int.class);// 报错如何处理?
    
            int result2 = (int) methodSub.invoke(calculator, 13, 4);
    
       System.out.println("13-4=" + result2);
    

      

    注意:invoke()方法调用对应的方法时,java会检查权限。

    解决方案:如果是调用private方法,是用setAccessible()方法设置允许调用。

       

    // sub方法的调用
    
    Method methodSub = clazz.getDeclaredMethod("sub", int.class, int.class);
    
    methodSub.setAccessible(true);
    
    int result2 = (int) methodSub.invoke(calculator, 13, 4);
    
    System.out.println("13-4=" + result2);
    

      

    5  Array类

    在java.lang.reflect包下提供了一个Array类。

    Java反射技术除了可以在运行时动态地决定要创建什么类型的对象,访问哪些成员变量,方法,还可以动态地创建各种不同类型,不同维度的数组。

    动态创建数组的步骤如下:

    1)        创建Class对象,通过class属性、forName(String)方法或者getClass()方法指定数组元素的类型。

    2)        调用Array.newInstance(Class, length_of_array)动态创建数组。

    操作动态数组常用方法

    1)        访问动态数组元素的方法和通常有所不同,它的格式如下所示,注意该方法返回的是一个Object对象

        Array.get(arrayObject, index)

    2)        为动态数组元素赋值的方法也和通常的不同,它的格式如下所示, 注意最后的一个参数必须是Object类型

          Array.set(arrayObject, index, object)

    示例代码:

    import java.lang.reflect.Array;
    
    public class Test {
    
       public static void main(String[] args) throws Exception {
    
           // 创建一个元素类型为String,长度为10的数组
    
           Object arr = Array.newInstance(String.class, 10);
    
           // 依次为数组中index为7、8的元素赋值
    
           Array.set(arr, 7, "China");
    
           Array.set(arr, 8, "German");
    
           // 依次取出数组中index为7、8的元素的值
    
           Object obj1 = Array.get(arr, 7);
    
           Object obj2 = Array.get(arr, 8);
    
    // 输出元素的值
    
           System.out.println(obj1.toString() + "  PK  " + obj2.toString());
    
       }
    
    }
    

    上机练习

    需求说明

    • 使用反射修改和查询Student类的姓名属性(public)和年龄属性(private)。
    • 使用反射动态执行Student类输出信息的方法。


    本博客文章未经许可,禁止转载和商业用途!

    如有疑问,请联系: 2083967667@qq.com


  • 相关阅读:
    wordpress通过$wpdb获取一个分类下所有的文章
    WordPress的摘要显示方式
    WordPress简洁的SEO标题、关键词和描述
    WordPress获取特色图像的链接地址
    WordPress的Bootstrap面包屑导航
    destoon 6.0 手机站支持在所有浏览器访问
    dede织梦5.7的安全防护设置
    WordPress主题制作:基础样式文件
    LInux常用到的命令(面试)
    1030 完美数列 (25分) PAT-B
  • 原文地址:https://www.cnblogs.com/rask/p/8254184.html
Copyright © 2011-2022 走看看