反射

来源:互联网 发布:咸鱼质量问题淘宝介入 编辑:程序博客网 时间:2024/06/06 20:13

反射是一种功能强大且复杂的机制,反射机制可以用来:

  • 在运行中分析类的能力
  • 在运行中查看对象
  • 实现通用的数组操作代码
  • 利用Method对象

Class类

在程序运行期间,java运行时系统始终为所有对象维护一个被称为运行时的类型标识。这个信息跟踪着每个对象所属的类。虚拟机利用运行时类型信息选择相应的方法执行。可以通过专门的java类访问这些信息,保存这些信息的类被称为Class。
关于Class类的详尽描述:https://docs.oracle.com/javase/6/docs/api/java/lang/Class.html

1、Object类的getClass()方法将会返回一个Class类型的实例

  Employee e = new Employee();        Class c1 = e.getClass();        //输出结果:class com.hhr.reflect.Employee        System.out.println(c1);

如同一个Employee对象表示一个特定的雇员属性一样,一个Class对象将表示一个特定类的属性。
最常用的一个Class方法是getName,将返回类的名字:

 Employee employee = new Employee("Joy");        String name = employee.getClass().getName();        //输出结果:com.hhr.reflect.Employee        System.out.println(name);

2、调用静态方法forName获得类名对应的Class对象

try {            String className = "java.util.Date";            Class c1 = Class.forName(className);            //输出结果:class java.util.Date            System.out.println(c1);        } catch (ClassNotFoundException e) {            e.printStackTrace();        }

此方法只有在className是类名或者接口名时才能够执行。否则会抛出ClassNotFoundException。无论何时使用这个方法,都应该提供一个异常处理器。
3、T.class (T为任意的java类型)

  Class c1 = int.class;  Class c2 = Date.class;  Class c3 = Double[].class;

请注意,Class对象实际上表示的是一种类型,而这个类型未必一定是一种类。int不是类,但int.class是一个Class类型的对象。
鉴于历史原因,getName方法应用于数组类型时会返回一个很奇怪的名字,如Double[].class会返回:

class [Ljava.lang.Double;

虚拟机为每个类型管理一个Class对象,因此可以用==运算符实现两个类对象比较的操作。

if (e.getClass()==Employee.class){

还有一个很有用的方法,newInstance(),可以用来快速的创建一个类的实例。

e.getClass().newInstance()

newInstance()调用默认的构造器初始化新创建的对象,如果没有默认的构造器,将会抛出异常。

利用反射分析类的能力

在java.lang.reflect包中有三个类:Field、Method、Constructor,分别用于描述类的域、方法、构造器。
具体描述:
https://docs.oracle.com/javase/6/docs/api/java/lang/reflect/Field.html
https://docs.oracle.com/javase/6/docs/api/java/lang/reflect/Method.html
https://docs.oracle.com/javase/6/docs/api/java/lang/reflect/Constructor.html
这三个类都有一个getName方法,用来返回项目的名称。
这三个类还有一个getModifiers()方法,将返回一个整型数值,描述public和static这样的修饰符的使用情况。
另外还可以利用java.lang.reflect包中的Modifier类的静态方法分析getModifiers()返回的整型数值。利用 Modifier.toString将修饰符打印出来。
Class类中的getFields、getMethods合getConstructors方法将分别返回类提供的public域、方法和构造器数组,其中包括超类的公有成员。
Class类的getDeclaredFields、getDeclaredMethods和getDeclaredConstructors方法将分别返回泪中声明的全部域、方法和构造器,其中包括私有和受保护的成员,但不包括超类的成员。
程序示例:程序清单-打印一个类的全部信息

在运行时使用反射分析对象

现在已经知道任意对象的数据域名称和类型:

  • 获得对应的Class对象
  • 通过Class对象调用etDeclaredFields()

查看对象域的关键方法是Field类中的get方法。

 Employee employee = new Employee("Harry"); Class cl =  employee.getClass(); Field field = cl.getDeclaredField("name"); Object v = field.get(employee);

实际上,上面这段代码会抛出一个IllegalAccessException,因为name是一个私有域。只有利用get方法才能得到可访问域的值。除非拥有访问权限,否则Java安全机制只允许查看任意对象有那些域而不允许读取它们的值。
反射机制的默认行为受限于Java的访问控制。然而,如果一个Java程序没有受到安全管理器的控制,就可以覆盖访问控制了。为此,可以调用Field、Constructor、Method对象的setAccessible方法。

field.setAccessible(true);

程序清单-一个可供任意类使用的toString方法
程序清单-利用反射扩展任意类型的数组

调用任意方法

反射机制允许你调用任意方法。
Method类中有一个invoke方法,它允许调用包装在当前Method对象中的方法。

public Object invoke(Object obj, Object... args)

第一个参数是隐式参数,其余的对象提供了显式参数。对于静态方法,第一个参数可以忽略,即可以将它设置为null。

 String m = (String) method.invoke(a);

如果返回的是基本类型,invoke方法会返回其包装器类型。
由于invoke的参数和返回值必须是Object类型,必须通过多次的类型转换。这样会使编译器错过检查代码的机会。不仅如此,使用反射获得方法指针的代码要比仅仅直接调用方法明显慢一些。
建议不要使用Method对象的回调功能。使用接口进行回调会使得代码执行速度更快

阅读全文
'); })();
0 0
原创粉丝点击
热门IT博客
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 香辣小鱼仔 小鱼仔代理 麻辣小鱼仔的做法 小鱼仔做法 小鱼仔包装袋 小鱼仔是什么鱼 小鱼子 小鱼钩 小魚儿 小鱼儿与花无缺小仙女 小鱼儿阅读 dj小鱼儿 9911小鱼儿 小鱼儿4849 小鱼儿图片 小鱼儿2 小鱼儿幺机2站 99288小鱼儿挂牌 ok12399小鱼儿 99288小鱼儿 小鱼儿玄 小鱼儿安吉 花无缺小鱼儿 大侠小鱼儿 花无缺和小鱼儿 小鱼儿国际象棋 小鱼儿儿歌 小鱼儿网址 小仙女小鱼儿 小鱼儿出装 小鱼儿水中游 小鱼儿576363 小鱼儿668665 43361小鱼儿 小鱼儿讨论 www46008 小雨儿 99288 www.46008 9911 58123