Java高级-反射

反射

  • 1.介绍
  • 2.获取Class对象的三种方法
  • 3.获取类的构造器
  • 4.获取类的成员变量
  • 5.获取类的成员方法
  • 6.反射的作用和应用场景

1.介绍

反射

  • 加载类,并允许以编程的方式解剖类的各种成分(成员变量、方法、构造器等)

反射步骤

  • 1.加载类,获取类的字节码:Class对象
  • 2.获取类的构造器:Constructor对象
  • 3.获取类的成员变量:Field对象
  • 4.获取类的成员方法:Method对象

2.获取Class对象的三种方法

获取Class对象的三种方法

  • Class c1 = 类名.class
  • 调用Class的方法: public static Class forName(String package);
  • Object提供的方法:public Class getClass(); Class c3 = 对象.getClass;
public class Test1Class {
    public static void main(String[] args) throws ClassNotFoundException {
        // 第一种
        Class c1 = Student.class;
        System.out.println(c1.getName()); // 全类名 advanced.reflex.Student
        System.out.println(c1.getSimpleName()); // 类名 Student

        // 第二种
        Class<?> c2 = Class.forName("advanced.reflex.Student");

        // 第三种
        Student s = new Student();
        Class<? extends Student> c3 = s.getClass();
        System.out.println(c3 == c2);
    }
}

3.获取类的构造器

  • getDeclaredConstructors (推荐)
  • getDeclaredConstructor (推荐)
  • 不建议在反射中加泛型,为了通用性
    Java高级-反射_第1张图片
/**
 * 目标:获取类的构造器,并对其进行操作
 */
public class Test2Constructor {

    @Test
    public void testGetConstructors() {
        // 1.必须先得到类的class对象
        Class<Cat> catClass = Cat.class;
        // 2.获取类的全部构造器
		// Constructor[] constructors = catClass.getConstructors();
        Constructor[] constructors = catClass.getDeclaredConstructors();
        // 3.遍历数组的中构造器对象
        for (Constructor constructor : constructors) {
            System.out.println(constructor.getName() + "--->" + constructor.getParameterCount());
        }
    }

    @Test
    public void testGetConstructor() throws NoSuchMethodException {
        // 1.必须先得到类的class对象
        Class<Cat> catClass = Cat.class;
        // 2.获取类的某个构造器
		// Constructor constructor = catClass.getConstructor();
        Constructor<Cat> constructor = catClass.getDeclaredConstructor();
        System.out.println(constructor.getName() + "--->" + constructor.getParameterCount());

        // 3.获取有参的构造器
        Constructor<Cat> constructor2 = catClass.getDeclaredConstructor(String.class, int.class);
        System.out.println(constructor2.getName() + "--->" + constructor2.getParameterCount());
    }
}

获取类构造器的作用
获取类构造器的作用:依然是初始化对象返回
在这里插入图片描述

@Test
public voidtestGetConstructor() throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
    // 1.必须先得到类的class对象
    Class<Cat> catClass = Cat.class;
    // 2.获取类的某个构造器
    Constructor constructor = catClass.getDeclaredConstructor();
    constructor.setAccessible(true);
    Cat cat = (Cat) constructor.newInstance();
    System.out.println(cat);

    // 3.获取有参的构造器
    Constructor constructor2 = catClass.getDeclaredConstructor(String.class, int.class);
    constructor2.setAccessible(true);
    Cat cat2 = (Cat) constructor2.newInstance("叮当猫", 12);
    System.out.println(cat2);
}

4.获取类的成员变量

Java高级-反射_第2张图片

public class Cat {
    private static int a;
    public static final String COUNTRY = "中国";
    private String name;
    private int age;
}
@Test
public void getGetFields() throws NoSuchFieldException {
    // 1.获取Class对象
    Class catClass = Cat.class;
    // 2.获取类的全部成员变量
    Field[] fields = catClass.getDeclaredFields();
    // 3.遍历成员变量数组
    for (Field field : fields) {
        System.out.println(field.getName() + "---" + field.getType());
    }

    // 4.定位某个成员变量
    Field fName = catClass.getDeclaredField("name");
    System.out.println(fName.getName() + "-->" + fName.getType());

    Field fAge = catClass.getDeclaredField("age");
    System.out.println(fAge.getName() + "-->" + fAge.getType());
}

获取成员变量的作用
获取成员变量的作用:赋值和取值
Java高级-反射_第3张图片

@Test
public void getGetFields() throws Exception {
    // 1.获取Class对象
    Class catClass = Cat.class;
    // 2.定位某个成员变量
    Field fName = catClass.getDeclaredField("name");
    System.out.println(fName.getName() + "-->" + fName.getType());
    
    // 赋值
    Cat cat = new Cat();
    fName.setAccessible(true);
    fName.set(cat, "加菲猫");
    System.out.println(cat);

    // 取值
    String name = (String) fName.get(cat);
    System.out.println("name = " + name);
}

5.获取类的成员方法

Java高级-反射_第4张图片

private void run() {
   System.out.println("猫跑的很快");
}

private void eat() {
    System.out.println("猫爱吃猫粮");
}
private String eat(String name) {
    return "猫爱吃" + name;
}
@Test
public void testGetMethods() throws Exception {
    // 1.获得Class对象
    Class catClass = Cat.class;
    // 2.获取类的全部成员方法
    Method[] methods = catClass.getDeclaredMethods();
    // 3.遍历
    for (Method method : methods) {
        System.out.println(method.getName() + "---" +
                method.getParameterCount() + "---" +
                method.getReturnType());
    }

    // 4.获取某个方法对象
    Method run = catClass.getDeclaredMethod("run");
    System.out.println(run.getName() + "---" +
            run.getParameterCount() + "---" +
            run.getReturnType());

    Method eat = catClass.getDeclaredMethod("eat", String.class);
    System.out.println(eat.getName() + "---" +
            eat.getParameterCount() + "---" +
            eat.getReturnType());
}

获取成员方法的作用
获取成员方法的作用:执行此方法在这里插入图片描述

@Test
public void testGetMethods() throws Exception {
    // 1.获得Class对象
    Class catClass = Cat.class;
    // 2.获取某个方法对象
    Method run = catClass.getDeclaredMethod("run");
    Method eat = catClass.getDeclaredMethod("eat", String.class);

    // 执行方法
    Cat cat = new Cat();
    run.setAccessible(true);
    Object rs = run.invoke(cat);// 调用无参数的run方法,用cat对象触发调用
    System.out.println("rs = " + rs);
    
    eat.setAccessible(true);
    rs = eat.invoke(cat, "火腿肠");
    System.out.println("rs = " + rs);
}

6.反射的作用和应用场景

反射的作用

  • 基本作用:可以得到一个类的全部成分然后操作
  • 可以破坏封装性
  • 最重要的用途:适合做Java的框架

案例:使用反射做一个简易版的框架
需求:

  • 对于任意一个对象,该框架都可以把对象的字段名和对应的值,保存到文件中去

实现步骤

  • 1.定义一个方法,可以接收任意对象
  • 2.每收到一个对象后,使用反射获取该对象的Class对象,然后获取全部的成员变量
  • 3.遍历成员变量,然后提取成员变量在该对象中的具体值
  • 4.把成员变量名、值,写出到文件中去即可
public class Student {
    private String name;
    private char sex;
    private int age;
    private double height;
    private String hobby;
}

public class Teacher {
    private String name;
    private double salary;
}
/**
 * 使用反射技术,设计一个保存对象的简易版框架
 */
public class Test5Frame {
    @Test
    public void save() throws Exception{
        Student s1 = new Student("吴彦祖", '男', 45, 185.3, "乒乓球");
        Teacher t1 = new Teacher("黄子韬", 999.9);

        // 需求:任意一个对象,该框架都可以把对象的字段名和对应的值,保存到文件中去
        ObjectFrame.saveObject(s1);
        ObjectFrame.saveObject(t1);
    }
}
/**
 * 保存任意对象的字段和数据到文件中去
 */
public class ObjectFrame {

    public static void saveObject(Object obj) throws Exception {
        PrintStream ps = new PrintStream(new FileOutputStream("F:\\Code\\JetBrains-Work\\Java\\2022study\\src\\advanced\\reflex\\data.txt", true));
        // obj是任意对象,到底有多少个字段要保存
        Class c = obj.getClass();
        String cName = c.getSimpleName();
        ps.println("-------------------" + cName + "-------------------");
        // 2.从该类中提取全部成员变量
        Field[] fields = c.getDeclaredFields();
        // 3.变量每个成员变量
        for (Field field : fields) {
            // 4.拿到成员变量的名字
            String name = field.getName();
            // 5.拿到这个成员变量在该对象的值
            field.setAccessible(true);
            String value = field.get(obj).toString();
            ps.println(name + "=" + value);
        }
        ps.close();
    }
}

你可能感兴趣的:(java)