概述

  • 通过java语言中的反射机制,可以操作字节码文件 .class。
  • 反射机制的相关类在 java.lang.reflect.* 包下
  • 反射机制相关的重要的类
    • java.lang.Class 整个字节码文件,代表一个类型
    • java.lang.reflect.Method 字节码中的方法
    • java.lang.reflect.Constructor 字节码中的构造方法
    • java.lang.reflect.Field 字节码中的属性

获取字节码文件

要操作一个类的字节码文件,需要首先获取到这个类的字节码文件。

三种获取class文件方式
  1. 通过java.lang.Class类中的forName() 来获取

Class c1 = ``Class.forName("com.yixuexi.test01.Test");
注意
forName()是静态方法
方法的参数是一个字符串 必须是一个完整的类名【带包名】
返回一个Class类型对象

  1. java中任何一个对象,都有一个getClass()方法

Test test = new Test();
Class c2 = test.getClass();

  1. java中任何一种类型,都有.class属性

    1. ` Class c3 = Test.class;`<br />c3代表 Test类型<br />注意:c3 == c1/c2 true 变量的内存地址相同

    获取到Class后

    通过newInstance()来实例化对象

    Class c1 = Class.forName(“com.yixuexi.bean.User”);
    Object obj = c1.newInstance();
    底层会调用User的无参构造方法
    如果写了有参构造,则默认的无参消失 报异常:java.lang.InstantiationException 实例化对象异常

    Class.forName() 方法的执行
    Class.forName("com.yixuexi.Test");<br />        forName()方法 会导致类加载,类加载时会执行静态代码块
    

可变长度参数

语法:

public static void m(int... args){

}

类型后面跟3个点 …

  • 可边长参数必须在形参列表中最后一个
  • 可以当作一个数组来对待, 直接用for遍历args也可以

作用
调用时,传参可以 传 0-n个

通过反射机制得到Field(属性)

getFields()

  • Class c = Class.forName(“com.yixuexi.bean.Student”);
  • //获取类中所有的field,返回一个Field数组
  • Field[] arr = c.getFields();
  • // 返回对应下标的属性的名字
  • String fieldName = arr[0].getName();
  • 获取类中所有(public ) 属性


    getDeclaredFields()

  • //获取全部的属性,不管是不是私有的 公开的

  • Field[] f = c.getDeclaredFields();

f[0].getType()
获取对应属性的类型

  • Class s = f[0].getType(); //返回一个Class
  • System.out.println(s.getName()); // 通过getName得到名字【带包名】
  • System.out.println(s.getSimpleName()); //得到简单的类名

f[0].getModifiers()

  • 返回对应属性的修饰符编号,每个数字是修饰符的代号
  • 将代号数字转换成字符串: Modifier.toString(f[0].getModifiers()) 静态方法

getName() 得到这个属性的名字

通过反射机制访问对象属性(掌握)

设置(公开的)

//通过反射机制访问java对象的属性
Class c = Class.forName("com.yixuexi.bean.Student");

//通过反射机制创建一个对象
Object obj = c.newInstance();

//获取id属性,根据属性的名称获取Field
Field f = c.getDeclaredField("id");

//赋值  三要素:obj对象, id属性 1111值
f.set(obj,1111);// 给obj的id属性赋值1111

访问(公开的)

System.out.println(f.get(obj)); //访问obj的id属性
访问私有属性需打破封装
//打破封装
f.setAccessible(true);
在set或者get上面 添加这行代码


反射机制调用方法

//通过反射机制调用方法 获取类
Class c = Class.forName("com.yixuexi.bean.Student");

//创建对象
Object obj = c.newInstance();

//获取Method,  第一个参数是方法名,第二个是可变长度类型Class
Method doSomeMethod = c.getDeclaredMethod("doSome", String.class, int.class);

//调用方法  调用obj对象的 doSomeMethod方法,[传 "张三" 11 参数(可变长度)]  返回值为returnValue
Object returnValue = doSomeMethod.invoke(obj,"张三",11);

通过反射获取类的父类和父接口

    Class c = Class.forName("java.lang.String");
    //获取String的父类

    Class superClass = c.getSuperclass();
    System.out.println(superClass.getSimpleName());

    //获取String实现的所有接口,返回Class数组
    Class[] superInterfaces = c.getInterfaces();
    for (Class superInterface : superInterfaces) {
        System.out.println(superInterface);
    }