惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Hacker News: Ask HN
Hacker News: Ask HN
Jina AI
Jina AI
U
Unit 42
月光博客
月光博客
宝玉的分享
宝玉的分享
博客园 - 叶小钗
Blog — PlanetScale
Blog — PlanetScale
The Cloudflare Blog
D
Docker
Y
Y Combinator Blog
P
Privacy & Cybersecurity Law Blog
Hacker News - Newest:
Hacker News - Newest: "LLM"
Last Week in AI
Last Week in AI
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
V
Visual Studio Blog
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
T
Threat Research - Cisco Blogs
G
Google Developers Blog
H
Hacker News: Front Page
罗磊的独立博客
博客园 - 【当耐特】
P
Proofpoint News Feed
MongoDB | Blog
MongoDB | Blog
A
About on SuperTechFans
有赞技术团队
有赞技术团队
P
Palo Alto Networks Blog
T
Tailwind CSS Blog
L
Lohrmann on Cybersecurity
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
博客园_首页
H
Help Net Security
SecWiki News
SecWiki News
J
Java Code Geeks
I
InfoQ
T
Troy Hunt's Blog
GbyAI
GbyAI
M
MIT News - Artificial intelligence
Project Zero
Project Zero
Martin Fowler
Martin Fowler
The Hacker News
The Hacker News
Know Your Adversary
Know Your Adversary
Application and Cybersecurity Blog
Application and Cybersecurity Blog
C
Cyber Attacks, Cyber Crime and Cyber Security
The Register - Security
The Register - Security
Cyberwarzone
Cyberwarzone
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
P
Proofpoint News Feed
MyScale Blog
MyScale Blog
A
Arctic Wolf
P
Privacy International News Feed

博客园 - csdnexpert

美国程序员Peter:落脚北京只因这里的胡同 不是冷饭的冷饭:重评芙蓉姐姐现象 从早晨8点到晚上12点:WebEx合肥CTO的一天 转胡一虎Blog:父亲是我生命中的永恒 十年后,ELM会不会创造SOA现在所创造的局面? 来京两载,今日入清华读书,记一笔 传媒人应该具备的素质:批判 理性 正气 异国也有欢乐:北京Linux User Group探访实录 解释传统与敏捷方法最贴切的故事:大象与猴子 媒体的关键还是在于“软件”(人与规范) “Web开发之华山论剑”制作花絮与推荐导读 利用Radrails开发Ruby on Rails程序入门指南 “悲欣交集”的《开源大本营》制作之路 Alistair讲座的几点感受:纠正对敏捷方法的误解 在Eclipse里实现Ant自动编译 Java之父Gosling:Java没有受到PHP、Ruby或C#的威胁 PC-cillin 2005网络安全版使用简评 为什么刘彻会成为一代名君? 有选择才精彩 到哪里都是从零开始 可怜的微软与项目管理经典图解 从对一篇文章的修改看写作中的主题把握 谁说做软件测试没有好的前途?反驳之 《程序员》第9期:面对多核时代 我们以何应对? 8月的最后一天,我们开赴日照前线 Java Transaction Design Strategies推荐阅读 温总理对读书和思考问题的回答 共享软件大鳄来华抢人 是机遇还是挑战? 只有资源共享 中国共享软件才能突破性发展 又可以写Blog了 心里竟有点小小的激动 事件驱动模型实例详解(Java篇) 商业项目应该向开源项目学习什么? 开源的软件+商业的服务=? 封印的武士 测试Google的网络Office——Writely 《男人装》2006.05 未来技术杂志会走向哪里? 评评点点,程序员的2006世界杯 终于理解了我的作者 你知道的Java,和你不知道的Java [投票]3·15消费者日 《程序员》杂志之现状调查 三言二拍 Eclipse+Tomcat实现Mysql数据库连接 解决在Eclipse中配置JBoss、Tomcat等插件时遇到的问题 Log4j日志管理系统简单使用说明 IntelliJ IDEA使用技巧一览表 我喜欢使用IntelliJ Idea的25个理由 新帆起航,目标新大陆,感谢大家.... 6.26南汇校园行 面向对象的授课感想 集合框架的授课感想 反射在Java Swing中的应用 从杭州到北京 华为“新同事文化”:爱你的同事如兄弟 读书的快乐 闻听06年研究生收费有感 用创新产品支撑流体计算 杂拌儿:歪评百度牵手MTV、雅虎推出优化IE7现象 有钱的IBM 有争议的开发者大会 7月最后一天脑袋里的杂事 2006-IBM开发者大会现场组图与技术点(部分) 火锅论坛:要团队不要群体 中国软件的井喷时代 热烈庆祝CSDN 2006年中大会顺利闭幕 听同学谈有中国特色的软件营销模式 马云于“赢在中国”的一些讲话 看图识性格,蛮有意思的,累的时候玩一下:) 8月19日BBUG:电信技术开发经验分享与前景展望 Yahoo!新成立Python开发者中心 推动Python发展 也谈如何举办一场成功的技术讲座? 不满SourceForge服务 JRuby迁移至CodeHaus 看完《天狗》,我对社会充满了失望 从写Blog看技术人员成长6要素 再次慨叹生命的脆弱,我辈当惜之 急雨、泥土与睡觉 Google继续扩张,“魔爪”伸向服务器 感慨国内技术网站的环境 外包,从拧螺丝钉开始 史上最大规模的Agile开源项目Callisto发布 畅快、郁闷、遗憾 阿根廷,让我如何不爱你? 好笑的那几个小时 人是应该有长远目标的 庆祝阿根廷挺进八强 博客究竟能做什么? 对Web标准的9大误解 Slashdot热点一览 Blogger的痛心事——没人回贴 一个责任编辑的日记 你可以赚钱,但你赚不来时间 印度软件外包发展简记 那一段情系列之一:Fangfang 从《读库》关于“报人”文章感叹今日技术媒体 Mop研发团队:网络时代的技术偏执狂(全文) DevCo专家李维推荐的学习方法 英雄迟暮,一声长叹,且看10个可怜的技术天才 《程序员》7月刊即将上市 10大看点值得关注 把软件外包给中国,放心吗? 我也是个博客青苹果 DirectX 10后面的微软牛人们 参加IBM开发者大会前一天
反射机制与系统耦合实例详解
csdnexpert · 2007-12-17 · via 博客园 - csdnexpert

反映射技术(以下简称:反射)的概念是由Smith1982年首次提出的,主要是指程序可以访问、检测和修改它本身状态或行为的一种能力。这一概念的提出很快引发了计算机科学领域关于应用反射性的研究。它首先被程序语言的设计领域所采用。最近,反射机制也被应用到了视窗系统、操作系统和文件系统中。

我--陈宇,作为Softworks对日软件人才培训中心的资深教员对于该技术有比较深入的研究,也正好借此与各位读者深入探讨一下。

在如今程序语言的设计领域中,几乎每种OO语言都专门设计了支持反射技术的API,不管是Microsoft公司的.Net框架还是SUN公司的Java语言都是如此,本技术帖就以Java为例来进行探讨。

Java编程语言中,反射是一种强大的工具。它使您能够创建灵活的代码,这些代码可以在运行时装配,无需在组件之间进行源代码链接。这样一来整个系统的耦合性就会降低并可以大大增加系统的灵活度。反射机制被大量运用在系统架构的设计层次上,并且在编写公共类和系统基盘的时候也起到了举足轻重的作用,甚至有人提出这门技术是一个程序员转型成为系统架构师的必经之路。

反射机制是 Java 被视为动态(或准动态)语言的关键,允许程序于执行期取得任何已知名称之 class 的內部信息,包括、父类、接口、内部类、属性结构体方法,並可于执行期生成实体、变更 字段內容或唤起 方法

有了反射机制,我们可以:

1.判断某个对象所属的类型(Class)

2.取得类型(Class)的属性,方法,构造体和父类的相关信息。

3.找出接口中的常量和方法定义。

4.为一个执行期才得知名称的类产生对象。

Java类反射中的主要方法:

对于类而言构造函数、字段和方法是最为重要的内容java.lang.Class 提供四种独立的反射调用,以不同的方式来获得信息。调用都遵循一种标准格式。

以下是用于查找构造函数的一组反射调用:

方法

说明

Constructor getConstructor(Class[] params)

获得使用特殊的参数类型的

公共构造函数

Constructor[] getConstructors()

获得类的所有公共构造函数

Constructor getDeclaredConstructor(Class[] params)

获得使用特定参数类型的构造函数(与访问级别无关)

Constructor[] getDeclaredConstructors()

获得类的所有构造函数(与访问级别无关)

获得字段信息的Class 反射调用不同于那些用于接入构造函数的调用,在参数类型数组中使用了字段名:

方法

说明

Field getField(String name)

获得指定的公共字段

Field[] getFields()

获得类的所有公共字段

Field getDeclaredField(String name)

获得指定的字段

Field[] getDeclaredFields()

获得类声明的所有字段

用于获得方法信息函数:

方法

说明

Method getMethod(String name, Class[] params)

使用特定的参数类型,获得命名的公共方法

Method[] getMethods()

获得类的所有公共方法

Method getDeclaredMethod(String name, Class[] params)

使用特定的参数类型,获得类声明的命名的方法

Method[] getDeclaredMethods()

获得类声明的所有方法

开始使用反射机制:

用于反射机制的类,如 Method,可以在 java.lang.relfect 包中找到。使用这些类的时候必须要遵循三个步骤:第一步是获得你想操作的类的java.lang.Class 对象。在运行中的 Java 程序中,用 java.lang.Class 类来描述类和接口等。

下面就是获得一个 Class 对象的方法之一:

Class c = Class.forName ("java.lang.Integer");

这条语句得到一个 String 类的类对象。还有另一种方法,如下面的语句:

Class c = Integer.class;

或者

Class c = Integer.TYPE;

它们可获得基本类型的类信息。其中后一种方法中访问的是基本类型的封装类 ( Integer) 中预先定义好的 TYPE 字段。

第二步是调用诸如 getDeclaredMethods 的方法,以取得该类中定义的所有方法的列表。

一旦取得这个信息,就可以进行第三步了。

第三步是使用 reflection API 来操作这些信息,如下面这段代码:

Class c = Class.forName("java.lang.String");

Method m[] = c.getDeclaredMethods();

System.out.println(m[0].toString());

它将以文本方式打印出 String 中定义的第一个方法的原型。

反射经常由框架型代码使用,由于这一点,我们可能希望框架能够全面接入代码,无需考虑常规的接入限制。例如当代码在不值得信任的代码共享的环境中运行时。

假设有以下这个类的声明:

class DemoReflection

{

       private String name = null;

       private void doPrint() {

              System.out.println("print.....");

       }

};

可以肯定的是,这个类中的属性name和方法doPrint都是无法对外展示的,但是使用了反射以后就可以办到。

package cn.softworks.demo;

import java.lang.reflect.*;

publicclass TestReflection {

    publicstaticvoid main(String args[]) {

        try {

            // 通过反映射技术得到DemoReflection的类型

            Class cls = Class.forName("DemoReflection");

            // 动态创建DemoReflection类的实力

            Object instance = cls.newInstance();

            // 通过反映射技术得到DemoReflection的非公有方法doPrint

            Method m = cls.getDeclaredMethod("doPrint",

                    new Class[] { String.class });

            // 表示可以随意访问该类中的方法

            m.setAccessible(true);

            // 调用doPrint方法

            m.invoke(instance, new Object[] { "Softworks" });

        } catch (Exception ex) {

            System.out.println(ex);

        }

    }

};

在该代码中,读者可能看到了一个比较陌生的方法setAccessible,这个方法非常重要,如果它不被设置成true那么所有非公有方法仍然无法调用,所以在调用非公有方法的时候需要注意这点。

Private属性的访问方式和方法的访问方式类似。

反射的实际应用

       在之前的介绍中,我们已经了解了反射机制的重要性,也已经了解到了反射经常被运用到系统框架设计和系统解耦中,现在就以一个真实的项目开发案例来探讨一下反射机制的重要性。

       1.什么叫系统耦合:

       或许很少有读者会在电影结束后做在电影院中观看电影的幕后工作者,但是可以肯定的是,如果没有那么多幕后工作者,那么就不会有诸如《指环王》等大片的出现了。但是如果真的要拍摄出像《指环王》这样的大片,光依靠强大的拍摄团队还不够,团队中的每个成员都必须要相互合作和交流,那么这种行为就被称为团队人员和团队人员的耦合关系。

       软件系统就如同刚才的电影拍摄团队,是有大量的类(工作人员)所组成的,那么这些类之间如果没有交互的话,整个软件系统就不可能正确合理的工作,因此软件系统中的耦合就来自于类与类之间的通讯,例如以下代码:

Cleaner clearner = new Cleaner(“Chen.yu”);

Broom broom = new Broom();

cleaner.clear(broom);

    通过这段代码,我们可以看出,Cleaner类和Broom之间有相互交互的关系,也就是说这两个类之间产生了耦合关系。请设想,代码如果有一个人来开发的话,耦合关系是不会影响到系统开发的。因为一个开发员可以理所当然的先开发Broom类再开发Clear类。可以软件工程是一个复杂的过程,一个人是不可能完成所有开发任务的,现在假设我们系统中的Cleaner类和Broom类一定要有两个人分别开发的话,那么问题就暴露出来了。因为根据代码可知,要想开发Cleaner类就必须先开发Broom类,Cleaner类中的方法clear需要使用Broom类的信息。那么究竟应该如何解决这个问题呢?      

       2.利用工厂模式解决耦合关系:

现在我把代码改写成以下的状态:

package cn.softworks.test;

import cn.softworks.demo.BeanFactory;

import cn.softworks.demo.Cleaner;

import cn.softworks.demo.IClearEquipment;

/**

 * 反射机制的测试类

 *

 * @version 1.0

 *

 * @author Chen.yu

 *

 * 上海Softworks对日软件人才培训中心版权所有

 */

public class TestClient {

    public static void main(String args[]) {

        //通过工厂创建指定的清洁工具类

        IClearEquipment eq =

            (IClearEquipment) BeanFactory.newInstance().creator("ClearEquipment");

        if(eq == null)

            return;

        //创建清洁工对象

        Cleaner cleaner = new Cleaner();

        //清洁工人开始清洁

        cleaner.clear(eq);

    }

}

 代码虽然多了,但是可以肯定的是在代码中我们只使用了Cleaner类,并没有使用到Broom类,那么Broom类上哪里去了呢?我们看到了IClearEquipment接口,Broom类正好实现了该接口,并且我们利用工厂模式BeanFactory完全隐藏了Broom类的创建细节,以此来解决Broom类与Cleaner类之间的耦合关系,现在Broom类和Cleaner类就可以交给2个开发员并行开发了。

以下是IClearEquipment接口的代码片断:

package cn.softworks.demo;

/**

 *

 * 该接口是的作用是用来定义清洁设备的标准<br>

 * 换句话说,如果要想成为清洁设备,那么就必须要具有清洁能力

 *

 * @version 1.0

 *

 * @author Chen.yu

 *

 * 上海Softworks对日软件人才培训中心版权所有

 */

public interface IClearEquipment {

    /**

     * 清洁设备的清洁方法<br>

     * 不同的清洁设备有不同的清洁方法

     *

     */

    public void clear();

}

以下是BeanFactory类的代码片断:

package cn.softworks.demo;

import java.io.IOException;

import java.io.InputStream;

import java.util.Properties;

/**

 * 该类的作用是从配置文件中读取类名,并依靠反射将指定类的实体<br>

 * 返回,以此达到“清洁工”类和“清洁设备”类之间的解耦<br>

 *

 * 该类被设置成了单例模式,并在创建指定类的时候加入了同步锁,<br>

 * 以此保证线程安全。

 *

 * @version 1.0

 *

 * @author Chen.yu

 *

 * 上海Softworks对日软件人才培训中心版权所有

 */

public class BeanFactory {

    /**

     * 单例工厂实体

     */

    private static BeanFactory instance = null;

    /**

     * 用于保存softworks.cfg.properties配置文件的实体。

     */

    private static Properties config = null;

    /**

     * 默认配置文件路径

     */

    private static final String CONFIG_PATH = "softworks.cfg.properties";

    /**

     * 使用了单例模式的工厂类默认构造函数

     *

     */

    private BeanFactory() {

        //得到配置文件的路径

        InputStream stream = Thread.currentThread().getContextClassLoader()

                .getResourceAsStream(CONFIG_PATH);

        config = new Properties();

        try {

            //将配置文件信息加载到config对象中

            config.load(stream);

        } catch (IOException e) {

            instance = null;

        }

    }

    /**

     * 创建BeanFactory实体的静态方法

     *

     * @return BeanFactory的单例实体

     */

    public synchronized static BeanFactory newInstance() {

        //判断BeanFactory的实体是否已经存在

        if (instance != null)

            return instance;

        //如果BeanFactory实体不存在那么立刻创建

        instance = new BeanFactory();

        return instance;

    }

    /**

     * 工厂了的创建方法,该方法可以用于创建配置文件中指定key名的类<br>

     * 现在配置文件中有如下信息:<br>

     * ClearEquipment=cn.softworks.demo.DustCollector<br>

     * 那么当参数被设置成ClearEquipment的时候,通过该方法就会创建<br>

     * cn.softworks.demo.DustCollector类的实体。

     *

     * @param key  配置文件中类所对应的Key

     *

     * @return     被加载类的实体

     */

    public synchronized Object creator(String key) {

        if(config == null)

            return null;

        //得到配置文件中的类名

        String className = config.getProperty(key);

        try {

            //通过反射机制创建类实体

            return Class.forName(className).newInstance();

        } catch (Exception e) {

            return null;

        }

    }

}

以下是Broom类的代码片断:

package cn.softworks.demo;

/**

 * 该类是用来描述扫帚这个清洁工具的<br>

 * 它实现了清洁工具接口,所以必须实现清洁方法

* @version 1.0

* @author Chen.yu

 * 上海Softworks对日软件人才培训中心版权所有

 */

public class Broom implements IClearEquipment {

    /**

     * 扫帚的清洁方法

     */

    public void clear() {

        System.out.println("The Cleaner Use Broom");

    }

}

以下是DustCollector类的代码片断:

package cn.softworks.demo;

/**

 * 该类是用来描述吸尘器这个清洁工具的<br>

 * 它实现了清洁工具接口,所以必须实现清洁方法

 * @version 1.0

 * @author Chen.yu

 * 上海Softworks对日软件人才培训中心版权所有

 */

public class DustCollector implements IClearEquipment {

    /**

     * 扫帚的清洁方法

     */

    public void clear() {

        System.out.println("The Cleaner Use Dust Collector");

    }

}

以下是Cleaner类的代码片断:

package cn.softworks.demo;

/**

 * 该类是用来描述一个清洁工人的<br>

 * 清洁工人会使用清洁设备来进行清洁工作的

 *

 * @version 1.0

 *

 * @author Chen.yu

 *

 * 上海Softworks对日软件人才培训中心版权所有

 */

public class Cleaner {

    /**

     * 这个方法的作用是定义清洁工人的清洁行为<br>

     * 可以肯定的是,清洁工人必须借助清洁设备才能清洁

     *

     * @param eq 使用的清洁设备

     */

    public void clear(IClearEquipment eq) {

        //清洁工人使用清洁设备进行清洁

        eq.clear();

    }

}

softworks.cfg.properties配置文件:

 ClearEquipment=cn.softworks.demo.DustCollector

代码工作原理:

通过以上代码可以知道,现在有一个清洁工类(Cleaner),两个清洁设备类(DustCollectorBroom他们都实现了清洁设备接口(IClearEquipment)),清洁工人的清洁方法(clear)明确要求指明,清洁工人究竟使用哪个清洁设备来开展工作,为了增加系统的灵活性,我们把清洁工人所需要使用的清洁设备在“softworks.cfg.properties”配置文件中做出了定义,并且利用BeanFactory从配置文件中读出了清洁设备的名字,利用反射机制将该清洁设备传入到了Cleaner类的clear方法中。这样一来系统的灵活读就上升了。如果系统需要更改清洁设备,那么我们只需要更改配置文件中的类名就可以了,整个系统的代码都不需要变更,因此反射机制不但解决了系统耦合,而且还大大增加了系统的灵活性。

       但是读者可能要问这样,那么CleanerBeanFactory之间的耦合性问题又显现出来了,这个问题又如何解决呢?

       以上这个问题我们可以利用Spring框架中的IoC(依赖注射)来解决。待续......

 上海Softworks软件人才培训中心
电话:021-53086530    53086531
地址:上海市北京东路668号科技京城东楼9楼E座
网址:
www.softworks.cn

  

Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=1589346