Java反射

    技术2025-10-31  3

    目录

    反射Class类基本方法getClass方法与getName方法forName方法、newInstance方法和getSuperclass方法虚拟机为每个类型管理一个 Class 对象 利用反射分析类的能力getModifiers方法获取类的域(Field)、构造器(Constructor)、方法(Method)获得方法的返回值和参数的类型 在运行时使用反射分析对象

    反射

    能够分析类能力的程序称为反射(reflective)。反射机制的功能极其强大,反射机制可以用来:(1)在运行时分析类的能力。 (2)在运行时查看对象, 例如, 编写一个 toString方法供所有类使用。s(3)实现通用的数组操作代码。 (3)利用 Method 对象, 这个对象很像cpp中的函数指针。

    通过代码分析展示反射的作用。

    首先创建com.reflectTest包下Test.java、Fa.java、Son.java三个类文件。代码如下:Test.java根据具体样例给出。 Fa.java

    package com.reflectTest; public class Fa { public final int a = 1; }

    Son.java

    package com.reflectTest; public class Son extends Fa{ private double b = 2.0; public static int maxn = 1000; public Son() {} public Son(double b) { this.b = b; } public void sonFunc(String s) { System.out.println(s); } }

    Class类

    在程序运行期间,Java运行时系统始终为所有的对象维护一个被称为运行时的类型标识。 这个信息跟踪着每个对象所属的类。虚拟机利用运行时类型信息选择相应的方法执行。 然而, 可以通过专门的 Java 类访问这些信息。保存这些信息的类被称为 Class, 这个名 字很容易让人混淆。Object 类中的 getClass( ) 方法将会返回一个 Class 类型的实例。

    基本方法

    getClass方法与getName方法

    通过Object的getClass方法可以获得一个对象的类,这是一个本地方法。通过Class的getName方法,可以获得类的名字。

    Test.java代码如下:

    package com.reflectTest; public class Test { public static void main(String[] args) throws ClassNotFoundException { Class c = new Son().getClass(); //通过Object类的getClass方法获得一个Class对象 System.out.println(c); System.out.println(c.getName()); //getName()方法返回类的名字 } }

    运行结果:

    forName方法、newInstance方法和getSuperclass方法

    Class的静态方法forName,通过输入的字符串获得一个Class对象,该方法可能抛出一个ClassNotFoundException异常。Class的newInstance方法,调用类的无参构造方法构造一个对象,该方法不能调用有参数构造方法。(Constructor 的 newInstance方法可以调用有参构造方法)方法可能抛出IllegalAccessException与InstantiationException异常。Class的getSuperclass方法,返回该Class对象的父类(不是返回Class类的父类)

    Test.java代码如下:

    package com.reflectTest; public class Test { public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException { String className = "com.reflectTest.Son"; //使用forName构建一个Class对象表示Son类 Class c = Class.forName(className); //可能抛出ClassNotFoundException double[] b = new double[0]; Son s = (Son) c.newInstance(); System.out.println(c.getName()); //输出Son类的类名 System.out.println(c.getSuperclass().getName()); //输出Son类父类的类名 } }

    虚拟机为每个类型管理一个 Class 对象

    通过以下代码的输出结果为true可以验证。(怎么实现的。为什么?)

    package com.reflectTest; public class Test { public static void main(String[] args) { Class c1 = Fa.class; Class c2 = new Fa().getClass(); Class c3 = new Fa().getClass(); System.out.println(c1 == c2 && c2 == c3); } }

    利用反射分析类的能力

    在java.lang.reflect包中有三个类Field 、Method、Constructor分别用于描述类的域、方法和构造器。下面一步一步分析这三个类的作用。

    getModifiers方法

    Class、Field 、Method、Constructor这几个类均有getModifiers方法返回一个整数(表示修饰符),利用java.lang.reflett包中的Modifier类的静态方法toString分析getModifiers返回的整型数值。如下代码:

    Test.java

    package com.reflectTest; import java.lang.reflect.Modifier; public final class Test { public static void main(String[] args) throws ClassNotFoundException { String className = "com.reflectTest.Son"; Class c = Class.forName(className); String modifier = Modifier.toString(c.getModifiers()); //分析类 System.out.println(modifier); //Son类的修饰符是public System.out.println(Modifier.toString(Class.forName("com.reflectTest.Test").getModifiers())); } }

    获取类的域(Field)、构造器(Constructor)、方法(Method)

    使用Class类的getFields、getConstructors、getMethods方法可以获得Field、Constructor、Method对象,但是只能获得public的。使用Class类的getDeclaredFields、getDeclaredConstructors、getDeclaredMethods方法可以获得Field、Constructor、Method对象,但是不能获得父类的。

    Test.java

    package com.reflectTest; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; public final class Test { public int a = 1; private int b = 1; public Test() {} private Test(int a) {} public void func1() {} private void func2() {} public static void main(String[] args) throws ClassNotFoundException { Class c = Class.forName("com.reflectTest.Test"); Constructor[] constructors = c.getDeclaredConstructors(); for (Constructor constructor : constructors) System.out.println(constructor.getName()); Field[] fields = c.getDeclaredFields(); for (Field field : fields) System.out.println(field.getName()); Method[] methods = c.getDeclaredMethods(); for (Method method : methods) System.out.println(method.getName()); } }

    获得方法的返回值和参数的类型

    通过Method的getReturnType方法可以获得返回值Class对象。通过Method的getParameterTypes方法可以获得函数的参数Class对象列表。 package com.reflectTest; import java.lang.reflect.Method; import java.lang.reflect.Modifier; public final class Test { public int func1(int a,double b) {return 0;} private boolean func2(boolean c) {return true;} public static void main(String[] args) throws ClassNotFoundException { Class c = Class.forName("com.reflectTest.Test"); Method[] methods = c.getDeclaredMethods(); for (Method method : methods) { String modifiers = Modifier.toString(method.getModifiers()); System.out.print(modifiers + " " + method.getReturnType().getName() + " "); System.out.print(method.getName() + "("); Class[] parameters = method.getParameterTypes(); for (int i = 0; i < parameters.length; i++) { if (i == 0) System.out.print(parameters[i].getName()); else System.out.print(", " + parameters[i].getName()); } System.out.println(")"); } } }

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

    在运行时,可以通过之前提到的方法获得Field对象,然后通过get获得对象的域中的值,或者通过set方法修改域中的值。注意通过Class对象的getDefaulted方法才能获得所有修饰符中的对象(如private),而获取private域的值时,需要调用Field、Method、Constructor的setAccess方法设置访问控制权限。

    Test.java

    package com.reflectTest; import java.lang.reflect.Field; public class Test { public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException { GetTest gt = new GetTest(); Class c = gt.getClass(); //获得s1域 Field field1 = c.getField("s1"); System.out.println(field1.get(gt)); //获得s2域(因为不是public,所以需要用getDeclaredField而不是get) Field field2 = c.getDeclaredField("s2"); //设置访问方法,否则(private)域不能访问。 field2.setAccessible(true); System.out.println(field2.get(gt)); //设置gt的field2域的值为"ccccc" field2.set(gt, "ccccc"); System.out.println(gt.getS2()); } } class GetTest { public String s1 = "aaaaa"; private String s2 = "bbbbb"; public String getS2() { return s2; } }

    Processed: 0.009, SQL: 9