JAVA - 反射

作者: AntiGravity | 来源:发表于2017-10-09 20:35 被阅读0次

一、理解

概念

反射是JAVA的一个机制。

在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。

每个类被加载之后,系统就会为该类生成一个对应的Class对象。通过该Class对象就可以访问到JVM中的这个类。

应用

1. 获取程序在运行时刻的内部结构

这对于程序的检查工具和调试器来说,是非常实用的功能。只需要短短的十几行代码,就可以遍历出来一个Java类的内部结构,包括其中的构造方法、声明的域和定义的方法等。这不得不说是一个很强大的能力。只要有了java.lang.Class类 的对象,就可以通过其中的方法来获取到该类中的构造方法、域和方法。对应的方法分别是getConstructorgetFieldgetMethod。这三个方法还有相应的getDeclaredXXX版本,区别在于getDeclaredXXX版本的方法只会获取该类自身所声明的元素,而不会考虑继承下来的。ConstructorFieldMethod这三个类分别表示类中的构造方法、域和方法。这些类中的方法可以获取到所对应结构的元数据。

2. 在运行时刻对一个Java对象进行操作

这些操作包括动态创建一个Java类的对象,获取某个域的值以及调用某个方法。在Java源代码中编写的对类和对象的操作,都可以在运行时刻通过反射API来实现。

二、使用

取得Class对象

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

  1. 使用 Class 类的forName(String clazzName)静态方法。该方法需要传入字符串参数,该字符串参数的值是某个类的全限定名(必须添加完整包名)。
  2. 调用某个类的class属性来获取该类对应的 Class 对象。
  3. 调用某个对象的getClass()方法。该方法是java.lang.Object类中的一个方法。
//第一种方式 通过Class类的静态方法——forName()来实现
class1 = Class.forName("com.lvr.reflection.Person");
//第二种方式 通过类的class属性
class1 = Person.class;
//第三种方式 通过对象getClass方法
Person person = new Person();
Class<?> class1 = person.getClass();

对于方式一和方式二都是直接根据类来取得该类的 Class 对象,相比之下,方式二有如下的两种优势:

  • 代码更安全。程序在编译阶段就能够检查需要访问的 Class 对象是否存在。
  • 线程性能更好。因为这种方式无须调用方法,所以性能更好。

可以通过类的类类型创建该类的对象实例。

//Class.newInstance();
Foot foot = (Foot) c1.newInstance();

从class中获取信息(常用)

一旦获得了某个类所对应的Class 对象之后,就可以调用 Class 对象的方法来获得该对象的和该类的真实信息了。

1. 获取 Class 对应类的成员变量
Field[] getDeclaredFields(); // 获取 Class 对象对应类的所有属性,与成员变量的访问权限无关。
Field[] getFields(); // 获取 Class 对象对应类的所有 public 属性。
Field getDeclaredField(String name); // 获取 Class 对象对应类的指定名称的属性,与成员变量的访问权限无关。
Field getField(String name); // 获取 Class 对象对应类的指定名称的 public 属性。
2. 获取 Class 对应类的方法
Method[] getDeclaredMethods(); // 获取 Class 对象对应类的所有声明方法,于方法的访问权限无关。
Method[] getMethods(); // 获取 Class 对象对应类的所有 public 方法,包括父类的方法。
Method getMethod(String name, Class<?>...parameterTypes); // 返回此 Class 对象对应类的、带指定形参列表的 public 方法。
Method getDeclaredMethod(String name, Class<?>...parameterTypes); // 返回此 Class 对象对应类的、带指定形参列表的方法,与方法的访问权限无关。
3. 获取 Class 对应类的构造函数
Constructor<?>[] getDeclaredConstructors(); // 获取 Class 对象对应类的所有声明构造函数,于构造函数的访问权限无关。
Constructor<?>[] getConstructors(); // 获取 Class 对象对应类的所有 public 构造函数。
Constructor<T> getDeclaredConstructor(Class<?>...parameterTypes); // 返回此 Class 对象对应类的、带指定形参列表的构造函数,与构造函数的访问权限无关。
Constructor<T> getConstructor(Class<?>...parameterTypes); // 返回此 Class 对象对应类的、带指定形参列表的 public 构造函数。

(不常用)

4. 获取 Class 对应类的 Annotation(注释)
<A extends Annotation>A getAnnotation(Class<A> annotationClass); // 尝试获取该 Class 对对象对应类存在的、指定类型的 Annotation;如果该类型的注解不存在,则返回 null。
<A extends Annotation>A getDeclaredAnnotation(Class<A> annotationClass); // 这是Java8新增的方法,该方法尝试获取直接修饰该 Class 对象对应类、指定类型的Annotation;如果该类型的注解不存在,则返回 null。
Annotation[] getAnnotations(); // 返回修饰该 Class 对象对应类存在的所有Annotation。
Annotation[] getDeclaredAnnotations(); // 返回直接修饰该 Class 对应类的所有Annotation。
<A extends Annotation>A[] getAnnotationsByType(Class<A> annotationClass); // 获取修饰该类的、指定类型的多个Annotation。
<A extends Annotation>A[] getDeclaredAnnotationsByType(Class<A> annotationClass); // 获取直接修饰该类的、指定类型的多个Annotation。
5. 获取 Class 对应类的内部类
Class<?>[] getDeclaredClasses(); // 返回该 Class 对象对应类包含的全部内部类。
6. 获取 Class 对应类的外部类
Class<?> getDeclaringClass(); // 返回该 Class 对象对应类所在的外部类。
7. 获取 Class 对应类所实现的接口
Class<?>[] getInterfaces();
8. 获取 Class 对应类所继承的父类
Class<? super T> getSuperClass();
9. 获取 Class 对应类的修饰符、所在包、类名等基本信息
int getModifiers(); // 返回此类或接口的所有修饰符。修饰符由 public、protected、private、final、static、abstract 等对应的常量组成,返回的整数应使用 Modifier 工具类的方法来解码,才可以获取真实的修饰符。
Package getPackage() // 获取该类的包。
String getName() // 以字符串的形式返回此 Class 对象所表示的类的名称。
String getSimpleName() // 以字符串的形式返回此 Class 对象所表示的类的简称。
10. 判断该类是否为接口、枚举、注解类型等
boolean isAnnotation() // 返此 Class 对象是否是一个注解类型(由@interface定义)。
boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) // 判断此 Class 对象是否使用了Annotation修饰。
boolean isAnonymousClass() // 此 Class 对象是否是一个匿名类。
boolean isArray() //此 Class 对象是否是一个数组。
boolean isEnum() // 此 Class 对象是否是一个枚举(由 enum 关键字定义)。
boolean isInterface() // 此 Class 对象是否是一个接口(由 interface 关键字定义)。
boolean isInstance(Object obj) // 判断 obj 是否是此 Class 对象的实例。该方法完全可以替代 instanceof 操作符。

相关文章

  • 博客地址

    java注解-01、java注解-02、Git面试资源java反射-01、java反射-02、java反射-03为...

  • Java反射机制入门

    Java反射机制入门 一、什么是反射 JAVA反射机制(The JAVA reflection mechanism...

  • Java基础之反射

    Java基础之—反射(非常重要)Java中反射机制详解Java进阶之reflection(反射机制)——反射概念与...

  • 反射之一

    总结内容源自一下文章粗浅看java反射机制反射机制应用实践谈谈java反射机制Java Reflection(反射...

  • 反射之二

    总结内容源自一下文章粗浅看java反射机制反射机制应用实践谈谈java反射机制Java Reflection(反射...

  • Java基础之反射

    Java基础之反射 反射基本介绍 反射的使用通过反射调用属性和方法通过反射获取配置文件 反射基本介绍 Java反射...

  • Java 反射机制

    Java 反射机制 什么是反射 Java 反射是Java语言的一个很重要的特征,它使得Java具体了“动态性”。 ...

  • 一探究竟:Java反射效率低的原因到底在哪?

    预备知识 了解 Java 反射基本用法 看完本文可以达到什么程度 了解 Java 反射原理及 Java 反射效率低...

  • 面试官说:大家都说 Java 反射效率低,你知道原因在哪里么

    预备知识 了解 Java 反射基本用法 看完本文可以达到什么程度 了解 Java 反射原理及 Java 反射效率低...

  • Java面试题之JavaSE高级

    一、Java中的反射 1.说说你对Java中反射的理解 java中的反射首先是能够获取到Java...

网友评论

    本文标题:JAVA - 反射

    本文链接:https://www.haomeiwen.com/subject/sfnpyxtx.html