能够分析类能力的程序成为反射,反射可以用来:

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

# Class 类

获取 Class 类方法:

  • Object 类的 getClass () 方法会返回一个 Class 类型的实例;
  • Class 类的静态方法 forName (String className)。
  • T.class,T 可以是任意类型,如 Random,int,Double []。

常用方法:

  • String getName () 返回类的名字。
  • Object newInstance () 动态创建一个类的实例。
  • Field [] getFields () 返回类或超类的公有域。
  • Field [] getDeclaredFields () 返回类中所有域。
  • Method [] getMethods () 返回类或超类的公有方法。
  • Method [] getDeclaredMethods () 返回类或接口的所有方法。
  • Constructor [] getConstructors () 返回类的所有公有构造器。
  • Constructor [] getDeclaredConstructors () 返回类的所有构造器。
  • Field getField (String name) 返回指定名称的公有域。
  • Field getDeclaredField (String name) 返回类中声明的给定名称的域。

# Field 类、Method 类、Constructor 类

常用方法:

  • Class getDeclaringClass () 返回一个用于描述类中定义的构造器、方法或域的 Class 对象。
  • Class [] getExceptionTypes () 返回一个用于描述方法抛出的异常类型的 Class 对象数组。
  • int getModifiers () 返回一个用于描述构造器、方法或域的修饰符的整型数值。
  • String getName () 返回一个用于描述构造器、方法或域名的字符串。
  • Class [] getParametertypes () 返回一个用于描述参数类型的 Class 对象数组。(在 Method 类和 Constructor 类中)
  • Class getReturnType () 返回一个用于描述返回类型的 Class 对象。(在 Method 类中)
  • Object get (Object obj) 返回 obj 对象中用 Field 对象表示的域值。(在 Field 类中)
  • void set (Object obj, Object newValue) 用一个新值设置 obj 对象中 Field 对象表示的域。(在 Filed 类中)

# Modifier 类

  • static String toString (int modifiers) 返回对应 modifiers 中位设置的修饰符的字符串表示。
  • static boolean isAbstract (int modifiers) 是否包含 Abstract。
  • static boolean isFinal (int modifiers) 是否包含 Final。
  • static boolean isInterface (int modifiers) 是否包含 Interface。
  • static boolean isNative (int modifiers) 是否包含 Native。
  • static boolean isPrivate (int modifiers) 是否包含 Private。
  • static boolean isProtected (int modifiers) 是否包含 Protected。
  • static boolean isPublic (int modifiers) 是否包含 Public。
  • static boolean isStatic (int modifiers) 是否包含 Static。
  • static boolean isSynchronized (int modifiers) 是否包含 Synchronized。
  • static boolean isVolatile (int modifiers) 是否包含 Volatile。

以上方法运用:

package com.example.demo.test;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
public class ClassTest {
    public static void main(String[] args) {
        String name = "java.lang.Double";
        try {
            Class cl = Class.forName(name);
            String modifiers = Modifier.toString(cl.getModifiers());
            if (modifiers.length() > 0) {
                System.out.print(modifiers + " ");
            }
            System.out.print("class " + name);
            Class superCl = cl.getSuperclass();
            if (superCl != null && superCl != Object.class) {
                System.out.print(" extends " + superCl.getName() + " {");
            }
            System.out.println();
            printFields(cl);
            System.out.println();
            printConstructors(cl);
            System.out.println();
            printMethods(cl);
            System.out.println("}");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
    public static void printFields(Class cl) {
        Field[] fields = cl.getFields();
        for (Field field : fields) {
            System.out.print("    ");
            String modifiers = Modifier.toString(field.getModifiers());
            if (!modifiers.isEmpty()) {
                System.out.print(modifiers + " ");
            }
            System.out.println(field.getType().getName() + " " + field.getName());
        }
    }
    public static void printConstructors(Class cl) {
        Constructor[] constructors = cl.getConstructors();
        for (Constructor constructor : constructors) {
            System.out.print("    ");
            String modifiers = Modifier.toString(constructor.getModifiers());
            if (!modifiers.isEmpty()) {
                System.out.print(modifiers + " ");
            }
            System.out.print(constructor.getName() + "(");
            Class[] paramTypes = constructor.getParameterTypes();
            for (int i = 0; i < paramTypes.length; i++) {
                if (i > 0) {
                    System.out.print(", ");
                }
                System.out.print(paramTypes[i].getName());
            }
            System.out.println(");");
        }
    }
    public static void printMethods(Class cl) {
        Method[] methods = cl.getMethods();
        for (Method method : methods) {
            System.out.print("    ");
            String modifiers = Modifier.toString(method.getModifiers());
            if (!modifiers.isEmpty()) {
                System.out.print(modifiers + " ");
            }
            System.out.print(method.getReturnType().getName() + " " + method.getName() + "(");
            Class[] paramTypes = method.getParameterTypes();
            for (int i = 0; i < paramTypes.length; i++) {
                if (i > 0) {
                    System.out.print(", ");
                }
                System.out.print(paramTypes[i].getName());
            }
            System.out.println(");");
        }
    }
}

运行结果:

public final class java.lang.Double extends java.lang.Number {
    public static final double POSITIVE_INFINITY
    public static final double NEGATIVE_INFINITY
    public static final double NaN
    public static final double MAX_VALUE
    public static final double MIN_NORMAL
    public static final double MIN_VALUE
    public static final int MAX_EXPONENT
    public static final int MIN_EXPONENT
    public static final int SIZE
    public static final int BYTES
    public static final java.lang.Class TYPE

    public java.lang.Double(double);
    public java.lang.Double(java.lang.String);

    public boolean equals(java.lang.Object);
    public static java.lang.String toString(double);
    public java.lang.String toString();
    public int hashCode();
    public static int hashCode(double);
    public static double min(double, double);
    public static double max(double, double);
    public static native long doubleToRawLongBits(double);
    public static long doubleToLongBits(double);
    public static native double longBitsToDouble(long);
    public volatile int compareTo(java.lang.Object);
    public int compareTo(java.lang.Double);
    public byte byteValue();
    public short shortValue();
    public int intValue();
    public long longValue();
    public float floatValue();
    public double doubleValue();
    public static java.lang.Double valueOf(java.lang.String);
    public static java.lang.Double valueOf(double);
    public static java.lang.String toHexString(double);
    public static int compare(double, double);
    public static boolean isNaN(double);
    public boolean isNaN();
    public static boolean isFinite(double);
    public static boolean isInfinite(double);
    public boolean isInfinite();
    public static double sum(double, double);
    public static double parseDouble(java.lang.String);
    public final void wait();
    public final void wait(long, int);
    public final native void wait(long);
    public final native java.lang.Class getClass();
    public final native void notify();
    public final native void notifyAll();
}

# Accessible 类

Accessible 类是 Field 类、 Method 类和 Constructor 类的公共超类,其 setAccessible() 方法可以修改访问控制。如下面的 field.setAccessible(true) 语句,没有这个语句,将不能获取私有变量 name 的值。当属性类型是基本数据类型时,会将值包装到对应的包装器中,即 double 包装成 Double

Java 代码:

package com.example.demo.test;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
public class ClassTest {
    public static void main(String[] args) {
        Person person = new Person("huihui", 18);
        Class cl = person.getClass();
        try {
            Field field = cl.getDeclaredField("name");
            Field field1 = cl.getDeclaredField("age");
            field.setAccessible(true);
            field1.setAccessible(true);
            Object v = field.get(person);
            Object v1 = field1.get(person);
            System.out.println(v + ":" + v.getClass().getName());
            System.out.println(v1 + ":" + v1.getClass().getName());
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }
}
class Person {
    private String name;
    private double age;
    public Person(String name, Integer age) {
        this.name = name;
        this.age = age;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public double getAge() {
        return age;
    }
    public void setAge(double age) {
        this.age = age;
    }
}

运行结果:

huihui:java.lang.String
18.0:java.lang.Double

# AccessibleObject 类

  • void setAccessible (boolean flag) 为反射对象设置可访问标志。
  • boolean isAccessible () 返回反射对象可访问标志的值。
  • static void setAccessible (AccessibleObject [] array, boolean flag) 设置对象数组可访问标志的快捷方法。

# Array 类

  • static Object get (Object array, int index) 返回储存在给定位置上的给定数组的内容。
  • static xxx getXxx (Object array, int index) xxx 是基本数据类型中的一种,返回存储在给定位置上的给定数组的内容。
  • static void set (Object array, int index, Object newValue) 将一个新值存储到给定位置上的给定数组中。
  • static void setXxx (Object array, int index, Object newValue) xxx 是基本数据类型中的一种,将一个新值存储到给定位置上的给定数组中。
  • static int getLength (Object array) 返回数组的长度。
  • static Object newInstance (Class componentType, int length) 返回一个具有给定类型、给定维数的新数组。
  • static Object newInstance (Class componentType, int length) 返回一个具有给定类型、给定维数的新数组。

Java 代码:

package com.example.demo.test;
import java.lang.reflect.*;
import java.util.ArrayList;
import java.util.Arrays;
public class ClassTest {
    public static void main(String[] args) {
        int[] a = {1, 2, 3};
        a = (int[]) goodCopyOf(a, 10);
        System.out.println(Arrays.toString(a));
        String[] b = {"aa", "bb", "cc"};
        b = (String[]) goodCopyOf(b, 10);
        System.out.println(Arrays.toString(b));
        b = (String[]) badCopyOf(b, 10);
    }
    public static Object[] badCopyOf(Object[] a, int newLength) {
        Object[] newArray = new Object[newLength];
        System.arraycopy(a, 0, newArray, 0, Math.min(a.length, newLength));
        return newArray;
    }
    public static Object goodCopyOf(Object a, int newLength) {
        Class cl = a.getClass();
        if (!cl.isArray()) {
            return null;
        }
        Class componentType = cl.getComponentType();
        int length = Array.getLength(a);
        Object newArray = Array.newInstance(componentType, newLength);
        System.arraycopy(a, 0, newArray, 0, Math.min(length, newLength));
        return newArray;
    }
}

运行结果:

[1, 2, 3, 0, 0, 0, 0, 0, 0, 0]
[aa, bb, cc, null, null, null, null, null, null, null]
Exception in thread "main" java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Ljava.lang.String;at com.example.demo.test.ClassTest.main(ClassTest.java:18)

badCopyof 方法中, Object[]String[] 报错,将 String[] 临时转为 Object[] 再转为 String[] 可以。从一开始就是 Object 的数组永远不能转换为 String[] 。在 goodCopyof 方法中, int[] 可以转换成 Object ,但不能转换为 Object[] ,所以方法返回 Object

# invoke () 方法

public Object invoke (Object implicitParameter, Object [] explicitParameters),调用这个对象所描述的方法,传递给定参数,并返回方法的返回值。对于静态方法,把 null 作为隐式参数传递,在使用包装器传递基本类型的值时,基本类型的返回值必须是未包装的。

Java 代码:

package com.example.demo.test;
import java.lang.reflect.*;
import java.util.ArrayList;
public class ClassTest {
    public static void main(String[] args) {
        try {
            Method square = ClassTest.class.getMethod("square", double.class);
            Method sqrt = Math.class.getMethod("sqrt", double.class);
            printTable(1, 10, 10, square);
            printTable(1, 10, 10, sqrt);
        } catch (NoSuchMethodException e) {
            System.out.println(e.getMessage());
        }
    }
    public static double square(double x) {
        return x * x;
    }
    public static void printTable(double from, double to, int n, Method f) {
        System.out.println(f);
        double dx = (to - from) / (n - 1);
        for (double x = from; x <= to; x += dx) {
            try {
                double y = (Double) f.invoke(null, x);
                System.out.printf("%10.4f | %10.4f%n", x, y);
            } catch (Exception e) {
                System.out.println(e.getMessage());
            }
        }
    }
}

运行结果:

public static double com.example.demo.test.ClassTest.square(double)
    1.0000 |     1.0000
    2.0000 |     4.0000
    3.0000 |     9.0000
    4.0000 |    16.0000
    5.0000 |    25.0000
    6.0000 |    36.0000
    7.0000 |    49.0000
    8.0000 |    64.0000
    9.0000 |    81.0000
   10.0000 |   100.0000
public static double java.lang.Math.sqrt(double)
    1.0000 |     1.0000
    2.0000 |     1.4142
    3.0000 |     1.7321
    4.0000 |     2.0000
    5.0000 |     2.2361
    6.0000 |     2.4495
    7.0000 |     2.6458
    8.0000 |     2.8284
    9.0000 |     3.0000
   10.0000 |     3.1623