4

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

 2 years ago
source link: https://www.cnblogs.com/look-word/p/16104362.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

什么是反射

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);// 设置无障碍


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK