反射的概念 和基本使用(一)

1 反射

什么是反射

java反射 是指在运行状态中 对于任意一个类 我们都可以知到这个类的所有方法和属性 也可以调用其所有的方法和属性 这种动态获取的方式 我们称为 反射

什么是class对象

我们通过使用反射 就是通过Class类来实现的 Class 类的实例表示正在运行的 Java 应用程序中的类和接口。

也就是jvm中有N多的实例每个类都有该Class对象。(包括基本数据类型)

反射的使用

获取class对象的三种方式

基本类
/**
 *
 * @author : look-word
 * @date : 2022-04-05 20:49
 **/
public class Student {
    private String username;
    private String gender;

    public  String getInfo() {
        this.setUsername("张三");
        this.setGender("男");
        return this.username+"="+this.gender;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getGender() {
        return gender;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }
}
测试代码如下
/**
 * @author : look-word
 * @date : 2022-04-05 20:54
 **/
public class Test {
    public static void main(String[] args) {

        /*
            1 创建对象 获取其class对象
         */
        Student student = new Student();
        Class<? extends Student> aClass = student.getClass();
        System.out.println(aClass.getSimpleName());
        /*
            2 任何数据类型(包括基本数据类型)都有一个“静态”的class属性
         */
        Class<? extends Student> bClass=Student.class;
        System.out.println(aClass == bClass?"两者是同一对象":"两者不是同一对象");
        /*
            3 通过Class类的forName方法获取
         */
        try {
            //  Class.forName(类的相对路径)
            Class<?> cClass = Class.forName("bean.Student");
            System.out.println(bClass == cClass?"两者是同一对象":"两者不是同一对象");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}
结果如下

证明

在运行期间 一个类只有一个class对象的产生

常用的是第三次 清晰 明了 因为 在一个项目中 可能会产生 相同名字的类

解决疑惑 为什么要是用 第三种

第一种对象都有了还要反射干什么。

第二种需要导入类的包,依赖太强,不导包就抛编译错误。

第三种,一个字符串可以传入也可写在配置文件中等多种方法。

获取Class类中的所有构造方法

基本类
public class Student {
    //---------------构造方法-------------------
    //(默认的构造方法)
    Student(String str){
        System.out.println("(默认)的构造方法 s = " + str);
    }

    //无参构造方法
    public Student(){
        System.out.println("调用了公有、无参构造方法执行了。。。");
    }

    //有一个参数的构造方法
    public Student(char name){
        System.out.println("姓名:" + name);
    }

    //有多个参数的构造方法
    public Student(String name ,int age){
        System.out.println("姓名:"+name+" 年龄:"+ age);//这的执行效率有问题,以后解决。
    }

    //受保护的构造方法
    protected Student(boolean n){
        System.out.println("受保护的构造方法 n = " + n);
    }

    //私有构造方法
    private Student(int age){
        System.out.println("私有的构造方法   年龄:"+ age);
    }
}
测试代码
/**
 * 测试构造方法
 * @author : look-word
 * @date : 2022-04-05 21:18
 **/
public class TestConstructor {

/**
 * 通过Class对象可以获取某个类中的:构造方法、成员变量、成员方法;并访问成员;
 *
 * 1.获取构造方法:
 * 		1).批量的方法:
 * 			public Constructor[] getConstructors():所有"公有的"构造方法
            public Constructor[] getDeclaredConstructors():获取所有的构造方法(包括私有、受保护、默认、公有)

 * 		2).获取单个的方法,并调用:
 * 			public Constructor getConstructor(Class... parameterTypes):获取单个的"公有的"构造方法:
 * 			public Constructor getDeclaredConstructor(Class... parameterTypes):获取"某个构造方法"可以是私有的,或受保护、默认、公有;
 *
 * 			调用构造方法:
 * 			Constructor-->newInstance(Object... initargs)
*/
    public static void main(String[] args) throws Exception {
        Class<?> student = Class.forName("bean.Student");
        /*
            1 获取所有共有的构造方法
         */
        System.out.println("\n1 获取所有共有的构造方法");
        Constructor<?>[] constructors = student.getConstructors();
        for (Constructor<?> constructor : constructors) {
            System.out.println(constructor);
        }

        /*
            2 获取共有的无参构造方法 可以写 null 或者 不填
         */
        System.out.println("\n2 获取共有的无参构造方法 可以写 null 或者 不填");
        Constructor<?> constructor2 = student.getConstructor();
        constructor2.newInstance();

        /*
            3 获取 给定参数共有的构造方法 public bean.Student(java.lang.String,int)
         */
        System.out.println("\n 3 获取 给定参数共有的构造方法 public bean.Student(java.lang.String,int)");
        Constructor<?> constructor3 = student.getConstructor(String.class, int.class);
        constructor3.newInstance("张三",19);

        /*
            4 获取 私有给定参数的构造方法 私有 不给定参数 不传参数即可
         */
        Constructor<?> constructor4 = student.getDeclaredConstructor(int.class);
        /*
            获取私有的属性 或者构造方法是 需要 设置无障碍 俗称 暴力访问
            不设置 会出异常 java.lang.IllegalAccessException
         */
        constructor4.setAccessible(true);
        constructor4.newInstance(19);
    }
}

执行结果

注意

获取私有属性的时候 一定要设置无障碍

setAccessible(true);

不设置 会出异常 java.lang.IllegalAccessException

newInstance(Object… initargs) 创建一个新实例
使用此 Constructor 对象表示的构造方法来创建该构造方法的声明类的新实例,并用指定的初始化参数初始化该实例。

每次是用 newInstance创建的对象 都是不同的对象 代表不同的实例

操作成员变量

基本类
 
public class Student {
	public Student(){
		
	}
	//**********字段*************//
	public String name;
	protected int age;
	char sex;
	private String phoneNum;
	
	@Override
	public String toString() {
		return "Student [name=" + name + ", age=" + age + ", sex=" + sex
				+ ", phoneNum=" + phoneNum + "]";
	}
}
测试代码
/**
 * @author : look-word
 * @date : 2022-04-05 21:55
 **/
public class TestField {

/*
 * 获取成员变量并调用:
 *
 * 1.批量的
 * 		1).Field[] getFields():获取所有的"公有字段"
 * 		2).Field[] getDeclaredFields():获取所有字段,包括:私有、受保护、默认、公有;
 * 2.获取单个的:
 * 		1).public Field getField(String fieldName):获取某个"公有的"字段;
 * 		2).public Field getDeclaredField(String fieldName):获取某个字段(可以是私有的)
 *
 * 	 设置字段的值:
 * 		Field --> public void set(Object obj,Object value):
 * 					参数说明:
 * 					1.obj:要设置的字段所在的对象;
 * 					2.value:要为字段设置的值;
*/
    public static void main(String[] args) throws Exception{
        Class<?> aClass = Class.forName("bean.Student");
        Student student = new Student();

        /*
            获取所有的共有字段
         */
        System.out.println("-------------------获取所有的共有字段--------------------");
        Field[] fields = aClass.getFields();
        for (Field field : fields) {
            /*
                filed => public java.lang.String bean.Student.username
                filed => 成员变量
             */

            /*
               我理解为 给某个对象的 成员变量 赋值
               当前的filed 为 username 因为这里只能获取为 共有属性的成员变量
             * field.set(student,"zhangsan");
             */
            field.set(student,"zhangsan");
            System.out.println(student);
            /*
                field.get(student);
                获取某student中的 field 的 内容
             */
            Object o = field.get(student);
            System.out.println(o);
            /*
             *  打印filed的内容 => public java.lang.String bean.Student.username
             */
            System.out.println(field);
        }

        System.out.println("-------------------给私有字段赋值--------------------");
        Field phone = aClass.getDeclaredField("phone");
        phone.setAccessible(true);// 设置无障碍 
        phone.set(student,"110");// 赋值给student对象

        System.out.println("-------------------获取私有字段--------------------");
        Field phone1 = aClass.getDeclaredField("phone");
        phone1.setAccessible(true);// 设置无障碍
        System.out.println(phone1.get(student));//取出student对象中的phone属性的值
    }
}
注意

在操作私有属性的时候 不管是获取还是设置值 都需要设置无障碍

setAccessible(true);// 设置无障碍

Tags: