(原创)java反射的介绍和使用

本文详细介绍了Java反射机制的基础概念,包括如何通过三种方式获取Class文件对象,以及如何利用反射进行无参构造、构造方法、成员变量和成员方法的操作。还展示了如何利用反射绕过泛型检查,并提供了实际代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

概述

在实际开发中,有时候会用到反射技术
很多人对此了解的不是很深
今天就来做一个简单的介绍

Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法。
对于任意一个对象,都能够调用它的任意一个方法和属性。
这种动态获取信息以及动态调用对象的方法的功能称为java语言的反射机制。
要想剖析一个类,必须先要获取到该类的字节码文件对象。
而解剖使用的就是Class类中的方法,
所以要先获取到每一个字节码文件对应的Class类型的对象。
具体有三种方式

获取Class文件对象的三种方式

具体方式如下图
在这里插入图片描述
1:对于一个Java源文件,可以通过包名.类名的方法获取
2:源文件编译成字节码对象后,可以通过字节码对象.class属性获取
3:对象创建完成后,可以通过对象的getClass方法获取
那么,获取到Class文件对象后,如何对对象进行反射呢?

反射的使用

通过反射获得无参构造

在使用反射之前,我们先看下普通的情况下我们是如何调用对象的属性和方法的
先看一个简单的例子:

public class Demo {
    public static void main(String[] args) {
        Work work = new Work();
        work.doWork(new Driver());
    }

}

class Work {
    public void doWork(Person person) {
        person.workIng();
    }
}

interface Person {
    public void workIng();
}

class Driver implements Person {
    @Override
    public void workIng() {
        System.out.println("司机师傅正在开车");
    }
}

这里有一个Work类,里面有一个doWork方法
传入一个Person类进去,执行person的workIng方法
打印结果自然是:

司机师傅正在开车

现在我们用反射来实现一下以上的功能

    public static void main(String[] args) throws Exception {
//        Work work = new Work();
//        work.doWork(new Driver());

        Class cls = Class.forName("com.example.javastudy.demo.Driver");
//        //newInstance使用类的无参构造去创建对象,如果类没有无参构造,就不能这样创建
        Person person = (Person) cls.newInstance();
        Work work = new Work();
        work.doWork(person);
    }

可以看到,这里反射了Driver这个司机类
然后doWork方法执行结果和刚刚是一样的
注意这个newInstance方法
如果类没有无参构造,是不能这样使用的

通过反射获得构造方法

如果要获得一个对象的构造方法,可以通过下面的方式

 Class cls = Class.forName("com.example.javastudy.demo.Driver");
 Constructor[] constructors = cls.getConstructors();//获得所有构造

getConstructors是获得这个对象的所有构造,以数组方式返回
如果要获得指定的一个构造呢?
可以看下面的例子
我们先对Driver类做一个修改
新增了一个年龄的有参构造

class Driver implements Person {
    @Override
    public void workIng() {
        System.out.println("司机师傅正在开车");
    }

    int age;//司机年龄

    public Driver() {
    }

    public Driver(int age) {
        this.age = age;
    }
}

然后进行反射操作:

    public static void main(String[] args) throws Exception {
        Class cls = Class.forName("com.example.javastudy.demo.Driver");
//        Constructor c = cls.getConstructor(int.class);//获得有参构造
        Constructor c = cls.getConstructor(int.class);
        Driver driver = (Driver) c.newInstance(34);//通过有参构造去创建对象
        System.out.println("司机年龄:" + driver.age);
        Work work = new Work();
        work.doWork(driver);
    }

输出结果:

司机年龄:34
司机师傅正在开车

通过反射获得成员变量

现在我们再对Driver类新增一个性别属性,不过是私有的
然后再新增一个msg公有方法和一个printMsg私有方法

class Driver implements Person {
    @Override
    public void workIng() {
        System.out.println("司机师傅正在开车");
    }

    public int age;//司机年龄

    private String sex;//司机性别

    public String getSex() {
        return sex;
    }

    public void msg() {
        System.out.println("年龄:" + age + ",性别:" + sex);
    }

    private void printMsg(String str) {
        System.out.println(str);
    }

    public Driver() {
    }

    public Driver(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "年龄:" + age + ",性别:" + sex;
    }
}

那么如何反射这个私有的sex属性并进行修改呢?

    public static void main(String[] args) throws Exception {
        //通过反射获取成员变量
        Class cls = Class.forName("com.example.javastudy.demo.Driver");
        Constructor c = cls.getConstructor(int.class);//获得有参构造
        Driver driver = (Driver) c.newInstance(25);//通过有参构造去创建对象
//        Field[] fields = cls.getFields();//获得所有成员变量
//        Field field = cls.getField("sex");//获得指定名称的成员变量,但不能获取私有的
        Field field = cls.getDeclaredField("sex");//获得指定名称的私有成员变量
        field.setAccessible(true);//去除私有变量的私有权限,这样就可以赋值了
        System.out.println(driver.toString());
        field.set(driver,"男");
        String sex = (String) field.get(driver);//得到私有变量所对应的值,返回object,可以强转
        System.out.println("修改后的性别:" + sex);
        System.out.println(driver.toString());
    }

打印结果:

年龄:25,性别:null
年龄:25,性别:

可以看到,成功利用反射将司机的性别改成了男
这里需要注意的是:
getField只能获取公有成员变量
getDeclaredField可以获取私有成员变量
在修改变量属性前,需要先创建出变量对象
然后通过setAccessible方法去掉私有变量的私有权限
最后才可以通过Field的set方法去对私有变量做修改
如果是公有变量,是不需要调用setAccessible方法的

通过反射获得成员方法

获得方法和获得变量其实差不多
这里就直接贴代码了

    public static void main(String[] args) throws Exception {
        //通过反射获取方法并使用
        Class cls = Class.forName("com.example.javastudy.demo.Driver");
        Constructor c = cls.getConstructor(int.class);//获得有参构造
        Driver driver = (Driver) c.newInstance(25);//通过有参构造去创建对象

//        Method[] methods = cls.getDeclaredMethods();//得到所有私有方法
//        Method[] methods1 = cls.getMethods();//得到所有方法
        Method method2 = cls.getMethod("msg");//获取msg方法
        method2.invoke(driver);//等价于 driver.msg();
        Method method3 = cls.getDeclaredMethod("printMsg", String.class);//获取私有printMsg方法
        method3.setAccessible(true);//去除方法的私有权限
        method3.invoke(driver,"这是一个出租车司机");
    }

打印结果:

年龄:25,性别:null
这是一个出租车司机

通过反射越过泛型检查

在Java中,
泛型只在编译期有效,在运行期会被擦除掉
所以我们可以利用这一点,越过泛型检查
例子如下:

    public static void main(String[] args) throws Exception {
        ArrayList<Integer> list = new ArrayList<>();
        list.add(111);
        list.add(222);
        Class cls = Class.forName("java.util.ArrayList");//获取到字节码对象
        Method addMethod = cls.getMethod("add", Object.class);
        addMethod.invoke(list, "abc");
        System.out.println(list);
    }

打印结果:

[111, 222, abc]

可以看到,成功在一个integer的list集合
存入了一个String字符串
最后,关于反射的使用就介绍到这里了~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值