java中的反射机制(一)

0. 概念

反射库:工具集合,能够用来编写动态操作Java代码的程序。

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

  1. 在运行的时候分析类的能力
  2. 在运行的时候检查对象
  3. 实现泛型数组操作代码
  4. 利用Method对象

1. class类

 1.1概念

运行时类型标识:java运行时系统始终为所有对象维护一个运行时类型标识,这个信息会跟踪每个对象所属的类

Class: 使用一个特殊的java类可以访问这些信息(运行时类型标识),保存这些信息的类名为Class

1.2 获取Class类对象的三种方法

a. Object.getClass方法:该方法会返回一个Class类型的实例

Employee e;
Class c1 = e.getClass();

 Class对象会描述一个特定类的属性 ,如上c1可以描述类Employee的属性,最常用的方法是getName(),这个方法将返回类的名字

e.getClass().getName()

b.静态方法forName: 获取类型对应的Class对象

String className = "java.util.Random";
Class c1 = Class.forName();

只有className是一个类名或者是接口名,该方法才能正常执行,而且无论何时使用,都需要提供一个异常处理器

c.如果T是任意的Java类型,T.class将代表匹配的类对象

例如:

Class cl1  = Random.class;
Class cl2 = int.class;
Class cl3  = Double[].class;

 注意:一个Class对象实际上表示的是一个类型,这可能是类,也可能不是类,如int不是类,int.class是一个Class类型的对象

1.3 利用==运算实现两个类的对象的比较

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

例如:

if (e.getClass == Employee.class)

 1.4 构造描述类的实例

 如果有一个Class类型的对像,可以用它构造类的实例

try {
            String className = "java.util.Random";
            Class c1 = Class.forName(className);
            Object obj = c1.getConstructor().newInstance();
            System.out.println(obj);
        } catch (Exception e) {
            e.printStackTrace();
  }

输出:

2.利用反射分析类的能力

可以检查类的结构。

java.lang.reflect中有三个类Filed、Method和Constructor分别用于描述类的字段、方法和构造器

这三个类共有一个getName()的方法,用来返回字段、方法、或者构造器的名称。

下面的代码就利用Class的api实现了打印一个类的全部信息

public class ReflectionTest {
    public static void main(String[] args) throws ClassNotFoundException {
        //从命令终端或者用户输入读取类名
        String name;
        if (args.length>0) {
            name = args[0];
        }else {
            Scanner in = new Scanner(System.in);
            System.out.println("Enter class name (e.g. java.util.Date):");
            name = in.next();
        }

        //打印该类名和父类名(不是Object的情况下)
        Class cl = Class.forName(name);
        Class superclass = cl.getSuperclass();
        //getModifiers返回一个整数,描述所使用的修饰符,利用Modifier.toString方法将修饰符打印出来
        String modifier = Modifier.toString(cl.getModifiers());
        if (modifier.length()>0) {
            System.out.print(modifier+" ");
        }
        System.out.print("class "+name);
        if (superclass !=null && superclass != Object.class) {
            System.out.print(" extends "+superclass.getName());
        }
        System.out.print("\n{\n");

        //打印构造器
        printConstructors(cl);
        System.out.println("");
        printMethods(cl);
        System.out.println("");
        printFiled(cl);
        System.out.println("}");

    }

    //打印该类的所有构造器
    public static void printConstructors(Class cl){
        //getDeclaredConstructors:获取所有构造器
        Constructor[] constructors = cl.getDeclaredConstructors();
        for (Constructor c : constructors) {
            //获取构造器的名字
            String name = c.getName();
            System.out.print("   ");
            //获取构造器的修饰符
            String modifier = Modifier.toString(c.getModifiers());
            if (modifier.length()>0) {
                System.out.print(modifier+" ");
            }
            System.out.print(name+"(");

            //打印参数类型
            Class[] parameterTypes = c.getParameterTypes();
            for (int i = 0; i <parameterTypes.length ; i++) {
                if (i>0) {
                    System.out.print(", ");
                }
                System.out.print(parameterTypes[i].getName());
            }
            System.out.println(");");

        }
    }


    //打印所有方法
    public static void printMethods(Class c1){
        Method[] methods = c1.getMethods();
        for (Method m : methods) {
            //返回类型
            Class retType = m.getReturnType();
            String name = m.getName();
            System.out.print("   ");
            String modifier = Modifier.toString(m.getModifiers());
            if (modifier.length()>0) {
                System.out.print(modifier+" ");
            }
            System.out.print(retType.getName()+" "+name+"(");

            //打印所有参数类型
            Class[] parameterTypes = m.getParameterTypes();
            for (int i = 0; i <parameterTypes.length ; i++) {
                if (i>0) {
                    System.out.print(", ");
                }
                System.out.print(parameterTypes[i].getName());
            }
            System.out.println(");");

        }
    }


    public static void printFiled(Class cl){
        Field[] fields = cl.getDeclaredFields();
        for (Field f : fields) {
            Class type = f.getType();
            String name = f.getName();
            System.out.print("   ");
            String modifiers = Modifier.toString(f.getModifiers());
            if (modifiers.length() > 0) {
                System.out.print(modifiers+" ");
            }
            System.out.println(type.getName()+" "+name+";");
        }
    }
}

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

  • 利用反射机制可以查看在编译期间还不知道的对象字段
  • 对于字段的访问,受到Java安全控制的影响,反射机制的默认行为受限于Java的访问控制,但是可以调用Field等的setAccessible方法覆盖掉Java的访问控制,例如: 
f.setAccessible(true);

4. 使用反射编写泛型数组代码

 java.lang.reflect包中的Array类允许动态的创建数组

如CopyOf的实现:

 public static Object goodCopyOf(Object a,int newlength){
        //获取a数组的类对象
        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;
    }

5.利用反射调用方法和构造器

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

 Method m1 = Math.class.getMethod("sqrt", double.class);
 double d =(Double) m1.invoke(null, 4);
 System.out.println(d);

输出:

原文地址:https://www.cnblogs.com/xiangshigang/p/15736363.html