Java基础-复习08-反射

一. 概述

Java基础-复习08-反射_第1张图片
类的加载器将 .class 文件字节码内容加载到内存中,并将这些静态数据转换成方法区的运行时数据结构,然后在堆中生成一个代表这个类的 java.lang.Class 对象,作为方法区中类数据的访问入口。一旦某个类被加载到类加载器中,它将维持加载(缓存)一段时间,不过JVM垃圾回收机制可以回收这些 Class 对象。

1. 什么是反射?

每个类都有一个 Class 对象,包含了与类有关的信息。当编译一个新类时,会产生一个同名的 .class 文件,该文件内容保存着 Class 对象。通过反射,可以在运行时动态地创建编译时未知的对象(编译期间该类的 .class 不存在),从而在运行时加载类、调用方法、访问属性(即使声明为 private)。
Java基础-复习08-反射_第2张图片

2. 反射的用途

反射最重要的用途就是开发各种通用框架。(框架 = 注解 + 反射 + 设计模式)
很多框架(比如 Spring)都是配置化的(比如通过XML 文件配置 Bean),为了保证框架的通用性,它们可能需要根据配置文件加载不同的对象或类,调用不同的方法,这个时候就必须用到反射,运行时动态加载需要加载的对象。

反射提供了以下功能:

  • 在运行时判断任意一个对象所属的类
  • 在运行时创建任意一个类的对象
  • 在运行时判断任意一个类所具有的属性和方法
  • 在运行时调用任意一个对象的属性和方法
  • 在运行时获取泛型、处理注解、生成动态代理

二. 运用反射

Class 和 java.lang.reflect 一起对反射提供了支持,java.lang.reflect 类库主要包括以下三个类:

  • Field:使用 get() 和 set() 方法读取和修改 Field 对象关联的字段
  • Method: 使用 invoke() 方法调用与 Method 对象关联的方法
  • Constructor:使用 Constructor 的 newInstance() 创建新对象

1. Class 类

Object 类中定义了被所有子类继承的 public final Class getClass() 方法
该方法返回的 Class 对象包含了被 getClass 对象的所有信息(属性、构造器、方法)

  • 一个加载的类在 JVM 中只会有一个 Class 实例
  • 一个 Class 对象对应一个加载到 JVM 中的一个 .class 文件
  • Class 类可以完整获取一个类中所有被加载的结构,它是反射的根源

获取 Class 对象

(1)对某个对象调用 getClass() 方法

Person p = new Person(); 
Class<? extends Person> cls1 = p.getClass();
System.out.println(cls1); //class com.xxx.java.Person

(2)直接调用类的 class 属性

Class<Person> cls2 = Person.class;
System.out.println(cls2); //class com.xxx.java.Person

(3)调用 Class 的静态 forName(String className) 方法

Class<?> cls3 = Class.forName("com.xxx.java.Person");
System.out.println(cls3); //class com.xxx.java.Person

(4)使用类加载器:ClassLoader (了解)

ClassLoader classLoader = this.class.getClassLoader();
Class<?> cls4 = classLoader.loadClass("com.xxx.java.Person");
System.out.println(cls4); //class com.xxx.java.Person

问题1:简单谈谈你对 Java 中 Class.forName()、Class.class、getClass() 三者的理解?

  • Class.class:JVM 使用类装载器将类装入内存,不做类的初始化工作
  • Class.forName():JVM 加载类并做类的静态初始化
  • obj.getClass():对类进行静态初始化、非静态初始化,返回obj引用运行时真正所指的对象

2. 常用方法

创建 Objetct 实例

使用 Class 的 newInstance() 方法创建 Class 对应类的实例

Class<?> c = String.class;
Object str = c.newInstance(); //调用了空参构造器

指定 Class 对应的构造器 ,对Constructor 使用 newInstance() 方法创建实例

Class<?> c = String.class;
Constructor con = c.getConstructor(String.class) //获取String类带String参数的构造器
Object obj = con.newInstance("创建带参实例"); //调用了带参构造器

获取方法调用方法

  • getDeclaredMethods:获取类和接口声明的所有方法,包括 private
  • getMethods:获取类的所有 public 方法
  • getMethod:获取类的一个特定方法,第一个参数为方法名,第二个参数为 Class 对象
package org.ScZyhSoft.common;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class test1 {
     
	public static void test() throws IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
     
	        Class<?> c = methodClass.class;
	        Object object = c.newInstance();
	        Method[] methods = c.getMethods();
	        Method[] declaredMethods = c.getDeclaredMethods();
	        //获取methodClass类的add方法
	        Method method = c.getMethod("add", int.class, int.class);
	        //getMethods()方法获取的所有方法
	        System.out.println("getMethods获取的方法:");
	        for(Method m:methods)
	            System.out.println(m);
	        //getDeclaredMethods()方法获取的所有方法
	        System.out.println("getDeclaredMethods获取的方法:");
	        for(Method m:declaredMethods)
	            System.out.println(m);
	    }
    }
class methodClass {
     
    public final int fuck = 3;
    public int add(int a,int b) {
     
        return a+b;
    }
    public int sub(int a,int b) {
     
        return a+b;
    }
}
  • 获取到方法后,使用 invoke() 方法调用获取到的方法,invoke() 方法定义如下:
public Object invoke(Object obj, Object... args)
        throws IllegalAccessException, IllegalArgumentException,InvocationTargetException
public class test1 {
     
    public static void main(String[] args) throws IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
     
        Class<?> klass = methodClass.class;
        //创建methodClass的实例
        Object obj = klass.newInstance();
        //获取methodClass类的add方法
        Method method = klass.getMethod("add",int.class,int.class);
        //调用method对应的方法 => add(1,4)
        Object result = method.invoke(obj,1,4);
        System.out.println(result);
    }
}
class methodClass {
     
    public final int fuck = 3;
    public int add(int a,int b) {
     
        return a+b;
    }
    public int sub(int a,int b) {
     
        return a+b;
    }
}

获取属性设置属性

  • getDeclaredField:获得某个类的所有字段,默认但是不包括父类声明的任何字段
  • getFileds:获得某个类的所有 public 的字段,包括继承自父类的所有公共字段
  • Field类提供的 set() 和 get() 方法完成设置和取得属性内容的操作
@Test
public void testField() throws Exception {
     
    Class clazz = Person.class;

    //创建运行时类的对象
    Person p = (Person) clazz.newInstance();

    //1. getDeclaredField(String fieldName):获取运行时类中指定变量名的属性
    Field name = clazz.getDeclaredField("name");

    //2.保证当前属性是可访问的
    name.setAccessible(true);
    //3.获取、设置指定对象的此属性值
    name.set(p,"Tom");

    System.out.println(name.get(p));
}

你可能感兴趣的:(Java基础)