zoukankan      html  css  js  c++  java
  • 反射

    反射的作用

      在运行时,动态发现对象或类的真实信息,拥有的构造方法列表,普通方法列表,类属性,注解等相关信息来构造类的对象,调用相应的一些方法。为了解决这个问题,我们有两种做法:

    1. 第一种是假设在编译和运行时都完全知道类型的具体信息,这种情况下,我们可以直接先使用instanceof运算符进行判断,再利用强制类型转换成其运行时类型的变量即可。
    2. 第二种是编译时根本无法预知该对象和类可能属于那些类,程序只依靠运行时信息来发现该对象和类的真实信息,这就必须使用反射。  

    获得Class对象 

      每个类被加载之后,系统就会为该类生成一个对应的Class对象,通过该Class对象就可以访问到JVM中的这个类。Java程序中获得Class对象通常有如下三种方式:

    1. 使用Class类的forName()静态方法。该方法需要传入字符串参数,该字符串参数的值是某个类的全限定类名。(添加完整包名)。
            try {
                Class clazz2 = Class.forName("java.lang.String");
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }

      2.调用某个类的class属性来获取该类对应的Class对象。例如Person.class将会返回Person类对应的Class对象。

    Class clazz1 = String.class;
    

      3.调用某个对象的getClass()方法,该方法是java.lang.Object类中的一个方法,该方法将会返回该对象所属类对应的Class对象。 

    String str = new String();
    Class clazz3 = str.getClass();
    

    从Class中获取信息

    1.反射得到包含的构造器

     

      2.反射得到包含的方法列表:

      3.反射得到包含的属性列表:

      4.反射得到包含的注解信息:

    反射还可以得到包名等。

     使用反射生成并操作对象

      Class对象可以获得该类里包括的方法(由Method对象表示)、构造器(由Constructor对象表示)、Field(由Field对象表示),这三个类都定义在java.lang.reflect包下,并实现了java.lang.reflect.Member接口。程序可以通过Method对象来执行对应的方法,通过COnstructor对象来调用对应的构造器创建对象,能通过Field对象直接访问并修改对象的属性值。

    通过反射来生成对象如下两种方式:

    1. 使用Class对象的newInstance()方法来创建Class对象对应类的实例,这种方式要求该Class对象的对应类有默认构造器,而执行newInstance()方法时实际上是利用默认构造器来创建该类的实例。
    // 使用无参构造器创建对象 可能会抛出异常
    Class clazz4 = String.class;
    clazz4.newInstance();
    

      2.先使用Class对象获取指定的Constructor对象,再调用Constructor对象的newInsance()方法来创建该Class对象对应类的实例,这种方式可以指定选择使用某个构造器来创建实例。

    //使用指定的构造方法构造对象
    Constructor<String> constructor = clazz4.getConstructor(String.class);
    String str2 = constructor.newInstance("Hello World");
    

    通过反射来调用方法:

      当获得某个类对应的Class对象后,就可以通过该Class对象的getMethods()方法或者getMethod()方法来获取全部方法或指定方法——这两个方法的返回值是Method对象数组,或者Method对象。每个Method对象对应一个方法,获得Method对象后,程序就可以通过该Method来调用对应的方法。在Method里包含以讹invoke方法,该方法的签名如下:

    • Object invoke(Object obj ,Object... args) :该方法中的obj是执行该方法的主调,后面的args是执行该方法时传入该方法的实参。

      代码:

    Class clazz1 = String.class;
    Method method = clazz1.getMethod("substring", int.class);
    String str3 = "ABCDEFG";
    String str6 = (String) method.invoke(str3, 3);
    System.out.println(str6);
    

      当通过Method的invoke方法来调用对应的方法时,Java会要求程序必须有调用该方法的权限,如果程序确实需要调用某个对象的private方法,可以先调用Method对象的setAccessible(boolean flag):将Method对象的accessible标志设置为指示的布尔值。值为true则表示该Method在使用时应该取消Java语言访问权限检查,值为false则反之。

    通过反射访问属性值

    通过Class对象的getFields()或getField()方法可以获取该类所包括的全部Field(属性)或指定Field。Field提供了如下两组方法来访问属性:

    1. getXxx(Object obj) : 获取obj对象该Field的属性值。此处的Xxx对应8个基本类型,如果该属性的类型是引用类型则取消get后面的Xxxx,直接使用set(Object obj)
    2. setXxx(Object obj ,Xxxx val):将obj对象的该Field设置为val值。此处的Xxx对应8个基本类型,如果该属性的类型是引用类型则取消set后面的Xxx。
    class Person
    {
    	private String name;
    	private int age;
    	public String toString()
    	{
    		return "Person [ name:" + name + 
    			" , age:" + age + " ]";
    	}
    }
    public class FieldTest
    {
    	public static void main(String[] args) 
    		throws Exception
    	{
    		//创建一个Person对象
    		Person p = new Person();
    		//获取Person类对应的Class对象
    		Class<Person> personClazz = Person.class;
    		//获取Person类名为name的属性
    		//使用getDeclaredField,表明可获取各种访问控制符的field
    		Field nameField = personClazz.getDeclaredField("name");
    		//设置通过反射访问该Field时取消访问权限检查
    		nameField.setAccessible(true);
    		//调用set方法为p对象的指定Field设置值
    		nameField.set(p , "Yeeku.H.Lee");
    		//获取Person类名为age的属性
    		Field ageField = personClazz.getDeclaredField("age");
    		//设置通过反射访问该Field时取消访问权限检查
    		ageField.setAccessible(true);
    		//调用setInt方法为p对象的指定Field设置值
    		ageField.setInt(p , 30);
    		System.out.println(p);
    	}
    }
    

     反射操作数组

    在java.lang.reflect包下还提供了一个Array类,Array对象可以代表所有的数组。程序可以通过使用Array来动态创建数组,和操作数组元素等。

    public class ArrayTest1 
    {
        public static void main(String args[])
        {
            try
            {
                //创建一个元素类型为String ,长度为10的数组
                Object arr = Array.newInstance(String.class, 10);
                //依次为arr数组中index为5、6的元素赋值
                Array.set(arr, 5, "Struts2权威指南");
                Array.set(arr, 6, "ROR敏捷开发最佳实践");
                //依次取出arr数组中index为5、6的元素的值
                Object book1 = Array.get(arr , 5);
                Object book2 = Array.get(arr , 6);
                //输出arr数组中index为5、6的元素
                System.out.println(book1);
                System.out.println(book2);
            }
            catch (Throwable e)
            {
                System.err.println(e);
            }
        }
    }
    加油
  • 相关阅读:
    Asp.net的一些编码问题
    计算ScriptResource.axd的d参数
    关于控件Visible属性的说明
    多分类产品查询
    广告位管理系统跨域广告加载问题
    广告位管理系统使用说明
    Repeater控件备忘
    SubSonic中的字段付值MakeOld & Update
    关于Left join 到 Inner join 的提升MSSQL自动转换
    函数(方法)级的授权
  • 原文地址:https://www.cnblogs.com/boothsun/p/4861359.html
Copyright © 2011-2022 走看看