java 反射

反射的概述

反射是一个非常重要的知识点,它是动态语言的关键。
动态语言就是不写死,而是根据程序的具体执行情况做出不同的变化。

反射概念很抽象
日常生活中的反射:照镜子可以反射物体的形态,镜子中可以看到实物的虚像,假说我们从镜子中看天空,我们则可以从镜中看到取天空的颜色,云彩等。

程序中的反射是通过某些信息(对象、类名 “java.lang.String”)可以映射到类,在程序运行期间获取类的相关信息。

反射的工作都是在程序运行期间进行的
反射具体操作简单来说就是在程序运行期间,动态获取类的信息,从而完成某些操作。常规情况下,是通过类创建对象,反射就是将其进行反转,通过对象来获取类的信息。

Class 类

Class 类是反射的源头,反射就是获取某些类的信息,抽象出一个对象来表示类的信息。
Class 就是用来创建这些对象的类(用来表示 反射获取的类的信息)。
Class 的实例化对象是专门用来描述其他类,Class 是专门用来描述其他类的类。
如何获取 Class 的实例化对象
一共有 3 种方式,都跟目标类有关系。

    public static void main(String[] args) {
        try {
//         1、   通过类名获取
            Class clazz = Class.forName("java.lang.String");
            System.out.println(clazz);
//            拿到接口
            Class<?> clazz1 = Class.forName("java.io.Serializable");
            System.out.println(clazz1);
//         2、   类字面量获取
            Class clazz2 = String.class;
            System.out.println(clazz2);

//         3、通过实例化对象获取
            String str = new String();
            Class clazz3 = str.getClass();
            System.out.println(clazz3);
            /**
             * 三种方式获取的对象都是同一个对象
             *
             */
            System.out.println(clazz == clazz2);
            System.out.println(clazz2 == clazz3);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

获取类的结构

这里我们创建一个User类

public class User {
    private Integer id;
    private String name;
    private Integer age;

    public User(Integer id, String name, Integer age) {
        this.id = id;
        this.name = name;
        this.age = age;
    }

    public User(Integer id) {
        this.id = id;
    }

    public Integer getId() {
        return id;
    }

    public String getName() {
        return name;
    }

    public Integer getAge() {
        return age;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setAge(Integer age) {
        this.age = age;
    }
}

这里我添加了三个构造器

    public static void main(String[] args) {
//        通过字面量获取目标类
        Class clazz = User.class;

/**
 * Constructor 是 Java 反射包提供的一个类,
 * 它的作用是专门用来描述其他类的构造器的,
 * 一个 Constructor 实例化对象映射的就是某个类的某个构造函数。
  */
        Constructor[] constructors = clazz.getConstructors();
//        遍历输出拿到的构造
        for (Constructor constructor : constructors) {
            System.out.println(constructor);
        }
    }

结果:
在这里插入图片描述
除了通过上面的获取类所有的构造器,也可以单个获取

        try {
//            无参构造
            Constructor constructor = clazz.getConstructor();
            System.out.println(constructor);
//            有参构造
            Constructor constructor1 = clazz.getConstructor(Integer.class);
            System.out.println(constructor1);
            Constructor constructor2 = clazz.getConstructor(Integer.class,String.class,Integer.class);
            System.out.println(constructor2);

        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }

获取接口

在User类上继承接口

public class User implements Serializable,MyInterface {
...
}
    public static void main(String[] args) {
        Class clazz = User.class;
//        将拿到的接口放入数组
        Class[] interfaces = clazz.getInterfaces();
//        遍历输出
        for (Class anInterface : interfaces) {
            System.out.println(anInterface);
        }
    }

结果:
在这里插入图片描述

获取属性(成员变量)

getFields() : 获取的是类中的公有成员变量(包括从父类继承过来的公有成员变量),public 修饰的

getDeclaredFields() : 获取的是类中全部成员变量(跟修饰无关,但是不包含父类中的成员变量)

getField(String name): 根据名称获取公有成员变量(包含父类继承过来的)

getDeclaredField(String name): 根据名称获取成员变量(不包含父类继承过来的)

创建一个父类Person

public class Person {
    public String gender;
}

子类继承父类

public class User extends Person implements Serializable,MyInterface {
private Integer id;
    private String name;
    public Integer age;
    public String hobby;
....
}
 public static void main(String[] args) {
        System.out.println("getFields()方法");
        Class clazz = User.class;
        Field[] fields = clazz.getFields();
        for (Field field : fields) {
            System.out.println(field);
        }
        System.out.println("------------------------------------------------");
        System.out.println("getDeclaredFields() 方法");
        Field[] declaredFields = clazz.getDeclaredFields();
        for (Field declaredField : declaredFields) {
            System.out.println(declaredField);
        }
        System.out.println("------------------------------------------------");
        System.out.println("getField(String name) 方法");
        try {
            Field age = clazz.getField("age");
            System.out.println(age);
            Field hobby = clazz.getField("hobby");
            System.out.println(hobby);
//            父类的公有成员变量
            Field gender = clazz.getField("gender");
            System.out.println(gender);

        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }
/**
 * getDeclaredField(String name) 同上,取本类的所有成员变量,无关权限修饰符。
 */

    }

结果:
在这里插入图片描述
获取属性后,我们可以通过反射给是属性赋值、取值。当然给属性赋值,取值的前提是有这个对象。

 Class clazz = User.class;
try {
            Field id= clazz.getDeclaredField("id");
            //通过反射拿到无参构造
            Constructor<User> constructor = clazz.getConstructro(null);
            User user = constructor.newInstance(null);
            //如果类里的成员变量访问权限为公有,可通过直接赋值,取值。如果是私有的成员变量则需 加上 id.setAccessible(true); 后再赋值 ,取值 (暴力反射)
            id.set(user,1);
            //Object o = id.get(user);
        } catch (Exception e) {
            e.printStackTrace();
        }

获取方法

public class Test2 {
    public static void main(String[] args) {
        Class clazz = User.class;
        Method[] methods = clazz.getMethods();
        for (Method method : methods) {
            System.out.println(method);
        }
    }
}

getMethods 方法获取目标类中的所有公有方法,包含从父类继承过来的公有方法。

Method[] declaredMethods = clazz.getDeclaredMethods();
for (Method declaredMethod : declaredMethods) {
    System.out.println(declaredMethod);
}

getDeclaredMethods 方法获取目标类中的所有方法,不包含从父类继承过来的方法。

通过反射调用方法

 public static void main(String[] args) throws Exception {
        Class clazz = User.class;
        Method getId = clazz.getDeclaredMethod("getId", null);
        //通过反射创建对象
        User user = (User) clazz.getConstructor(null).newInstance(null);
        //赋值 调用set方法
        Method setId = clazz.getMethod("setId", Integer.class);
        setId.invoke(user, 22);
        //取值
        System.out.println(getId.invoke(user, null));
    }

反射机制在实际开发中最主要的三个应用构造器、方法、成员变量。

Spring 框架,IoC 容器,自动创建对象,不需要开发者手动创建对象,程序根据配置文件自动生成程序需要的各种对象。

1、通过构造器创建对象

2、给对象的属性赋值

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值