浅谈Java的反射机制和作用

作者:Java大师

转载自:浅谈Java的反射机制和作用 - idea激活- IntelliJ IDEA 2021.1激活破解教程(亲测激活至 2099 年,长期更新)- 爪哇男教程 (javaman.cn)

很多刚学Java反射的同学可能对反射技术一头雾水,为什么要学习反射,学习反射有什么作用,不用反射,通过new也能创建用户对象。

那么接下来大师就带你们了解一下反射是什么,为什么要学习反射?

下面我们首先通过一个实例来说明反射的好处:

方法1、不用反射技术,创建用户对象,调用sayHello方法

1.1 我们首先创建一个User类

package com.dashi;/**
 * Author:Java大师
 * User对象,包含用户的id和姓名以及sayHello方法
 */public class User {    private int id;    private String name;    public int getId() {        return id;
    }    public void setId(int id) {        this.id = id;
    }    public String getName() {        return name;
    }    public void setName(String name) {        this.name = name;
    }    public String sayHello(String who) {        return who+ "{" +                "id=" + id +                ", name='" + name + '\'' +                '}';
    }
}

1.2 创建测试用例

package com.dashi;import org.junit.Test;/**
 * 创建Juinit测试对象
 */public class Test01 {    @Test
    public void test01(){
        User user = new User();
        user.setId(1);
        user.setName("Java大师");        //调用sayHello方法
        System.out.println(user.sayHello("user1"));
    }
}

1.3运行结果如下,打印出sayHello结果:

user1{id=1, name='Java大师'}

Process finished with exit code 0

方法2、通过反射技术,创建用户对象,调用sayHello方法

2.1 调用测试用例

 @Test
    public void test02(){        try {            //创建用户对象字符串
            String obj = "com.dashi.User";            //通过用户对象字符串加载类
            Class clz = Class.forName(obj);            //通过newInstance方法,创建用户对象
            User user = (User)clz.newInstance();
            user.setId(2);
            user.setName("Java大师2");            //调用sayHello方法
            System.out.println(user.sayHello("user2"));
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }

2.2 运行结果如下,打印出sayHello结果:

user1{id=1, name='Java大师'}
user2{id=2, name='Java大师2'}

Process finished with exit code 0

通过两者以上对比,发现方法1和方法2都能创建用户对象,并调用sayHello方法,并且打印的结果都正确。但是方法2比方法1先进的地方是方法2针对字符串编程,方法1针对实体类编程

那么针对字符串编程有什么好处呢,小伙伴们耐心接着往下看:

我们通过一个Dao层来演示下针对字符串编程的好处:

假设我们有一个IUserDao接口,里面有一个load方法,代码如下:

package com.dashi;public interface IUserDao {    public void load();
}

有两个实现类来实现该IUserDao接口,实现类如下:

package com.dashi;/**
 * A实现类
 */public class AUserDao implements IUserDao{    @Override
    public void load() {
        System.out.println("这是AUserDao");
    }
}
package com.dashi;/**
 * B实现类
 */public class BUserDao implements IUserDao{    @Override
    public void load() {
        System.out.println("这是BUserDao");
    }
}

方法3、不通过反射技术,创建IUserDao,调用load方法

@Test
    public void testDao01(){
        IUserDao userDao = new AUserDao();
        userDao.load();
    }

打印结果如下:

这是AUserDao

Process finished with exit code 0

方法4、通过反射技术,创建IUserDao,调用load方法

@Test
    public void testDao02(){        try {            //创建接口实现类字符串
            String dao_str = "com.dashi.AUserDao";            //通过类加载的方式创建IUserDao
            IUserDao userDao = (IUserDao) Class.forName(dao_str).newInstance();            //调用load方法
            userDao.load();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

打印结果如下:

这是AUserDao
这是AUserDao

Process finished with exit code 0

通过类加载的方式,我们也创建了IUserDao对象,调用了load方法,和方法3的运行结果一样

方法5、通过反射技术,创建IUserDao,调用load方法

@Test
    public void testDao03(){        try {            //创建接口实现类字符串
            String dao_str = "com.dashi.BUserDao";            //通过类加载的方式创建IUserDao
            Class clz = Class.forName(dao_str);
            IUserDao userDao= (IUserDao)clz.newInstance();            //创建调用方法字符串
            String mm = "load";            //创建method对象
            Method method =  clz.getMethod(mm);            //调用通过反射调用invoke方法
            method.invoke(userDao);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }

运行结果如下:

这是AUserDao
这是AUserDao
这是BUserDao

Process finished with exit code 0

通过method.invoke方法也可以实现load方法的调用

方法5比方法4和方法3更加灵活,不需要知道AUserDao和BUserDao实体类,只提供类的字符串和类的方法名称,通过反射就可以实现方法的调用

实战中的实际意义

假设我们的Dao层,从mysql迁移导oracle,SQL server等

运用反射技术,通过字符串编程,那么我们不需要进行Dao层实体类的更改,只需要改动我们的字符串名字就可以进行Dao层的更新。比如:

1、不通过反射技术,我们需要修改实现类中的AUserDao改为BUserDao
IUserDao userDao = new AUserDao();
userDao.load();``如果有几百个Dao,我们需要修改几百次````2、运用发射技术通过字符串编程,我们可以把字符串定义在properties文件中,通过修改properties文件中的配置即可实现Dao的更新 //创建接口实现类字符串
 String dao_str = "com.dashi.AUserDao"; //可以改写为:String dao_str = PropertyUtil.get("dao");
 //通过类加载的方式创建IUserDao
 IUserDao userDao = (IUserDao) Class.forName(dao_str).newInstance(); //调用load方法
 userDao.load();

这就是反射技术的实际运用,通过以上实例就可以看出字符串编程和通过实现类编程的最大的区别和实际的意义

并且通过反射技术可以使我们的编程更加灵活

灵活运用反射技术,我们可以设计出更加灵活的框架哦~

关注博主公众号, 每日推送干货文章, 回复「资源」, 即可领取全网最火的Java学习&面试核心资源!~。

浅谈Java的反射机制和作用_java反射