Java基础之——反射

类加载器(java.lang.ClassLoader)

ClassLoader

负责加载类的对象

还有以下内置类加载器:

  • Bootstrap class loader:他是虚拟机的内置类加载器,通常为null,并且没有父null
  • Platform class loader:平台类加载器可以看到所有平台类,平台类包括由平台类加载器或其祖先定义的JavaSE平台API,模块路径和JDK特定工具上的类
  • System class loader:它也被称为应用程序类加载器,与平台类加载器不同。
  • 类加载器的继承关系:System的父加载器为Platform,而Platform的父加载器为Bootstrap

示例

    ClassLoader c = ClassLoader.getSystemClassLoader();
    System.out.println(c);  //AppClassLoader

    ClassLoader c2 = c.getParent();
    System.out.println(c2); //PlatformClassLoader

    ClassLoader c3 = c2.getParent();
    System.out.println(c3); //null

反射

概念

是指在运行时去获取一个类的变量和方法信息。然后通过获取到的信息来创建对象,调用方法的一种机制。
类的加载过程

获取Class类的对象

三种方式:

  • 使用类的class属性来获取该类对应的Class对象
  • 调用对象的getClass方法,返回该对象所属类对应的Class对象
  • 使用Class类中的静态方法forName(String className),该字符串参数是某个类的全路径,也就是完整包名的路径

示例

	//使用class属性
    Class<Student> c = Student.class;
    System.out.println(c);  //class reflect.demo2.Student
    System.out.println("-----------");

    Class<Student> c2 = Student.class;
    System.out.println(c == c2);  //true
    System.out.println("-----------");

    //使用getClass方法
    Student student = new Student();
    Class<? extends Student> c3 = student.getClass();
    System.out.println(c == c3);  //true
    System.out.println("-----------");

    //使用forName方法
    Class<?> c4 = Class.forName("reflect.demo2.Student");
    System.out.println(c == c4);  //true

反射获取构造方法

java.lang.Class类中获取构造方法的方法:

  • Constructor<?>[] getConstructors():返回所有公共构造方法的数组
  • Constructor<?>[] getDeclaredConstructors():返回所有构造方法对象的数组(包含私有构造方法
  • Constructor getConstructor​(Class<?>… parameterTypes):返回单个公共构造方法对象
  • Constructor getDeclaredConstructor​(Class<?>… parameterTypes):返回单个构造方法对象(包含私有构造方法

java.lang.reflect.Constructor类中用于创建对象的方法

  • T newInstance​(Object… initargs):根据指定的构造方法创建对象

示例

	Class<Student> clazz = Student.class;
    //获取所有的公共构造方法
    Constructor<?>[] cons = clazz.getConstructors();
    for(Constructor<?> con : cons)
    {
      System.out.println(con);
    }
    System.out.println("---------------");
    //获取所有的公共方法(包含私有的)
    Constructor<?>[] cons2 = clazz.getDeclaredConstructors();
    for(Constructor<?> con2 : cons2)
    {
      System.out.println(con2);
    }
    System.out.println("---------------");

    //根据构造方法创建对象
    Constructor<Student> con3 = clazz.getConstructor();
    Object student = con3.newInstance();
    System.out.println(student);
    System.out.println("---------------");

    //练习反射实现公共构造方法:Student s = new Student("林青霞", 30, "西安");
    Constructor<Student> con4 = clazz.getConstructor(String.class, int.class, String.class);
    Student student1 = con4.newInstance("林青霞", 30, "西安");
    System.out.println(student1);

    //练习反射实现私有构造方法:Student s = new Student("林青霞");
    Constructor<Student> con5 = clazz.getDeclaredConstructor(String.class);
    System.out.println(con5);
    //暴力反射,获取私有构造方法
    con5.setAccessible(true);

    Student student2 = con5.newInstance("林青霞");
    System.out.println(student2);

输出示例:

public reflect.demo2.Student()
public reflect.demo2.Student(java.lang.String,int,java.lang.String)
---------------
public reflect.demo2.Student()
public reflect.demo2.Student(java.lang.String,int,java.lang.String)
reflect.demo2.Student(java.lang.String,int)
private reflect.demo2.Student(java.lang.String)
---------------
Student:{name:null-age:0-address:null}
---------------
Student:{name:林青霞-age:30-address:西安}
private reflect.demo2.Student(java.lang.String)
Student:{name:林青霞-age:0-address:null}

反射获取成员变量

java.lang.Class类中获取成员变量的方法:

  • Field[] getFields():返回所有公共成员变量对象的数组
  • Field[] getDeclaredFields():返回所有成员变量对象的数组(包含私有变量
  • Field getField​(String name):返回单个公共成员变量对象
  • Field getDeclaredField​(String name):返回单个成员变量对象(包含私有成员变量

java.lang.reflect.Field类中用于给成员变量赋值的方法

  • void set​(Object obj, Object value):给obj对象的成员变量赋值为value

示例

    Class<?> clazz = Class.forName("reflect.demo2.Student");
    //获取公共参数
    Field[] fields = clazz.getFields();
    for(Field field : fields)
    {
      System.out.println(field);
    }
    System.out.println("---------");

    //获取所有参数
    Field[] fields1 = clazz.getDeclaredFields();
    for(Field field : fields1)
    {
      System.out.println(field);
    }
    System.out.println("---------");

    //获取address field
    Field addressField = clazz.getField("address");
    //无参构造实例化类
    Constructor<?> con = clazz.getConstructor();
    Object obj = con.newInstance();
    //给obj的成员变量addressField赋值
    addressField.set(obj, "西安");
    System.out.println(obj);
    System.out.println("---------");

    //赋值练习
    Field[] fields2 = clazz.getDeclaredFields();
    for(Field field : fields2)
    {
      field.setAccessible(true);
    }
    fields2[0].set(obj, "林青霞");
    fields2[1].set(obj, 30);
    fields2[2].set(obj, "西安");
    System.out.println(obj);

输出示例:

public java.lang.String reflect.demo2.Student.address
---------
private java.lang.String reflect.demo2.Student.name
int reflect.demo2.Student.age
public java.lang.String reflect.demo2.Student.address
---------
Student:{name:null-age:0-address:西安}
---------
Student:{name:林青霞-age:30-address:西安}

反射获取成员方法

java.lang.Class类中获取成员方法的方法:

  • Method[] getMethods():返回所有公共成员方法对象的数组,包括继承的
  • Method[] getDeclaredMethods():返回所有成员方法对象的数组,不包括继承的(包含私有方法
  • Method getMethod​(String name, Class<?>… parameterTypes):返回单个公共成员方法对象
  • Method getDeclaredMethod​(String name, Class<?>… parameterTypes):返回单个成员方法对象(包含私有方法

java.lang.reflect.Method类中用于调用成员方法的方法

  • Object invoke​(Object obj, Object… args):调用obj对象的成员方法,参数是args,返回值是Object类型

示例

    Class<?> clazz = Class.forName("reflect.demo2.Student");
    //获取所有的公共方法,包括继承的
    Method[] methods = clazz.getMethods();
    for(Method method : methods)
    {
      System.out.println(method);
    }
    System.out.println("------------");

    //获取所有的方法,包括私有的,不包括继承的
    Method[] declaredMethods = clazz.getDeclaredMethods();
    for(Method declaredMethod : declaredMethods)
    {
      System.out.println(declaredMethod);
    }
    System.out.println("------------");

    //获得method1方法
    Method method1 = clazz.getMethod("method1");
    Constructor<?> constructor = clazz.getConstructor();
    //无参构造实例化类
    Object obj = constructor.newInstance();
    //调用obj的method1方法
    method1.invoke(obj);
    System.out.println("------------");

    //练习调用method2并传参
    Method method2 = clazz.getMethod("method2", String.class);
    method2.invoke(obj, "林青霞");

    //练习调用method3并传参
    Method method3 = clazz.getMethod("method3", String.class, int.class);
    Object obj2 = method3.invoke(obj, "林青霞", 30);
    System.out.println(obj2);

    //练习调用私有的function方法
    Method function = clazz.getDeclaredMethod("function");
    //暴力反射
    function.setAccessible(true);
    function.invoke(obj);

输出示例:

public void reflect.demo2.Student.method1()
public void reflect.demo2.Student.method2(java.lang.String)
public java.lang.String reflect.demo2.Student.method3(java.lang.String,int)
public java.lang.String reflect.demo2.Student.toString()
public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
public final void java.lang.Object.wait() throws java.lang.InterruptedException
public boolean java.lang.Object.equals(java.lang.Object)
public native int java.lang.Object.hashCode()
public final native java.lang.Class java.lang.Object.getClass()
public final native void java.lang.Object.notify()
public final native void java.lang.Object.notifyAll()
------------
public void reflect.demo2.Student.method1()
public void reflect.demo2.Student.method2(java.lang.String)
public java.lang.String reflect.demo2.Student.method3(java.lang.String,int)
public java.lang.String reflect.demo2.Student.toString()
private void reflect.demo2.Student.function()
------------
method
------------
method: 林青霞
------------
林青霞,30
------------
function

使用反射越过泛型检查

Q:有一个ArraryList<Integer>集合,在这个集合中添加一个字符串数据,如何实现?

示例

    ArrayList<Integer> array = new ArrayList<>();
    //array.add("hello"); //编译不通过
    Class<? extends ArrayList> clazz = array.getClass();
    //调用add方法
    Method method = clazz.getMethod("add", Object.class);
    method.invoke(array, "hello");
    method.invoke(array, "world");
    method.invoke(array, "123");
    System.out.println(array);  //[hello, world, 123]

使用配置文件来进行反射

示例
class.txt

className=reflect.demo6.Teacher
methodName=teach

使用配置文件进行反射

    //加载配置文件
    Properties properties = new Properties();
    FileReader fileReader = new FileReader("src/main/java/reflect/demo6/class.txt");
    properties.load(fileReader);
    fileReader.close();

    //获取类路径和方法名
    String className = properties.getProperty("className");
    String methodName = properties.getProperty("methodName");

    Class<?> clazz = Class.forName(className);
    //构造方法实例化对象
    Constructor<?> constructor = clazz.getConstructor();
    Object obj = constructor.newInstance();
    //获得方法
    Method method = clazz.getMethod(methodName);

    //调用方法
    method.invoke(obj);

Spring中@AutoWired的反射示例

示例
UserController:

//  @AutoWired
  private UserService userService;

  public UserService getUserService()
  {
    return userService;
  }

  public void setUserService(UserService userService)
  {
    this.userService = userService;
  }

使用反射进行实例化:

    UserController userController = new UserController();
    System.out.println(userController.getUserService());  //null
    UserService userService = new UserService();
    //获取class对象
    Class<? extends UserController> clazz = userController.getClass();
    //获取全部变量
    Field[] declaredFields = clazz.getDeclaredFields();
    //获取变量名称(当前只有一个对象)
    String name = declaredFields[0].getName();
    //构造set方法名
    String methodName = "set" + name.substring(0, 1).toUpperCase() + name.substring(1);
    //获取方法
    Method setUserService = clazz.getMethod(methodName, UserService.class);
    //反射,初始化了userService
    setUserService.invoke(userController, userService);
    //顺利得到方法:reflect.demo7.UserService@7921b0a2
    System.out.println(userController.getUserService());

Student类

public class Student
{
  //成员变量:一个私有 一个默认 一个公共
  private String name;
  int age;
  public String address;

  //构造方法: 一个私有 一个默认 两个公共
  public Student()
  {
  }

  private Student(String name)
  {
    this.name = name;
  }

  Student(String name, int age)
  {
    this.name = name;
    this.age = age;
  }

  public Student(String name, int age, String address)
  {
    this.name = name;
    this.age = age;
    this.address = address;
  }

  //成员方法:一个私有 四个公共
  private void function()
  {
    System.out.println("function");
  }

  public void method1()
  {
    System.out.println("method");
  }

  public void method2(String s)
  {
    System.out.println("method: " + s);
  }

  public String method3(String s,int i)
  {
    return s + "," + i;
  }

  @Override
  public String toString()
  {
    return "Student:{" + "name:" + name + "-age:" + age + "-address:" + address + "}";
  }
}

项目源码

链接: 传送门

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值