Java - 反射机制 ,反射机制概念 ,Class类,Constructor类,Field类,Method类,AssessibleObject类,反射机制案例

第十二章、反射机制

场景:一般用在框架设计中、spring 框架。

ApplicationContext.xml -

反射机制:框架设计灵魂

反射的好处:代码通用性非常强

12.1、反射机制的概念

1、什么是反射?

框架设计:要求不修改代码的基础上,实现功能。不能有硬编码。

定义:

JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一

个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。

image

解读:

要想解剖一个类,必须先要获取到该类的字节码文件(class文件)对象。而解剖使用的就是Class类中的方法.所以先要获取到每一个字

节码文件对应的Class类型的对象.

总结:反射就是把java类中的各种成分映射成一个个的Java对象

例如:一个类有:成员变量、方法、构造方法、包等等信息,利用反射技术可以对一个类进行解剖,把个个组成部分映射成一个个对象。

加载的时候:Class对象的由来是将class文件读入内存,并为之创建一个Class对象。

一个类在JVM中只会有一个Class对象

图示:

image

12.2、Class类的概述

1、定义:

Class是一个类,封装了当前对象所对应的类的信息,比如:属性,方法,构造器等

万事万物皆对象,所以我们创建的每一个类也都是对象,即类本身是java.lang.Class类的实例对象

2、解读:

比如说有一个Person类,一个Order类,一个Book类,这些都是不同的类,现在需要一个类,用来描述类,这就是Class,它应该有类名,属性,方法,构造器等。

所以:Class是用来描述类的类

Class类是一个对象照镜子的结果,对象可以看到自己有哪些属性,方法,构造器,实现了哪些接口等等

反射之中包含了一个“反”的概念,所以要想解释反射就必须先从“正”开始解释,一般而言,当用户使用一个类的时候,应该先知道
这个类,而后通过这个类产生实例化对象,但是“反”指的是通过class对象找到类。

3、一个类的组成部分

属性 : Field

方法: Method

构造方法: Constructor

4、使用反射机制获取 Class 对象的3种方法

@Test
public void test04() throws ClassNotFoundException {
    //动态初始化
    //创建class对象 => 最重要
    //创建方式一: 硬编码
    Class<Emp> empClass = Emp.class;
    System.out.println(empClass);
    //创建方式二: 硬编码
    Emp emp = new Emp();
    Class<? extends Emp> aClass = emp.getClass();
    System.out.println(aClass);
    //说明一个类的class对象,在内存中只有1个!!!
    System.out.println("创建的2个class对象是同一个吗?"+(empClass==aClass));
    //创建方式三: 经常使用 ===> 通用性强
    Class<?> eClass = Class.forName("cn.kgc.bean.Emp");
    System.out.println(eClass);
}

5、与 Java 反射相关的类:

Class:表示类;

Field:表示成员变量;

Method:表示方法;

Constructor:表示构造器。

6、Class 类的常用方法

1)获取类名称,包含包名;

String			getName()
    			以 String 的形式返回此 Class 对象所表示的实体(类、接口、数组类、基本数据类型或 void)名称。

2)创建类的实例

T				newInstance()
    			创建此 Class 对象所表示的类的一个新实例。

3)根据类名返回类的 class 对象

static Class<?>				forName(String className)
    				返回与带有给定字符串名的类或接口相关联的 Class

4)获取 Constructor 对象

获取Construcator对象需要使用Class对象,下面API来自Class类:

1、通过指定的参数类型获取公有构造器反射对象

Constructor<T>			getConstructor(Class<?>... parameterTypes)
    					返回一个 Constructor 对象,它反映此 Class 对象所表示的类的指定公共构造方法。

2、获取所有公有构造器对象

Constructor<?>[]		getConstructors()
    					返回一个包含某些 Constructor 对象的数组,这些对象反映此 Class 对象所表示的类的所有公共构造方法。

5)获得 Field 的方法

注意:带有 Declared 修饰的方法可以反射到 私有的方法,没有 Declared 修饰的只能用来反射公有的方法。

1、通过名字获取公有成员变量的反射对象,包含父类中声明的公有成员变量

Field					getField(String name)
    					返回一个 Field 对象,它反映此 Class 对象所表示的类或接口的指定公共成员字段。

获取属性对象的语法:

Field 属性对象 = Class对象.getField("属性名");

2、获得所有公有的属性对象

Field[]					getFields()
    					返回一个包含某些 Field 对象的数组,这些对象反映此 Class 对象所表示的类或接口的所有可访问公共字段。

3、通过名字获取本类中某个成员变量,包含本类的 private 成员变量,但父类中声明的任何成员变量都不包含

Field					getDeclaredField(String name)
    					返回一个 Field 对象,该对象反映此 Class 对象所表示的类或接口的指定已声明字段。

4、获得所有属性对象

Field[]					getDeclaredFields()
    					返回 Field 对象的一个数组,这些对象反映此 Class 对象所表示的类或接口所声明的所有字段。

6)获得 Method 的方法

1、通过方法名和方法参数类型获取公共方法反射对象,包含父类中声明的公有方法,但不包含所有私有方法

Method					getMethod(String name, Class<?>... parameterTypes)
    					返回一个 Method 对象,它反映此 Class 对象所表示的类或接口的指定公共成员方法。
参数1:方法名
参数2:形参的 Class 类型

2、获得该类所有公有的方法

Method[]				getMethods()
    					返回一个包含某些 Method 对象的数组,这些对象反映此 Class 对象所表示的类或接口(包括哪些由该类或接口声明的以及从超类和超接口继承的那些的类或接口)的公共 member 方法。

3、通过方法名和方法参数类型获取本类中声明的方法的反射对象,包含本类中的私有方法,但不包含父类中的任何方法

Meethod					getDeclaredMethod(String name, Class<?>... parameterTypes)
    					返回一个 Method 对象,该对象反映此 Class 对象所表示的类或接口的指定已声明方法。

4、获得该类所有方法

Method[]				getDeclaredMethods()
    					返回 Method 对象的一个数组,这些对象反映此 Class 对象表示的类或接口声明的所有方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法。

7、Constructor 类常用方法

1、获取构造器名

String					getname()
    					以字符串形式返回此构造方法的名称。

2、通过构造器反射对象调用构造器

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

8、Field 类的常用方法

Field 代表类的成员变量(成员变量也称为类的属性)。

1)获得 obj 中对应的属性值

Object					get(Object obj)
    					返回指定对象上此 Field 表示的字段的值

2)设置 obj 中对应的属性值

void					set(Object obj, Object value)
    					将指定对象变量上此 Field 对象表示的字段设置为指定的新值。

设置/获取属性值的语法:

设置属性值语法:属性对象.set(实例化对象,值);
获取属性值语法:属性对象.get(实例化对象)

9、Method 类常用方法

Method 代表类的方法

1)传递 object 对象及参数调用该对象对应的方法

Object					invoke(Object obj, Object... args)
    					对带有指定参数的指定对象调用由此 Method 对象表示的底层方法。
参数1:实例化对象
参数2:可变实参列表

2)获取方法名

String					getName()
    					以 String 形式返回此 Method 对象表示的方法名称。

获取方法对象并且执行的语法:

//获取方法的对象
Method 方法对象 = Class对象.getMethod("方法名",数据类型的Class类型);
//执行方法
返回值类型 返回值 = 方法对象.invoke(实例化对象,实参列表);

10、AssessibleObject类

AssessibleObject 类是Constructor、Method、Field三个类的父类。

AssessibleObject 最为重要的方法如下:

1)判断当前成员是否可访问

boolean					isAssessible()
    					获取此对象的 accessible 标志的值

2)设置当前成员是否可访问

true :可以访问

false :不能访问

void					setAccessible(boolean flag)
    					将此对象的 accessible 标志设置为指示的布尔值。

注意:当 Constructor、Method、Field 为私有时,如果我们想反射操作,那么就必须先调用反射对象的 setAccessible(true) 方法,然后才能操作。

11、测试反射机制

public class MyRef {

    private String name;
    private char sex;
    private String address;
    public boolean isFlag;

    public MyRef() {
    }

    public MyRef(String name, char sex) {
        this.name = name;
        this.sex = sex;
    }

    public MyRef(String name, char sex, String address) {
        this.name = name;
        this.sex = sex;
        this.address = address;
    }

    public void showInfo(){
        System.out.println("我是MyRef类的showInfo()方法...");
    }

    public void print(){
        System.out.println(name + "," + sex + "," + address);
    }

    public boolean isOk(String email, int age){
        System.out.println(email + "," + age);
        return true;
    }

    private void pri_test(){
        System.out.println("这是一个私有的方法...");
    }
}
import org.junit.Test;

import java.io.FileReader;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Properties;

public class Test01 {
    @Test
    public void test01() throws Exception {
        //常用方式 1 :通过类的全路径名,来获取 class 对象
        //aClass:当前 MyRef 类的 class 对象
        Class<?> aClass = Class.forName("com.xunfang.wangc.demo.MyRef");
        //创建实例化对象
        Object obj = aClass.newInstance();
        MyRef myRef = (MyRef) obj;
        myRef.showInfo();
    }

    @Test
    public void test02() throws Exception {
        //高通用性
        //创建Properties对象
        Properties p = new Properties();
        //加载配置文件
        p.load(new FileReader("src\\ref.properties"));
        //定义变量接收配置文件中的变量名字
        String className = p.getProperty("className");
        //根据类名,返回 Class 类型的对象
        Class<?> aClass = Class.forName(className);
        //根据aClass 创建你加载的类 MyRef 的实例化对象
        Object obj = aClass.newInstance();
        System.out.println("obj 的运行类型是:" + obj.getClass());
        System.out.println("=========================");

        //通过 aClass 对象获取构造器对象数组
        Constructor<?>[] constructors = aClass.getConstructors();
        System.out.println(Arrays.toString(constructors));
        //通过 aClass 对象获取公有的构造器对象(有参)
        Constructor<?> constructor01 = aClass.getConstructor(String.class, char.class, String.class);
        //constructor01 调用 newInstance 来创建有参的实例化对象
        Object o = constructor01.newInstance("小黄", '男', "襄阳");
        System.out.println("o = " + o);
        System.out.println("=========================");

        //获取所有的公有的字段/属性
        Field[] fields = aClass.getFields();
        System.out.println(Arrays.toString(fields)); //[public boolean com.xunfang.wangc.demo.MyRef.isFlag]
        //Declared可以调所有,私有和公有均可
        Field[] declaredFields = aClass.getDeclaredFields();
        System.out.println(Arrays.toString(declaredFields));

        //通过 aClass 对象获取 "name"字段对象
        Field name = aClass.getDeclaredField("name");
        //解除私有制的限制
        name.setAccessible(true);
        //给 obj 的 name 字段赋值
        name.set(obj,"小黄");
        //获取 obj 的 name 的值
        Object oName = name.get(obj);
        System.out.println("oName = " + oName);
        System.out.println(obj);
        System.out.println("=========================");

        //无参无返回方法
        //通过 aClass 得到你加载的类 com.xunfang.wangc.demo.MyRef 的 showInfo 的方法对象
        Method method1 = aClass.getMethod("showInfo");
        //通过 method1 调用方法: 即通过方法对象来实现调用方法
        method1.invoke(obj);

        //有参有返回方法
        Method method02 = aClass.getMethod("isOk", String.class, int.class);
        Object res = method02.invoke(obj,"12323sdf@163.com",22);
        System.out.println("res = " + res);

        //私有方法
        //通过 aClass 调用 getDeclaredMethod 方法创建 "pri_test" 的方法对象
        Method method03 = aClass.getDeclaredMethod("pri_test");
        //解除 method03 的私有化限制
        method03.setAccessible(true);
        //执行方法
        method03.invoke(obj);

    }
}
posted @   Thecong  阅读(73)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· DeepSeek 开源周回顾「GitHub 热点速览」
点击右上角即可分享
微信分享提示