Java反射总结(一)

今天给大家总结一下java中非常重要的反射,这里不给大家看反射的概念,和其它的技术一样,我从一个需求开始,带着大家一步一步做,带大家理解什么是反射以及为什么要用反射机制。

一、需求描述

假设我现在要开发一款游戏,游戏的名称叫《无敌破坏神》,玩家可以选择五中英雄角色,分别是:
1. 破坏神
2. 法师
3. 战神
4. 雅典娜女神
5. 精灵
这五个英雄角色都是我瞎想的,具体是什么不是咱们要关心的。这五个英雄都有自己的技能,比如奔跑,躲避,一般技能和大招等,玩家选择了其中一个英雄,这个英雄的技能就确定了。这是需求的简单的描述,咱们只需要这么多信息就够了。

二、需求分析


咱们先来分析一下这个游戏,首先咱们有五个英雄,对应到代码就是五个类,然后五个英雄有各自的技能和一些属性,这些对应到代码就是类中的属性和方法,咱们要做的是用java简单的模拟这五个英雄的技能调用,下面咱们来具体看一下怎么实现。
这里咱们要写很多个版本,每个版本比上一个版本代码要改进一些,功能不变,方便大家理解改进的思路和原因。
版本一

版本一是最傻瓜式的写法,这里给出部分代码:

public class Test1 {
    public static void main(String[] args) {
        Hero_PoHuaiShen hero1 = new Hero_PoHuaiShen("破坏神一号");
        hero1.run();
    }
}

class Hero_PoHuaiShen {
    String name;
    Hero_PoHuaiShen(String name) {
        this.name = name;
    }
    public void run() {
        System.out.println(name+"跑");
    }
}

先解释一下,这里省略了其它四个英雄的类的编写,只写了一个,而且这个英雄的属性和方法都是最简单的,但是这些足以说明问题了。这里的英雄对应一个具体的类,英雄的属性和技能对应类的属性和方法,模拟英雄技能就是实例化这个类并且通过对象调用英雄的方法。

现在分析一下这种写法,这种写法给每个英雄都写了一个类,如果英雄的种类增加了,就得再重新写英雄类,并实现它的方法,而且这样写每个英雄不能保证有相同的属性和相同的技能,这里所说的相同是指属性的个数和种类,所以这样写很不好,咱们来看看版本二是怎么写的

版本二

对于上面的代码咱们可以分析一下,每个英雄都有一个run()方法,咱们是不是可以把这个方法提出来写在一个接口里,代码如下:

interface Hero{
    public void run();
    public void kill();
}

class 破坏神 implements Hero {
    @Override
    public void run() {
        System.out.println("破坏神奔跑");
    }

    @Override
    public void kill() {
        System.out.println("破坏神放技能");
    }
}

这里把英雄的技能提出来了,每种英雄只需要实现Hero这个借口然后根据角色重写方法就可以了,这样使英雄的技能种类统一了起来,如果要统一属性的种类和个数,大家可以再写一个类,里面只写一些英雄属性,然后用具体的英雄类继承这个类就可以了。然后在主函数里调用这个类就可以了:

public class Test1 {
    public static void main(String[] args) {
        破坏神 p = new 破坏神();
        p.run();
        p.kill();
    }
}

这个版本要比版本一好一些,但是游戏角色是用户选择的,怎么根据用户的选择来生成具体的类呢?来看版本三。

版本三

我们假设用户的选择存在了一个字符串中,咱们根据这个字符串生成对应的类:

public static void main(String[] args) {
        String choice = "破坏神";
        Hero h=null;
        if(choice.equals("破坏神")){
            h = new 破坏神();
        }
        if(choice.equals("法师")){
            h = new 法师();
        }
        if(choice.equals("战神")){
            h = new 战神();
        }
        if(choice.equals("雅典娜女神")){
            h = new 雅典娜女神();
        }
        if(choice.equals("精灵")){
            h = new 精灵();
        }
    }

用if判断语句或者switch分支语句就可以根据玩家的选择创建具体的英雄类,这种写法虽然提高了用户选择的灵活性,但是也存在一些问题,如果英雄的种类很多或者添加了新的英雄,那么就要添加判断语句,这样很麻烦,能不能继续改进版本三的代码呢?可以,这里就要引出反射了,咱们来看一下。

版本四

这里改的代码是主函数调用部分,对于很长的一段判断用户选择的代码咱们可以用几行简单的代码代替,而且功能完全相同:

public class Test1 {
    public static void main(String[] args) {
        String choice = "破坏神";
        try{
            Class c= Class.forName("com.one."+choice);
            Hero h = (Hero)c.newInstance();
            h.run();
            h.kill();
        }catch(Exception e) {
            e.printStackTrace();
        }
    }
}

这样写就算修改了英雄名称或添加很多英雄角色都可以不用修改这部分代码,是不是很强大。咱们来看一下代码:

Class c= Class.forName("com.one."+choice);

这行代码是关键,这里要讲一下Class这个类,大家都知道java是面向对象的编程语言,每个类可以有很多个对象,其实java中的类也是对象,但是它是哪个类的对象呢?这个类就是Class,所有的类都是Class的对象,大家可以先这样理解。这一行代码的功能就是通过类名获取一个类,这里因为是通过字符串来获取类的,所以可能存在咱们要获取的这个类不存在的情况,因此这里需要捕获异常。获取了这个类后,然后通过Class的对象c再生成一个实例对象,这个对象是Object类型的,所以需要类型转化,然后就可以通过h调用具体英雄的方法。这样写的好处显而易见,首先代码量减少了,但是这不是它的主要优点,咱们来看另外一个例子再来看看反射的好处。

开发中经常会用到数据库,链接mysql的代码如下:

public static Connection getConnection() {
        Connection conn=null;
        try{
            Class.forName("com.mysql.jdbc.Driver");
            conn=DriverManager.getConnection("jdbc:mysql://localhost:3306/"
                    + "schema1","root","123456");
        }catch(Exception e){
            e.printStackTrace();
        }
        return conn;
}

这里加载数据库驱动用的就是反射,大家都知道代码要经过编译后才能运行,但是编译过的代码就不能再改变了,现在我想用其他的数据库,就需要加载其它的数据库驱动,并且用户名、密码和url这些可能都会改变,但是这些都已经写在代码里并且编译了,不可能再改变,除非修改源代码再进行编译,可想而知这样做有多麻烦了。开发中会用到很多配置文件,咱们可以把数据库驱动、用户名、密码和url写在一个配置文件,然后在代码中读取这个配置文件的信息就可以了,这样如果要更换数据库或者修改密码,就可以直接修改配置文件里的信息,而不需要再修改源代码并且重新编译了。

这样是根据用户的选择动态的加载某个类并且执行其中的方法,这样做代码的灵活性很大,代码在运行的时候可以获取一个类的所有信息,包括它的属性和方法,然后执行这个类中的方法。其实在javaweb开发中用到的各种框架的实现都是基于反射来实现的,做过这方面开发的朋友都会知道这些框架有一大堆配置文件要填写,这其实就是根据用户的选择动态的加载一些类,原理就是反射。

希望这个思路能让大家理解什么是反射,具体怎么用,请看我的另一篇博客。
链接:Java反射总结(二)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值