Java反射机制

Java反射机制,第1张

Java反射机制概述
  • Reflection(反射)是被视为动态语言的关键,反射机制允许程序在执行期借助于Reflection API取得任何类的内部信息,并能直接 *** 作任意对象的内部属性及方法。
  • 加载完类之后,在堆内存的方法区就产生了一个Class类型的对象(一个类只有一个Class对象),这个对象就包含了完整的类的结构信息。我们可以通过这个对象看到类的结构。这个对象就像一面镜子,透过这个镜子看到类的结构,所以我们形象的称之为:反射。

补充:动态语言VS静态语言

  • 动态语言

是一类在运行是可以改变其结构的语言:例如新的函数、对象、甚至代码可以被引进,已有的函数可以被删除或是其他结构上的变化。通俗点讲就是在运行时代码可以根据某些条件改变自身结构。例如Python、PHP.

  • 静态语言

与动态语言相对应的,运行时结构不可变的语言就是静态语言。例如Java、C、C++.

Java不是动态语言,但Java可以称之为“准动态语言”。即Java有一定的动态性,我们可以利用反射机制、字节码 *** 作获得类似动态语言的特性,Java的动态性让编程的时候更加灵活!


Java反射机制研究及应用
  • Java反射机制提供的功能

Java反射机制提供的功能

在运行时判断任意一个对象所属的类

在运行时构造任意一个类的对象

在运行时判断任意一个类所具有的成员变量和方法

在运行时获取泛型信息

在运行时调用任意一个对象的成员变量和方法

在运行时处理注解

生成动态代理


Java 反射机制的优缺点

优点:

  1. 能够运行时动态获取类的实例,大大提高系统的灵活性和扩展性。
  2. 与 Java 动态编译相结合,可以实现无比强大的功能。
  3. 对于 Java 这种先编译再运行的语言,能够让我们很方便的创建灵活的代码,这些代码可以在运行时装配,无需在组件之间进行源代码的链接,更加容易实现面向对象

缺点:

  1. 反射会消耗一定的系统资源,因此,如果不需要动态地创建一个对象,那么就不需要用反射;
  2. 反射调用方法时可以忽略权限检查,获取这个类的私有方法和属性,因此可能会破坏类的封装性而导致安全问题。

Java反射机制API

实现Java反射机制的类都位于 java.lang.reflect 包中,java.lang.Class 类是 Java 反射机制 API 中的核心类。

java.lang.Class 类

java.lang.Class 类是实现反射的关键所在,Class 类的一个实例表示 Java 的一种数据类型,包括类、接口、枚举、注解(Annotation)、数组、基本数据类型和 void。Class 没有公有的构造方法,Class 实例是由 JVM 在类加载时自动创建的。

在程序代码中获得 Class 实例可以通过如下代码实现:

// 1. 通过类型class静态变量
Class clz1 = String.class;
String str = "Hello";
// 2. 通过对象的getClass()方法
Class clz2 = str.getClass();

每一种类型包括类和接口等,都有一个 class 静态变量可以获得 Class 实例。另外,每一个对象都有 getClass() 方法可以获得 Class 实例,该方法是由 Object 类提供的实例方法。
Class 类提供了很多方法可以获得运行时对象的相关信息,下面的程序代码展示了其中一些方法。

public class ReflectionTest01 {
    public static void main(String[] args) {
        // 获得Class实例
        // 1.通过类型class静态变量
        Class clz1 = String.class;
        String str = "Hello";
        // 2.通过对象的getClass()方法
        Class clz2 = str.getClass();
        // 获得int类型Class实例
        Class clz3 = int.class;
        // 获得Integer类型Class实例
        Class clz4 = Integer.class;
        System.out.println("clz2类名称:" + clz2.getName());
        System.out.println("clz2是否为接口:" + clz2.isInterface());
        System.out.println("clz2是否为数组对象:" + clz2.isArray());
        System.out.println("clz2父类名称:" + clz2.getSuperclass().getName());
        System.out.println("clz2是否为基本类型:" + clz2.isPrimitive());
        System.out.println("clz3是否为基本类型:" + clz3.isPrimitive());
        System.out.println("clz4是否为基本类型:" + clz4.isPrimitive());
    }
}

运行结果如下: 

clz2类名称:java.lang.String
clz2是否为接口:false
clz2是否为数组对象:false
clz2父类名称:java.lang.Object
clz2是否为基本类型:false
clz3是否为基本类型:true
clz4是否为基本类型:false 

java.lang.reflect 包

java.lang.reflect 包提供了反射中用到类,主要的类说明如下:

  1. Constructor 类:提供类的构造方法信息。
  2. Field 类:提供类或接口中成员变量信息。
  3. Method 类:提供类或接口成员方法信息。
  4. Array 类:提供了动态创建和访问 Java 数组的方法。
  5. Modifier 类:提供类和成员访问修饰符信息。

代码如下:

public class ReflectionTest02 {
    public static void main(String[] args) {
        try {
            // 动态加载xx类的运行时对象
            Class c = Class.forName("java.lang.String");
            // 获取成员方法集合
            Method[] methods = c.getDeclaredMethods();
            // 遍历成员方法集合
            for (Method method : methods) {
                // 打印权限修饰符,如public、protected、private
                System.out.print(Modifier.toString(method.getModifiers()));
                // 打印返回值类型名称
                System.out.print(" " + method.getReturnType().getName() + " ");
                // 打印方法名称
                System.out.println(method.getName() + "();");
            }
        } catch (ClassNotFoundException e) {
            System.out.println("找不到指定类");
        }
    }
}

  上述代码第 5 行是通过 Class 的静态方法forName(String)创建某个类的运行时对象,其中的参数是类全名字符串,如果在类路径中找不到这个类则抛出 ClassNotFoundException 异常,见代码第 17 行。
代码第 7 行是通过 Class 的实例方法 getDeclaredMethods() 返回某个类的成员方法对象数组。代码第 9 行是遍历成员方法集合,其中的元素是 Method 类型。
代码第 11 行的method.getModifiers()方法返回访问权限修饰符常量代码,是 int 类型,例如 1 代表 public,这些数字代表的含义可以通过Modifier.toString(int)方法转换为字符串。代码第 13 行通过 Method 的 getReturnType() 方法获得方法返回值类型,然后再调用 getName() 方法返回该类型的名称。代码第 15 行method.getName()返回方法名称。


Java通过反射访问构造方法

为了能够动态获取对象构造方法的信息,首先需要通过下列方法之一创建一个 Constructor 类型的对象或者数组。

  1. getConstructors()
  2. getConstructor(Class…parameterTypes)
  3. getDeclaredConstructors()
  4. getDeclaredConstructor(Class...parameterTypes)

如果是访问指定的构造方法,需要根据该构造方法的入口参数的类型来访问。例如,访问一个入口参数类型依次为 int 和 String 类型的构造方法,下面的两种方式均可以实现。

objectClass.getDeclaredConstructor(int.class,String.class);
objectClass.getDeclaredConstructor(new Class[]{int.class,String.class});

创建的每个 Constructor 对象表示一个构造方法,然后利用 Constructor 对象的方法 *** 作构造方法。Constructor 类的常用方法如下表所示。

方法名称

说明

isVarArgs()

查看该构造方法是否允许带可变数量的参数,如果允许,返回 true,否则返回
false

getParameterTypes()

按照声明顺序以 Class 数组的形式获取该构造方法各个参数的类型

getExceptionTypes()

以 Class 数组的形式获取该构造方法可能抛出的异常类型

newInstance(Object … initargs)

通过该构造方法利用指定参数创建一个该类型的对象,如果未设置参数则表示
采用默认无参的构造方法

setAccessiable(boolean flag)

如果该构造方法的权限为 private,默认为不允许通过反射利用 netlnstance()
方法创建对象。如果先执行该方法,并将入口参数设置为 true,则允许创建对

getModifiers()

获得可以解析出该构造方法所采用修饰符的整数

 

通过 java.lang.reflect.Modifier 类可以解析出 getMocMers() 方法的返回值所表示的修饰符信息。在该类中提供了一系列用来解析的静态方法,既可以查看是否被指定的修饰符修饰,还可以字符串的形式获得所有修饰符。下表列出了 Modifier 类的常用静态方法。

态方法名称

说明

isStatic(int mod)

如果使用 static 修饰符修饰则返回 true,否则返回 false

isPublic(int mod)

如果使用 public 修饰符修饰则返回 true,否则返回 false

isProtected(int mod)

如果使用 protected 修饰符修饰则返回 true,否则返回 false

isPrivate(int mod)

如果使用 private 修饰符修饰则返回 true,否则返回 false

isFinal(int mod)

如果使用 final 修饰符修饰则返回 true,否则返回 false

toString(int mod)

以字符串形式返回所有修饰符

例如,下列代码判断对象 con 所代表的构造方法是否被 public 修饰,以及以字符串形式获取该构造方法的所有修饰符。

int modifiers = con.getModifiers();    // 获取构造方法的修饰符整数
boolean isPublic = Modifier.isPublic(modifiers);    // 判断修饰符整数是否为public 
string allModifiers = Modifier.toString(modifiers);

Java通过反射访问成员变量

通过下列任意一个方法访问成员变量时将返回 Field 类型的对象或数组。

  1. getFields()
  2. getField(String name)
  3. getDeclaredFields()
  4. getDeclaredField(String name)

 Field 类的常用方法如下表所示:

方法名称

说明

getName()

获得该成员变量的名称

getType()

获取表示该成员变量的 Class 对象

get(Object obj)

获得指定对象 obj 中成员变量的值,返回值为 Object 类型

set(Object obj, Object value)

将指定对象 obj 中成员变量的值设置为 value

getlnt(0bject obj)

获得指定对象 obj 中成员类型为 int 的成员变量的值

setlnt(0bject obj, int i)

将指定对象 obj 中成员变量的值设置为 i

setFloat(Object obj, float f)

将指定对象 obj 中成员变量的值设置为 f

getBoolean(Object obj)

获得指定对象 obj 中成员类型为 boolean 的成员变量的值

 

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/743288.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-04-29
下一篇 2022-04-29

发表评论

登录后才能评论

评论列表(0条)

保存