Java反射-简单应用

为了程序更好的维护和扩展,在面向对象思维的世界里,首先是面向接口编程,然后我们应该把做什么和怎么做进行分离。

下面我将用一个开晚会的例子来演示一下,最终达到的效果是:工厂+反射+配置文件实现程序的灵活应用。会具体说明一下这个过程是怎么来的,明白了这个,就会对反射和配置文件的结合更加深刻一些。

想要实现的功能是:晚会有一个唱歌、舞蹈、小品的节目单,具体各个节目的表演者只需要一个就可以,每一个表演接口都有两个实现类(表演者),通过客户端调用不同的实现类来实现不同的节目单。表演者就是“做什么”,那么“怎么做”就是节目单了,首先来看看类图结构:

下面放代码,首先是接口,即各类表演:

<span style="font-size:14px;">/**跳舞接口*/
</span><pre name="code" class="java">public interface Dancer {

public void dance();} /**小品接口*/public interface Performer { public void performance();}/**歌唱接口*/ public interface Singer { public void sing();}


然后是各个实现类,即表演者:

Dancer接口实现类:
public class YangLiPing implements Dancer {

   @Override
   public void dance() {
      System.out.println("杨丽萍跳舞:孔雀舞");
   }

}

public class XiaoHuDui implements Dancer {

   @Override
   public void dance() {
      System.out.println("小虎队跳舞:霹雳舞");
   }

}
Performer接口实现类:
public class GongHanLin implements Performer {

   @Override
   public void performance() {
      System.out.println("巩汉林表演:功夫令");
   }

}
public class ZhaoBenShan implements Performer {

   @Override
   public void performance() {
      System.out.println("赵本山表演:卖拐");
   }

}
Singer接口实现类:
public class ZhouHuaJian implements Singer {

   @Override
   public void sing() {
      System.out.println("周华健演唱:刀剑如梦");
   }

}
public class WangFei implements Singer {

   @Override
   public void sing() {
      System.out.println("王菲演唱:我愿意");
   }

}

客户端调用方式:

<span style="font-size:14px;"> public static void main(String[] args) {

      //定义晚会流程
      //演出:歌曲、舞蹈、表演
      //第1种方法:单纯使用多态

      System.out.println("晚会开始=======>>");

      Singer singer = new ZhouHuaJian();
      singer.sing();

      Performer performer = new ZhaoBenShan();
      performer.performance();

      Dancer dancer = new YangLiPing();
      dancer.dance();

      System.out.println("<<========晚会结束");
   }</span>

代码挺简单,不过发现一个问题,作为节目组织者,在现实中基本上是不应该直接与表演者打交道的,而是与其所在的公司或者代理人进行交流,假设现在所有的表演者都同属于一个娱乐公司,那么我只需要从这个娱乐公司里获得我想要的那些表演者就可以了,那么UML图将会变为如下结构(Factory就代表这个娱乐公司):

Facotry代码:

public classFactory {

   //提供准备歌手方法
   public static Singer getSinger(){
      return new ZhouHuaJian();
   }

   //提供准备舞蹈方法
   public static Dancer getDancer(){
      return new YangLiPing();
   }

   //提供准备表演方法
   public static PerformergetPerformer(){
      return new GongHanLin();
   }
}

那么客户端代码就变成了这样:

public staticvoidmain(String[] args) {
      //定义晚会流程
      //演出:歌曲、小品、舞蹈
      //第1种方法:使用工厂获取各个表演种类

      System.out.println("晚会开始=======>>");

      Singersinger = Factory.getSinger();
      singer.sing();

      Performerperformer = Factory.getPerformer();
      performer.performance();

      Dancerdancer = Factory.getDancer();
      dancer.dance();

      System.out.println("<<========晚会结束");
}

大家可以看到,在Factory代码中我们发现还是将各个实现类写死了,也就是说娱乐公司强制某些表演者必须参加,但实际上很多时候有些表演者可能没法参加,而另外一些闲着的表演者则可以参加,那么我是不是应该在需要表演者的时候动态获取有空参加更好一些呢?这个时候就需要用上配置文件+反射了。Factory代码更改如下:

<span style="font-size:14px;">public class Factory {

   /**提供准备歌手方法*/
   public static Singer getSinger(){

      //读取配置文件及获取key对应的value
      StringclassName = ResourceBundle.getBundle("party").getString("Singer");
      Singersinger = null;

      try {
         //将配置文件中读取的完整类名通过反射获取该类的实例
         singer= (Singer)Class.forName(className).newInstance();
      }catch(InstantiationException | IllegalAccessException
            |ClassNotFoundException e) {
         e.printStackTrace();
      }

      return singer;

   }

   /**提供准备舞蹈方法*/
   public static Dancer getDancer(){

      StringclassName = ResourceBundle.getBundle("party").getString("Dancer");
      Dancerdancer = null;

      try {
         dancer= (Dancer)Class.forName(className).newInstance();
      }catch(InstantiationException | IllegalAccessException
            |ClassNotFoundException e) {
         e.printStackTrace();
      }

      return dancer;
   }

   /**提供准备表演方法*/
   public static PerformergetPerformer(){

      StringclassName = ResourceBundle.getBundle("party").getString("Performer");
      Performerperformer = null;

      try {
         performer= (Performer)Class.forName(className).newInstance();
      }catch(InstantiationException | IllegalAccessException
            |ClassNotFoundException e) {
         e.printStackTrace();
      }

      return performer;
   }
}</span>

配置文件party.properties中的代码:

Singer = com.lc.reflect.demo3.person.WangFei
Performer = com.lc.reflect.demo3.person.ZhaoBenShan
Dancer =com.lc.reflect.demo3.person.XiaoHuDui

这样就能把代码解耦了。仔细看的话,在Factory中的代码3个方法基本上没啥不同,除了变量和对象不同,发现了代码的坏味道。那就重构吧:

public classFactory1 {     

      /**提供准备歌手方法*/
      public static Singer getSinger(){

         Singersinger = null;
         return (Singer)getObject("Singer",singer);
      }

      /**提供准备舞蹈方法*/
      public static Dancer getDancer(){

         Dancerdancer = null;

         return (Dancer)getObject("Dancer",dancer);
      }

      /**提供准备表演方法*/
      public static PerformergetPerformer(){

         Performerperformer = null;

         return (Performer)getObject("Performer",performer);
      }

      /**
       * 获取目标对象的方法
       * @param objName 对象名称
       * @param obj 对象类型
       * @return对象
       */
      public static Object getObject(StringobjName,Object obj){

         //获取配置文件中的目标对象路径
         StringclassName = ResourceBundle.getBundle("party").getString(objName);
         try {
            //获取目标对象实例
            obj= Class.forName(className).newInstance();
         }catch(InstantiationException | IllegalAccessException
                |ClassNotFoundException e) {
            e.printStackTrace();
         }
         return obj;
      }
}

这样就简洁多了。

学习一块知识不仅仅要学习API是怎么用的,还要与生活相结合,做出一个个简单有效的Demo,同时在做Demo的过程中,如果发现了编写的代码有值得重构的地方,一定不要停下思考的脚步,Just do it!虽然对反射的具体实现原理和过程还不太清楚,但首先会用才能有继续研究的动力。继续努力中~~

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-07-28 21:51:22

Java反射-简单应用的相关文章

java反射简单实现注入

做了好久的java开发 ,却一直没有详细了解java反射机制,后来写项目的时候发现用反射可以少写好多无聊的代码,因此用java反射简单实现注入. java反射的具体细节可参见 这篇博客写的非常详细,点此进入~ 而一般基于业务的编程主要用反射实现将属性动态的注入一个对象中. 以下是方法实现: 1 /** 2 * 根据 传入的map与类名,通过反射实例化对象 3 * @param className 需要实例化的类名 4 * @param map 包含属性的键值对 (String,Object) 5

Java反射 - 简单的给Bean赋值和取值

由于项目的实际需要,所以利用java反射原理写了一个简单给bean赋值和取值通用的类,在此记录下方便自己日后用到,也为需要的兄弟提供个参考例子. 工具类BeanRefUtil: [java] view plain copy print? package com.test; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.text.SimpleDateFormat; import java.u

Java反射+简单工厂模式总结

除了 new 之外的创建对象的方法 通过 new 创建对象,会使得程序面向实现编程,先举个例子,某个果园里现在有两种水果,一种是苹果,一种是香蕉,有客户想采摘园子里的水果,要求用get()方法表示即可 一般情况下,最直接的写法为: public class Apple { public void get() { System.out.println("得到苹果"); } }   public class Banana { public void get() { System.out.p

java反射简单例子

假设有如下类: package com.test.reflect; public class Person { private int age; private String name; public Persion() { } public Persion(String name) { this.name = name; } public Persion(String name,int age) { this(name); this.age = age; } public void setNa

java反射机制简单介绍

1.字节码.所谓的字节码就是当java虚拟机载入某个类的对象时,首先须要将硬盘中该类的源码编译成class文件的二进制代码(字节码),然后将class文件的字节码载入到内存中,之后再创建该类的对象 2.java反射的基础是Class类(注意不是小写的class),Class类实例代表着内存中的一份字节码.常见的获取Class类对象的方法例如以下(第一种为对象的方法,另外一种为类的方法): Dog dog = new Dog(); Class dogClass = dog.getClass();

Java反射机制的原理及在Android下的简单应用

花了几天时间,研究了一下Java的反射机制.在这里总结一下这几天学习的成果,一来分享自己的学习过程和在学习中遇到的问题,二来是给像我一样不太了解Java反射机制的同学做一个简单的介绍.在文章后面会链接一个Android反射机制的应用程序. 一.反射的概念及在Java中的类反射 反射主要是指程序可以访问.检测和修改它本身状态或行为的一种能力.在计算机科学领域,反射是一类应用,它们能够自描述和自控制.这类应用通过某种机制来实现对自己行为的描述和检测,并能根据自身行为的状态和结果,调整或修改应用所描述

java反射并不是什么高深技术,面向对象语言都有这个功能,而且功能也很简单,就是利用jvm动态加载时生成的class对象

java反射并不是什么高深技术,面向对象语言都有这个功能. 面向对象语言都有这个功能,而且功能也很简单,就是利用jvm动态加载时生成的class对象,去获取类相关的信息 2.利用java反射可以调用类的私有方法么?private()方法 答:可以,class取出method,method继承executable类,executable类继承AccessibleObject类,AccessibleObject有个setAccessiable()设置这个方法是否可访问. 则设置成true,就可将pr

java反射之Constructor简单应用

Constructor类是java反射中重要的类,它是对类中构造器的描述的类.类似于Method(对类中方法的描述的类),Field(对类中属性的描述的类). 通过创建Constructor的对象实例,我们可以创建源对象. 小测试demo: package com.wtd; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.util.Array

Java反射机制简单使用

1.Java反射相关类所在package: java.lang.reflect.* 2.开始使用Reflection: 使用reflect相关类,遵循三个步骤: a.获取想要操作类的 java.lang.Class 对象. 如: Class c = Class.forName("java.lang.String"); //得到的是一个String类的对象 或者使用: Class c = int.class; b.调用诸如 getDeclaredMethods() 方法,用以获取该类的方