关于反射的简单认识


重要前言:Java的重要思想就是万物皆对象。

关于反射学习篇一

反射理解

注:反射(Reflection)
反射就是加载类,并允许以编程的方式 解剖类中的各种成分(成员变量成员方法构造器等);

反射可以用来做框架的。

 
在这里插入图片描述
 

学习要点

学习如何获取类的信息,并对它们进行操作。

  
在这里插入图片描述
  

三种获取Class对象方式

  
在这里插入图片描述
  

作用是获取类

也是实现反射的第一步,获取Class类就是获取对应的字节码文件,就是获取到对应的类,然后继续通过此类获取到 对应的 构造器成员变量成员方法;然后进行一定操作;Class类对象代表了类。

案例

导入依赖

注:简化代码

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.20</version>
</dependency>
创建对象模板类

Student类

package com.xie.reflect02.test.obj;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Student {
    private String name;
    private int age;
    private char sex;
    private double height;
    private String hobby;

    public Student(String name) {
        this.name = name;
    }
}
测试

测试类(Test1Class)

package com.xie.reflect02.test;

import com.xie.reflect02.test.obj.Student;
import org.junit.Test;

/**
 * 目标:获取Class对象
 * */
public class Test1Class {

    /**
     * 通过第一种方式
     * */
    @Test
    public void testGetClass1() {
        Class c = Student.class;
        // 获取类的全类名
        System.out.println(c.getName());
        // 获取类的简名
        System.out.println(c.getSimpleName());
    }

    /**
     * 通过第二种方式 调用Class对象提供的forName()方法,方法内部需要传参,传一个全类名
     * */
    @Test
    public void testGetClass2() throws ClassNotFoundException {
        Class c = Class.forName("com.xie.reflect02.test.obj.Student");
        // 获取类的全类名
        System.out.println(c.getName());
        // 获取类的简名
        System.out.println(c.getSimpleName());
    }

    /**
     * 不用单元测试,直接用main方法进行,判断通过三种方式获取到的是否是同一个对象
     * */
    public static void main(String[] args) throws Exception {
        // 根据模板类,创建对应对象,并初始化对象中的其中一个字段name
        Student s = new Student("小明");
        // 获取Class对象
        Class c1 = Student.class;
        Class c2 = Class.forName("com.xie.reflect02.test.obj.Student");
        Class c3 = s.getClass();
        // 打印判断,观察
        System.out.println(c1 == c2);
        System.out.println(c2 == c3);
    }
}

总的认识

反射作用

  1. 基本作用:可以得到一个类的全部成分然后操作。

  2. 可以破坏封装性

  3. 最重要的用途是:适合做]ava的框架,基本上,主流的框架都会基于反射设计出一些通用的功能。

  
在这里插入图片描述
  

一,获取构造器

  
在这里插入图片描述
  

构造器应用案例

导入依赖

作用:maven项目—>简化代码

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.20</version>
</dependency>

创建对象模板类

Cat类

package com.xie.reflect02.test.obj;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Cat {
    private String name;
    private int age;

    private Cat(String name) {
        this.name = name;
        System.out.println("私有有参构造器name参数的执行了!!!");
    }

    public Cat(int age) {
        this.age = age;
        System.out.println("有参构造器int参数的执行了!!!");
    }
}

测试

测试类(Test2Contructor)

package com.xie.reflect02.test;

import com.xie.reflect02.test.obj.Cat;
import org.junit.Test;

import java.lang.reflect.Constructor;

/**
 * 目标:掌握获取类的构造器,并对其进行操作。
 * */
public class Test2Contructor {

    /**
     * 获取public修饰的构造方法(构造器),获取全部构造器
     * */
    @Test
    public void testGetContructors() {
        // 1,反射第一步:必须先得到这个类的Class对象
        Class c = Cat.class;
        // 2,获取类的全部构造器
        Constructor[] constructors = c.getConstructors();
        // 3,遍历该数组,得到每一个构造器
        for (Constructor constructor : constructors) {
            // 打印构造器的名字(全类名)及构造参数的数量
            System.out.println(constructor.getName() + "--->" + constructor.getParameterCount());
        }
    }

    /**
     * 同时获取private修饰的构造方法(构造器),获取全部构造器
     *
     * 开发中常用此种方式获取构造器
     * */
    @Test
    public void testGetContructors2() {
        // 1,反射第一步:必须先得到这个类的Class对象
        Class c = Cat.class;
        // 2,获取类的全部构造器
        Constructor[] constructors = c.getDeclaredConstructors();
        // 3,遍历该数组,得到每一个构造器
        for (Constructor constructor : constructors) {
            // 打印构造器的名字(全类名)及构造参数的数量
            System.out.println(constructor.getName() + "--->" + constructor.getParameterCount());
        }
    }

    /**
     * 获取public修饰的构造方法(构造器)
     *
     * 获取指定参数的构造器,即获取某个构造器
     * */
    @Test
    public void testGetContructor() throws Exception {
        // 1,反射第一步:必须先得到这个类的Class对象
        Class c = Cat.class;
        // 2,获取某个构造器:无参构造器
        Constructor constructor = c.getConstructor();
        // 3,// 打印构造器的名字(全类名)及构造参数的数量
        System.out.println(constructor.getName()+"--->"+constructor.getParameterCount());
    }

    /**
     * 获取指定参数的构造器,即获取某个构造器
     *
     * 同时获取private修饰的构造方法(构造器),开发中常用此种方式获取
     * */
    @Test
    public void testGetContructor2() throws Exception {
        // 1,反射第一步:必须先得到这个类的Class对象
        Class c = Cat.class;
        // 2,获取某个构造器:单参构造器(这里指的是Cat类中的name参数 与 int参数)
        Constructor constructor = c.getDeclaredConstructor(String.class);
        Constructor constructor2 = c.getDeclaredConstructor(int.class);
        // 3,// 打印构造器的名字(全类名)及构造参数的数量
        System.out.println(constructor.getName()+"--->"+constructor.getParameterCount());
        System.out.println(constructor2.getName()+"--->"+constructor2.getParameterCount());
        // 禁止检查--->访问权限
        constructor.setAccessible(true);
        // 初始化对象,然后进行返回
        Cat cat1 = (Cat) constructor.newInstance("叮当猫");
        Cat cat2 = (Cat) constructor2.newInstance(3);
        System.out.println(cat1);
        System.out.println("--------------------------------");
        System.out.println(cat2);
    }
}

获取的类构造器的作用

获取类构造器的作用:依然是初始化一个对象返回

二,获取成员变量

  
在这里插入图片描述
  

成员变量应用案例

导入依赖

注:简化代码

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.20</version>
</dependency>

创建对象模板类

Cat类

package com.xie.reflect02.test.obj;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Cat {
    public static int a;
    public static final String country = "中国";
    private String name;
    private int age;

    public Cat(String name) {
        this.name = name;
        System.out.println("有参构造器name参数的执行了!!!");
    }

    public Cat(int age) {
        this.age = age;
        System.out.println("有参构造器int参数的执行了!!!");
    }
}

测试

测试类(Test3Field)

package com.xie.reflect02.test;

import com.xie.reflect02.test.obj.Cat;
import org.junit.Test;

import java.lang.reflect.Field;

/**
 * 目标:掌握获取类的成员变量,并对其进行操作。
 * */
public class Test3Field {
    /**
     * 获取全部成员变量
     * */
    @Test
    public void testGetFields() {
        // 1,反射第一步:必须先得到类的Class对象
        Class c = Cat.class;
        // 2,获取类的全部成员变量。
        Field[] fields = c.getDeclaredFields();
        // 3,遍历这个成员的变量数组
        for (Field field : fields) {
            System.out.println(field.getName() + "--->" + field.getType());
        }
    }

    /**
     * 获取指定成员变量,即单个成员变量
     * */
    @Test
    public void testGetField() throws Exception {
        // 1,反射第一步:必须先得到类的Class对象
        Class c = Cat.class;
        Field name = c.getDeclaredField("name");
        System.out.println(name.getName() + "--->" + name.getType());
        Field age = c.getDeclaredField("age");
        System.out.println(age.getName() + "--->" + age.getType());
        System.out.println("---------------分隔符-----------------");
        Field a = c.getDeclaredField("a");
        System.out.println(a.getName() + "--->" + a.getType());
        Field country = c.getDeclaredField("country");
        System.out.println(country.getName() + "--->" + country.getType());

        // 赋值,赋值前提需要一个对象来接收,所以先创建一个Cat对象
        Cat cat = new Cat();
        // 在设值之前,执行暴力反射,禁止检查访问权限,使其通过检查的拦截
        name.setAccessible(true);
        name.set(cat, "咖啡猫");
        System.out.println("设值--->" + cat);
        // 取值
        String s = (String) name.get(cat);
        System.out.println("取值--->" + s);
    }
}

获取的成员变量的作用

获取类成员变量的作用:依然是赋值取值

三,获取成员方法

  
在这里插入图片描述
  

获取的成员方法的作用

获取类成员方法的作用:依然是执行此方法。

成员方法应用案例

导入依赖

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.20</version>
</dependency>

创建模板类对象

Cat类

package com.xie.reflect02.test.obj;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Cat {
    public static int a;
    public static final String country = "中国";
    private String name;
    private int age;

    public Cat(String name) {
        this.name = name;
        System.out.println("有参构造器name参数的执行了!!!");
    }

    public Cat(int age) {
        this.age = age;
        System.out.println("有参构造器int参数的执行了!!!");
    }

    /**
     * 成员方法
     * */
    private void run() {
        System.out.println("跑的贼快哈!!!");
    }

    public void eat() {
        System.out.println("非常爱吃鱼!!!");
    }

    private String eat(String name) {
        return "也爱吃猫粮!!!" + name;
    }
}

测试

测试类(Test4Method)

package com.xie.reflect02.test;

import com.xie.reflect02.test.obj.Cat;
import org.junit.Test;

import java.lang.reflect.Method;

/**
 * 目标: 掌握获取类的成员方法,并对其进行操作。
 * */
public class Test4Method {
    @Test
    public void testGetMethods() throws Exception {
        // 1,反射第一步:必须先得到类的Class对象
        Class c = Cat.class;
        // 2,获取类中的全部成员方法
        Method[] methods = c.getDeclaredMethods();
        // 3,遍历这个数组中的每个方法对象
        for (Method method : methods) {
            System.out.println(method.getName() + "--->" + method.getParameterCount() + "--->" + method.getReturnType());
        }
        System.out.println("----------------分隔符----------------");
        // 4,获取某个成员方法
        Method run = c.getDeclaredMethod("run");
        System.out.println(run.getName() + "--->" + run.getParameterCount() + "--->" + run.getReturnType());
        Method eat = c.getDeclaredMethod("eat", String.class);
        System.out.println(eat.getName() + "--->" + eat.getParameterCount() + "--->" + eat.getReturnType());

        System.out.println("----------------分隔符----------------");
        // 5,invoke()为触发方法,触发执行某个对象的该方法,执行方法的前提是要有该对象,然后再有该对象的方法,所以先创建一个Cat对象
        Cat cat = new Cat();
        //
        //调用无参数的run方法,用cat对象触发调用的
        run.setAccessible(true);
        eat.setAccessible(true);
        Object invoke1 = run.invoke(cat);
        String invoke2 = (String)eat.invoke(cat, " + 中国猫");
        System.out.println(invoke1+ "--->" + invoke2);
    }
}

简易框架制作案例

Maven依赖

注:简写代码之用

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.20</version>
</dependency>

创建对象模板类

Student类

package com.xie.reflect02.test;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Student {
    private String name;
    private int age;
    private char sex;
    private double height;
    private String hobby;
}

Teacher类

package com.xie.reflect02.test;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@AllArgsConstructor
@NoArgsConstructor
@Data
public class Teacher {
    private String name;
    private double salary;
}

制作框架

框架类(ObjectFrame)

package com.xie.reflect02;

import java.io.FileOutputStream;
import java.io.PrintStream;
import java.lang.reflect.Field;

/**
 * 简易框架,一个简单案例
* */
public class ObjectFrame {
    /**
      目标:保存任意对象的字段和其数据到指定文件中去
    * */
    public static void saveObject(Object obj) throws Exception {
        // 创建打印流,把需要保存内容打印到指定文件中去
        PrintStream ps = new PrintStream(new FileOutputStream("E:\\WorkStations\\JavaStation\\分点重点学习\\反射\\fanshe01\\data.txt", true));
        // obj是可以接收任意对象的
        Class c = obj.getClass();
        String simpleName = c.getSimpleName();
        ps.println("-------------------" + simpleName + "----------------------");
        // 从类中取出它的全部成员变量
        Field[] fields = c.getDeclaredFields();
        // 遍历每个成员变量
        for (Field field : fields) {
            // 禁止检查访问控制
            field.setAccessible(true);
            // 拿到成员变量的名字
            String name = field.getName();
            // 拿到该成员变量在对象中的数据
            //String value = (String) field.get(obj);
            String value = field.get(obj) + "";
            ps.println(name + "=" + value);
        }
        // 关闭流
        ps.close();
    }
}

测试

测试类(Test5Frame)

package com.xie.reflect02.test;

import com.xie.reflect02.ObjectFrame;
import org.junit.Test;

/**
 * 目标:利用反射技术,设计一个保存任意对象字段信息的简易版框架
 * */
public class Test5Frame {
    @Test
    public void save() throws Exception {
        // 测试方法可用性
        System.out.println("--666--");
        // 创建对象
        Student s1 = new Student("柳岩", 18 , '女',60, "唱歌");
        Teacher t1 = new Teacher("谢老师",12000);
        // 调用框架,进行保存对象信息操作
        ObjectFrame.saveObject(s1);
        ObjectFrame.saveObject(t1);
    }
}

备注

应用的时候记得多多注意各类的包的正确性此类包括第三方包的类及本类

参考视频

黑马磊哥

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

it-Mrxie-天

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值