tbwshc

#

经验分享:我的JavaEE学习道路

 从很小都认识苹果机了,我不记得我是否在小学的时候学过Basic,只记得大学实验室里的苹果机我的确是摸过(得益于我是教师子弟,有“特殊待遇”),也看到计算机系的学生们编写的游戏。初中,有了自己的游戏机。玩过魂斗罗,坦克。当时觉得很不过瘾,心想以后能自己编写游戏就好了,于是立志以后做个程序员。

    高考不顺利,只考上了普通学校电力专业。这还是幸亏当时学校的罗老师(那四年,她一直都在帮助我)看到我以前的成绩还不错,决定要下我,否则,我就往下落的更厉害了。电力专业几乎没有计算机课程。等到学校关于自动化的时候,开始接触了汇编,和自学了C.当时很羡慕学计算机的那个女老乡,姓杨,呵呵,因为羡慕,还被别人误认为我喜欢她,其实完全不是,她根本对计算机没有兴趣,毕业后也去了当公务员,可惜啊,早知道如此,她何必要高出几分,占据我喜欢的专业呢,我甚至为此感到暗自不爽。 不过大学还是学到了一些计算机皮毛知识,C程序写的很好,记得写了一个模仿TT的打字程序。汇编也不错,写个文件病毒,源代码10K,编译链接后3K多,很大,AV95能识别出来,我想大概是我写的太烂,别的杀毒程序,象KV300,都不认为这是个病毒。不管怎么样,我没有拿这个干啥坏事情。这始终是不光彩的事情。

    该毕业了,家乡的供电局没能进去。我怨我老妈没有帮我跑关系,其实我跟我老妈都不愿意我去,我老妈是不想让我回铜仁,我自己也不想做电力职工(虽然在我们那是一等的暴有钱的工作),我还是喜欢去做个程序员,为此也退掉了别的电力相关的工作。但是,我始终不到该如何入门。毕业了,门卫老头开始赶我们出去,我工作无着落,同学们都已经回到家乡开始上班了,我还在跟老头打游击。他进我退,他退我上床休息,有次晚上洗澡,被他发现,吓得我光着屁股从三楼跑到5楼,再跑回三楼。呵呵,那时候整个宿舍楼都空了,所以也不算丢脸了。

    好运终于坚持到了,网上碰到一网友,后来我叫他秦哥,他说他需要一个人帮他做个网站。我便毛遂自荐了一下,其实,那时候我不懂做网站,不懂ASP,不过我相信我的能力,果然,一段适应时间后,我成了他得力的帮手,我也开始正式进入程序员这个行业了。相比现在的很多学生,我觉得他们比我幸运多了,在大学的时候都已经学习到很多知识,甚至是已经有一定的实践了。刚毕业就能踏入这行,还能有地方住,要知道我不光要跟老头打游击,有时候还睡在电脑城广场的板凳上,早上起来看的第一眼便是保安和他身边对我俯视眈眈的狼狗。

    搞懂了ASP和网站后,开始考虑学更多的东西,这时候我已经放弃了我编写游戏程序的梦想了,因为我跟本不知道如何去追逐这个梦想。我也放弃了我比较擅长的单片机开发(现在应该叫嵌入式)。我转向了Java.俗话说,女怕嫁错狼,男怕入错行。8年前的这个时候,我算是马马虎虎开始我的JavaEE道路吧,这儿有点体会就是一定要坚持自己的理想,而这个理想,应该能养活你的,能让你有兴趣做的事情。

    初学Java,有些迷惑,当时微软有个VJ++,我先买了一本介绍这样的书看,结构后来发现它主要是桌面程序的,而且,跟我知道的JSP不太一样。当时也没有想到可以找人问或者论坛上发给帖子问。幸好后来明智的转到了JSP,挺简单,跟ASP差不多,tb概念都能通用(毕竟处理的问题都一样嘛),比起现在的孩子来说,我当时学的东西太少了,不用学习hibernate,spring,j2ee,也不用学习ant,Junit什么的,呵呵,关键还是当时书太少,见识少,也没有这么多新玩意。好处就是我能深入JSP技术,为以后理解这些Web框架打下了很好的基础。不象现在的孩子,还搞不懂JSP,就去弄MVC,搞的本末倒置了。

    J2EE技术得到提高得益于后来到了北京,去了ZZ公司,现在看来,好不夸张的说,从这个公司出来的程序员,都有一定创新能力和解决问题能力。一到这公司,就做了一个算是大的项目,几十个人,还包括国防科技大学的数十个博士,当时用到了很多J2EE技术,象EJB,JMS都用到了,当时不懂这些,费了很多力气去学,还好项目本身就是个很好的学习材料。通过专研项目代码学到了不少东西,远比看书强多了。现在的很多培训方式都是通过做独立完成项目来学习技术,这是很有道理的。当时那个项目做了一年,期间我对自己要求蛮高的,总会多学点东西,比如学了EJB 无状态会话Bean,虽然项目没有用到有状态Bean,但还是花时间去搞明白。这个项目期间,头一次知道了还有英文资料这么一说,象什么Weblogic使用说明,Java文档都,我都会强迫自己去看,有时候打印下来,躺在小床,打开台灯看,那感觉真是美阿。

posted @ 2012-08-02 16:56 chen11-1| 编辑 收藏

J2ME编程程序开发平台的概念

对于J2ME编程开发平台,在其他平台风生水起的时候,J2ME编程开发平台似乎很沉寂。本文将简单介绍一下几个J2ME编程开发平台的重要概念。

  内存

  我们一直在强调,移动信息设备的内存非常小,使用起来应该加倍的珍惜,但是我们却很少知道这些内存是如何分类的,下面将做详细的介绍。事实上MIDP设备的内存分为三种,

  1.ProgrammeMemory、Heap、persistentStorage

  ProgrammeMemory是移动信息设备分配给MIDletsuite的空间,因为MIDletsuite是以jar文件进行发布的,所以这个文件的大小可以认为是ProgrammeMemory的大小。一些厂商对ProgrammeMemory的最大值是有限制的,例如我的Nokia6108的最大值是64k,超过的话将不能进行安装。减小MIDletsuite的大小非常重要,一个便捷的方法就是使用混淆器对应用程序进行混淆,这样可以减小jar文件的大小。在以后的文章中我会谈到如何使用Proguard.

  Heap是应用程序在运行过程中存放所创建的对象的存储空间,tb本地变量和成员变量也是放在Heap上的,MIDP设备中提供的Heap空间大概在几十k到几百K.

  PersistentStorage的空间是用来实现MIDP应用程序的本地数据持久性存储的,在RecordManagementSystem从入门到精通中我做了详细的介绍这里就不再多说了。

  2.ConnectedLimitedDeviceConfiguration

  CLDC包括一个Java虚拟机和一系列的基础类,J2ME的专家组经过对移动信息设备进行硬件抽象后得到他们的特点,然后设计并实现了在移动信息设备上运行的java虚拟机,通常我们把它叫做KVM.在CLDC1.0还同时提供了由java.io、java.lang、javax.microediton.io、java.util组成的基础类。在CLDC1.1里面添加了java.lang.ref.

  3.MobileInfomationDeviceProfile

  MIDP是运行在CLDC基础之上的,在MIDP中定义了应用程序的生命周期、用户图形界面、数据管理系统等子集,从而构建起了J2ME平台。通常,J2ME平台由一个CLDC和一个或者多个Profile构成。

posted @ 2012-08-01 16:40 chen11-1 阅读(660) | 评论 (0)编辑 收藏

jQuery绘图插件jCanvas 绘制窗口的技巧分享

 Jquery是继prototype之后又一个优秀的Javascrīpt框架。它是轻量级的js库,除了兼容CSS3外,还兼容各种浏览器+)。jQuery使用户能更方便地处理HTML documents、events、实现动画效果,并且方便地为网站提供AJAX交互。

  HTML5 中新定义的 HTML 元素,可以用来在 HTML 页面中通过 JavaScriptb 绘制图形、制作动画。现在要推荐的 jCanvas 就是一个 jQuery 的绘图插件,它封装了一些绘制图形的方法,只需编写几行代码即可生成图形。

  以下是JCanvas 绘制窗口并对其监听的程序代码分享

  import java.awt.*;

  import javax.swing.*;

  import java.awt.event.*;

  class JCanvas extends JComponent

  {

  public JCanvas()

  {

  setDoubleBuffered(true);

  }

  public void paintComponent(Graphics g)

  {

  Dimension size = getSize();

  g.setColor(getBackground());

  g.fillRect(0,0,size.width,size.height);

  }

  }

  class TestJCanvas

  {

  public static void main(String s[] )

  {

  MyWindowListener l = new MyWindowListener();

  JCanvas c = new JCanvas();

  c.setBackground(Color.yellow);

  JFrame f = new JFrame("Test JCanvas...");

  f.addWindowListener(l);

  f.getContentPane().add(c,BorderLayout.CENTER);

  f.pack();

  f.setSize(500,400);

  f.show();

  }

  }

  class MyWindowListener extends WindowAdapter

  {

  public void windowClosing(WindowEvent e)

  {

  System.exit(0);

  }

  }

posted @ 2012-08-01 16:37 chen11-1 阅读(1845) | 评论 (2)编辑 收藏

JavaScript框架:jQuery选择器精通教程

虽然jQuery上手简单,相比于其他库学习起来较为简单,但是要全面掌握,却不轻松。因为它涉及到网页开发的方方面面,提供的方法和内部变化有上千种之多。初学者常常感到,入门很方便,提高很困难。本文的目标是将jQuery选择器做一个系统的梳理,试图理清jQuery的设计思想,找出学习的脉络,使读者从入门到精通。

  jQuery是什么

  简单的说,jQuery是一个JavaScript框架,它的宗旨是:写更少的代码,做更多的事情。对于Web开发人员而言,jQuery是一个功能强大的JavaScript库,能更加快速开发相关应用,例如AJAX交互,JavaScript动画效果等。对于Web设计师而言,jQuery封装了Javascript源码细节,实现了与HTML标签的有效分离,便于设计师更加专注于Web页面设计效果。基于此,网页的用户体验大大增强,包括网页的交互性,视觉效果等等。

  jQuery的核心设计思想是:选择某个网页元素,然后对其进行某种操作。那么如何选择、定位某个网页元素呢?对于JavaScript开发人员而言,通常的一种手段是document.getElementById()。而在jQuery语法中,使用的是美元符号“$”,等价的选择表达式写法为:

var someElement = $("#myId");

  jQuery之所以称之为“jQuery”,主要就是因为它强大的选择器,也就是Javascript Query的意思。下面,我们具体介绍jQuery选择器相关的设计思想:

  一、jQuery基本选择器

  前面提到,选择器是jQuery的特色。jQuery的基本选择器主要分为tb以下五种类型:

  1. $(“#myId”) // 选择ID为myId的网页元素

  2. $(“标签名”) // 例如$(“div”)获取的就是HTML文档中的所有的div元素的jQuery对象集合

  3. $(“.myClass”) // 获取的是HTML文档中所有的class为“myClass”的元素集合

  4. $(“*”) // 这个获取的是HTML文档中的所有的元素

  5. $(“selector1,selector2,selector3…selectorN “) // 这种选择器叫做组选择器。例如:$(“span,#two”)

  // 选取所有的span标签元素和id=two的元素。

  二、jQuery层次选择器

  无论何时,通过jQuery选择器获取的jQuery对象任何时候都是一组元素。jQuery的层次选择器主要分为以下两种类型:

  1. $(“ancestor descendant”):选取parent元素后所有的child元素。ancestor的中文意思是“祖先”,descendant的中文意思是“后代”。例如:

  $(“body div”) 选取body元素下所有的div元素。

  $(“div#test div”) 选取id为“test”的div所包含的所有的div子元素

  2. $(“parent > child”):选取parent元素后所有的第一个child元素。例如:

  $(“body > div”) 选取body元素下所有的第一级div元素。

  $(“div#test > div”) 选取id为“test”的div所包含的所有的第一级div子元素
 三、jQuery过滤选择器

  jQuery最基本过滤选择器包括:

  1. :first // 选取第一个元素。$(“div:first”)选取所有div元素中的第一个div元素

  2. :last // 选取最后一个元素。$(“div:last”)选取所有div元素中的最后一个div元素

  3. :even // 选取索引是偶数的所有元素。$(“input:even”)选取索引是偶数的input元素。

  4. :odd // 选取索引是奇数的所有元素。$(“input:odd”)选取索引是奇数的input元素。

  5. :eq(index) // 选取索引等于index的元素。$(“input:eq(1)”)选取索引等于1的input元素。

  6. :gt(index) // 选取索引大于index的元素。$(“input:gt(1)”)选取索引大于1的input元素。

  7. :lt(index) // 选取索引小于index的元素。$(“input:lt(3)”)选取索引小于3的input元素。

  jQuery内容过滤选择器,可以轻松地对DOM文档中的文本内容进行筛选,从而准确地选取我们所需要的元素。

  1. :contains(text) // 选取含有文本内容为“text”元素。$(“div:contains(‘你’)”)选取含有文本“你”的div元素。

  2. :empty // 选取不包含子元素和文本的空元素。$(“div:empty”)选取不包含子元素(包括文本元素)的div空元素。

  3. :parent // 选取含有子元素或者文本的元素。$(“div:parent”)选取拥有子元素(包括文本元素)的div元素。

  可以看见,jQuery内容过滤选择器的过滤规则主要体现在它所包含的子元素或文本内容上。

  jQuery可见性过滤选择器的用法如下:

  1. :hidden // 选取所有不可见的元素。$(“:hidden”)选取网页中所有不可见的元素。

  2. :visible // 选取所有可见元素。$(“div:visible”)选取所有可见的div元素。

  jQuery属性过滤选择器的过滤规则是通过元素的属性来获取相应的元素。

  1. [attribute] // 选择拥有此属性的元素。$(“div[id]“)选取拥有属性id的元素。

  2. [attribute=value] // 选取属性值为value的元素。$(“div[name=test]“)选取属性name的值为“test”的div元素。

  3. [attribute!value] // 选取属性值不等于value的元素。

  4.[attribute^=value] // 选取属性的值以value开始的元素。

  5. [attribute$=value] // 选取属性的值以value为结束的元素。

  6. [attribute*=value] // 选取属性的值含有value的元素。

  7. [selector1] [selector2] [selectorN] //复合属性选择器。$(“div[id][name*=test]“)选取拥有属性id,且属性name的值含有“test”的div元素

  jQuery子元素过滤选择器的过滤规则相对于其它的选择器稍微有些复杂。

  1. :nth-child(index/even/odd/equation) // 选取每个父元素下的第index个子元素或者奇偶元素。

  2. :first-child // 选取每个父元素的第一个子元素

  3. :last-child // 选取每个父元素的最后一个子元素

  jQuery表单对象属性过滤选择器主要是对所选择的表单元素进行过滤,例如选择不可用的表单元素、被选中的下拉框、多选框等等。

  1. :enabled // 选取所有可用的表单元素。$(“#form1 :enabled”)选取id为“form1”的表单内的所有可用元素。

  2. :disabled // 选取所有不可用的表单元素。

  3. :checked // 选取所有被选中的元素。$(“input:checked”)选取所有被选中的元素。

  4. :selected // 选取所有被选中的选项元素。$(“select :selected”)选取所有被选中的选项元素(option)。

  jQuery中引入了表单选择器,让我们能极其方便地获取到一个表单中的某个或某类型的元素。

 

posted @ 2012-08-01 16:36 chen11-1 阅读(898) | 评论 (0)编辑 收藏

Java 异步消息处理

在前一节实现异步调用的基础上 , 现在我们来看一下一个完善的 Java 异步消息处理机制 .

[ 写在本节之前 ]

       在所有这些地方 , 我始终没有提到设计模式这个词 , 而事实上 , 多线程编程几乎每一步都在应该设计模式 . 你只要能恰如其份地应用它 , 为什么要在意你用了某某名称的模式呢 ?

       一个说书人它可以把武功招数说得天花乱坠 , 引得一班听书客掌声如雷 , 但他只是说书的 . 真正的武林高手也许并不知道自己的招式在说书人口中叫什么 , 这不重要 , 重要的是他能在最恰当的时机把他不知名的招式发挥到极致 !

       你了解再多的设计模式 , 或你写出了此类的著作 , 并不重要 , 重要的是你能应用它设计出性能卓越的系统 .

 

 

       本节的这个例子 , 如果你真正的理解了 , 不要怀疑自己 , 你已经是 Java 高手的行列了 . 如果你抛开本节的内容 , 五天后能自己独立地把它再实现一次 , 那你完全可以不用再看我写的文章系列了 , 至少是目前 , 我再也没有更高级的内容要介绍了 .

       上节的 Java 异步调用为了简化调用关系 , 很多角色被合并到一个类中实现 , 为了帮助大家改快地抓住核心的流程 . 那么一个真正的异步消息处理器 , 当然不是这样的简单 .

一.    它要能适应不同类型的请求 :

本节用 makeString 来说明要求有返回值的请求 . 用 displayString 来说明不需要返回值的请求 .

二.    要能同时并发处理多个请求 , 并能按一定机制调度 :

本节将用一个队列来存放请求 , 所以只能按 FIFO 机制调度 , 你可以改用 LinkedList, 就可以简单实现一个优先级 ( 优先级高的 addFirst, 低的 addLast).

三.    有能力将调用的边界从线程扩展到机器间 (RMI)

四.    分离过度耦合 , 如分离调用句柄 ( 取货凭证 ) 和真实数据的实现 . 分离调用和执行的过程 , 可以尽快地将调返回 .

 

现在看具体的实现 :

public interface Axman {

  Result resultTest(int count,char c);

  void noResultTest(String str);

}

这个接口有两个方法要实现 , 就是有返回值的调用 resultTest 和不需要返回值的调用

noResultTest, 我们把这个接口用一个代理类来实现 , 目的是将方法调用转化为对象 , 这样就可以将多个请求 ( 多个方法调 ) 放到一个容器中缓存起来 , 然后统一处理 , 因为 Java 不支持方法指针 , 所以把方法调用转换为对象 , 然后在这个对象上统一执行它们的方法 , 不仅可以做到异步处理 , 而且可以将代表方法调用的请求对象序列化后通过网络传递到另一个机器上执行 (RMI). 这也是 Java 回调机制最有力的实现 .

       一个简单的例子 .

       如果 1: 做 A

       如果 2: 做 B

如果 3: 做 C

如果有 1000 个情况 , 你不至于用 1000 个 case 吧 ? 以后再增加呢 ?

所以如果 C/C++ 程序员 , 会这样实现 : (c 和 c++ 定义结构不同 )

 

type define struct MyStruct{

int mark;

(*fn) ();

} MyList;

      

       然后你可以声明这个结构数据 :

       {1,A,

         2,B

         3,C

}

做一个循环 :

for(i=0;i<length;i++) {

       if( 数据组 [i].mark == 传入的值 ) ( 数据组 [i].*fn)();

}

简单说 c/c++ 中将要被调用的涵数可以被保存起来 , 然后去访问 , 调用 , 而 Java 中 , 我们无法将一个方法保存 , 除了直接调用 , 所以将要调用的方法用子类来实现 , 然后把这些子类实例保存起来 , 然后在这些子类的实现上调用方法 :

interface My{

       void test();

}

 

class A implements My{

       public void test(){

              System.out.println(“A”):

}

}

class B implements My{

       public void test(){

              System.out.println(“B”):

}

}

 

class C implements My{

       public void test(){

              System.out.println(“C”):

}

}

 

class MyStruct {

      

       int mark;

       My m;

       public MyStruct(int mark,My m){this.mark = amrk;this.m = m}

}

数组 :

{ new MyStruct(1,new A()),new MyStruct(2,new B()),new MyStruct(3,new C())}

for(xxxxxxxxx) if( 参数 == 数组 [i].mark) 数组 [i].m.test();

 

这样把要调用的方法转换为对象的保程不仅仅是可以对要调用的方法进行调度 , 而且可以把对象序列化后在另一台机器上执行 , 这样就把调用边界从线程扩展到了机器 .

 

回到我们的例子 :

class Proxy implements Axman{

  private final Scheduler scheduler;

  private final Servant servant;

 

  public Proxy(Scheduler scheduler,Servant servant){

    this.scheduler = scheduler;

    this.servant = servant;

  }

  public Result resultTest(int count,char c){

    FutureResult futrue = new FutureResult();

    this.scheduler.invoke(new ResultRequest(servant,futrue,count,c));

    return futrue;

  }

 

  public void noResultTest(String str){

    this.scheduler.invoke(new NoResultRequest(this.servant,str));

  }

}

 

其中 scheduler 是管理对调用的调度 , servant 是真正的对方法的执行 :

 

Servant 就是去真实地实现方法 :

 

class Servant implements Axman{

  public Result resultTest(int count,char c){

    char[] buf = new char[count];

    for(int i = 0;i < count;i++){

      buf[i] = c;

      try{

        Thread.sleep(100);

      }catch(Throwable t){}

    }

    return new RealResult(new String(buf));

  }

 

  public void noResultTest(String str){

    try{

      System.out.println("displayString :" + str);

      Thread.sleep(10);

    }catch(Throwable t){}

  }

}

在 scheduler 将方法的调用 (invkoe) 和执行 (execute) 进行了分离 , 调用就是开始 ” 注册 ” 方法到要执行的容器中 , 这样就可以立即返回出来 . 真正执行多久就是 execute 的事了 , 就象一个人点燃爆竹的引信就跑了 , 至于那个爆竹什么时候爆炸就不是他能控制的了 .

public class Scheduler extends Thread {

  private final ActivationQueue queue;

  public Scheduler(ActivationQueue queue){

    this.queue = queue;

  }

 

  public void invoke(MethodRequest request){

    this.queue.putRequest(request);

  }

 

  public void run(){

    while(true){

 

      // 如果队列中有请求线程 , 测开始执行请求

      MethodRequest request = this.queue.takeRequest();

      request.execute();

    }

  }

}

在 schetbduler 中只用一个队列来保存代表方法和请求对象 , 实行简单的 FIFO 调用 , 你要实更复杂的调度就要在这里重新实现 :

class ActivationQueue{

  private static final int MAX_METHOD_REQUEST = 100;

  private final MethodRequest[] requestQueue;

  private int tail;

  private int head;

  private int count;

 

  public ActivationQueue(){

    this.requestQueue = new MethodRequest[MAX_METHOD_REQUEST];

    this.head = this.count = this.tail = 0;

  }

 

  public synchronized void putRequest(MethodRequest request){

    while(this.count >= this.requestQueue.length){

      try {

        this.wait();

      }

      catch (Throwable t) {}

    }

    this.requestQueue[this.tail] = request;

    tail = (tail + 1)%this.requestQueue.length;

    count ++ ;

    this.notifyAll();

 

  }

 

 

  public synchronized MethodRequest takeRequest(){

    while(this.count <= 0){

      try {

        this.wait();

      }

      catch (Throwable t) {}

 

    }

 

    MethodRequest request = this.requestQueue[this.head];

    this.head = (this.head + 1) % this.requestQueue.length;

    count --;

    this.notifyAll();

    return request;

  }

}

 

为了将方法调用转化为对象 , 我们通过实现 MethodRequestb 对象的 execute 方法来方法具体方法转换成具体对象 :

abstract class MethodRequest{

  protected final Servant servant;

}

posted @ 2012-07-31 15:38 chen11-1 阅读(2570) | 评论 (0)编辑 收藏

Java模拟异步消息的发送与回调

本文的目的并不是介绍使用的什么技术,而是重点阐述其实现原理。

 

一、 异步和同步

讲通俗点,异步就是不需要等当前执行的动作完成,就可以继续执行后面的动作。

 

通常一个程序执行的顺序是:从上到下,依次执行。后面的动作必须等前面动作执行完成以后方可执行。这就是和异步相对的一个概念——同步。

 

案例:

A、张三打电话给李四,让李四帮忙写份材料。

B、李四接到电话的时候,手上有自己的工作要处理,但他答应张三,忙完手上的工作后马上帮张三写好材料,并传真给张三。

C、通完电话后,张三外出办事。

 

说明:

张三给李四通完电话后,就出去办事了,他并不需要等李四把材料写好才外出。那么张三让李四写材料的消息就属于异步消息。

相反,如果张三必须等李四把材料写好才能外出办事的话,那么这个消息就属于同步消息了。

 

二、 异步的实现

传统的程序执行代码都是从上到下,一条一条执行的。

但生活中有很多情况并不是这样,以上的案例中,如果李四需要几个小时以后才能帮张三写好材料的话,那张三就必须等几个小时,这样张三可能会崩溃或者抓狂。

 

这种一条龙似的处理,显示不太合理。

 

可以使用以下办法来处理这种问题:

张三找王五去给李四打电话,等李四写好材料后,由王五转交给张三。这样张三就可以外出办其他的事情了。

 

问题得到了合理的解决,之前张三一条线的工作,由张三和王五两条线来完成了,两边同时进行,彼此不耽误。

 

三、 计算机语言的实现

办法有了,如何用程序来模拟实现呢?

 

A、以前由一个线程来处理的工作,可以通过新增一个线程来达到异步的目的。这也就是JAVA中的多线程技术。

B、最后李四写好的材料必须交给张三,以做他用。这就是回调。

 

回调你可以这样来理解:

A发送消息给B,B处理好A要求的事情后,将结果返回给A,A再对B返回的结果来做进一步的处理。

 

四、 Java代码的实现

A、 回调的实现

 


Java代码tb 
  
public interface CallBack {   
      
    public void execute(Object... objects );   
 
public interface CallBack { public void execute(Object... objects ); }

 

Java是面向对象的语言,因此回调函数就变成了回调接口。

 

B、 消息的发送者

 


Javatb代码
  
public class Local implements CallBack,Runnable{   
       
      
    private Remote remote;   
       
      
    private String message;   
       
    public Local(Remote remote, String message) {   
        super();   
        this.remote remote;   
        this.message message;   
    }   
  
      
    public void sendMessage()   
    {   
          
        System.out.println(Thread.currentThread().getName());   
          
        Thread thread new Thread(this);   
        thread.start();   
          
        System.out.println("Message has been sent by Local~!");   
    }   
  
      
    public void execute(Object... objects {   
          
        System.out.println(objects[0]);   
          
        System.out.println(Thread.currentThread().getName());   
          
        Thread.interrupted();   
    }   
       
    public static void main(String[] args)   
    {   
        Local local new Local(new Remote(),"Hello");   
           
        local.sendMessage();   
    }   
  
    public void run() {   
        remote.executeMessage(message, this);   
           
      

C、 远程消息的接收者

 

 


Java代码
  
public class Remote {   
  
      
    public void executeMessage(String msg,CallBack callBack)   
    {   
          
        for(int i=0;i<1000000000;i++)   
        {   
               
        }   
          
        System.out.println(msg);   
        System.out.println("I hava executed the message by Local");   
          
        callBack.execute(new String[]{"Nice to meet you~!"});   
    }   
       
 
public class Remote { public void executeMessage(String msg,CallBack callBack) { for(int i=0;i<1000000000;i++) { } System.out.println(msg); System.out.println("I hava executed the message by Local"); callBack.execute(new String[]{"Nice to meet you~!"}); } }

  

执行Local类的main方法。

 

注意Local类中红色背景的那行:

remote.executeMessage(message, this);

executeMessage方法需要接收一个message参数,表示发送出去的消息,而CallBack参数是他自己,也就是这里的this。表示发送消息后,由Local类自己来处理,调用自身的execute方法来处理消息结果。

如果这里不是用this,而是用其他的CallBack接口的实现类的话,那就不能称之为“回调”了,在OO的世界里,那就属于“委派”。也就是说,“回调”必须是消息的发送者来处理消息结果,否则不能称之为回调。这个概念必须明确。

posted @ 2012-07-31 15:35 chen11-1 阅读(1553) | 评论 (0)编辑 收藏

java实现异步调用实例

在JAVA平台,实现异步调用的角色有如下三个角色:
 
调用者 取货凭证   真实数据
 
一个调用者在调用耗时操作,不能立即返回数据时,先返回一个取货凭证.然后在过一断时间后
凭取货凭证来获取真正的数据.
 
所以连结调用者和真实数据之间的桥梁是取货凭证.我们先来看它的实现:
 
public class FutureTicket{
 private Object data null;
 private boolean completed false;
 
 public synchronized void makeRealData(){
  if(this.complited) return;
  //获取数据的耗时操作.这里用Sleep代替
  try{
   Thread.sleep(10000);
  }catch(Throwable t){}
  this.data "返回的数据内容";
  this.completed true;
  notifyAll();
 }
 
 public synchronized Object getData(){
  while(!this.completed)){
   try{
    wait();
   }catch(Throwable t){}
  }
  return this.data;
  
 }
 public boolean isCompleted(){
  return this.completed;
 }
}
 
为了简单化说明(不把它们的关系开得复杂),这里用Objectb代替了真实数据.而真实的实现中
我们应该把makeData放在一个真实数据的类中,然后提供一个方法返回真实数据.这样对于真实
数据的处理和取货凭证解耦.
 
对于这个取货凭证,调用者的如何调用是异步调用的关键:
 
publc class Requester{
 public FutureTicket request(){
  final FutureTicket ft new FutureTicket();
  
  //在新线程中调用耗时操作
  new Thread(){
   public void run(){
    ft.makeRealData();
   }
  }.start();
  return ft;
 }
}
在新线程中启动耗时操作后,不等待线程的完成立即返回提货单.
 
然后调用者可以根据ft.isCompleted()来调用getData()获取真实数据.
当然对ft.isCompleted()测试可以按规定时间间隔轮巡(极低级的方案),也可以
在条件不满足时wait(),然后等待makeData的notifyAll();这样你就完成了一个
用JAVA模拟的异步操作.
 

改进:
但这样的调用对于调用者来说仍然要继续控制线程操作.如果调用者是一个资深的
程序员,这当然没有问题.但假如我们把对直接数据的处理委托给取货凭证来做.调用
者直接规定对数据的操作,然后由取货凭证来调用规定的操作,这对于调用者是一个很
好的解脱:
 
interface ProcessData{
 public void process(Onject data);
}
 
public MyProcessData{
 public void process(Object data){
  //你不管什么时候起初数据data被获取了.
  //你只要规定如果获取到数据了如何处理
  
  System.out.println(data.toString() "处理完成...........");
  //insert into dataBase?
 }
}
 
取货凭证在接收调用者请求获取数据时,要知道对获取的数据如何处理的方法:
 
public class FutureTicket{
 private Object data null;
 private boolean completed false;
 private ProcessData pd;
 
 public FutureTicket(ProcessData pd){
  this.pd pd;
 }
 public synchronized void makeRealData(ProcessData pd){
  if(this.complited) return;
  //获取数据的耗时操作.这里用Sleep代替
  try{
   Thread.sleep(10000);
  }catch(Throwable t){}
  this.data "返回的数据内容";
  this.completed true;
  notifyAll();
 }
 
 public synchronized void putData(){
  while(!this.completed)){
   try{
    wait();
   }catch(Throwable t){}
  }
  //return this.data;
  //不用返回了,直接处理
  this.pd.process(this.data);
  // alert(?);
  
 }
 

 //这个方法也可以不要了.
 public boolean isCompleted(){
  return this.completed;
 }
}
 
调用:
 
  final FutureTicket ft new FutureTicket(new ProcessData());
  
  //在新线程中调用耗时操作
  new Thread(){
   public void run(){
    ft.makeRealData();
   }
  }.start();
  ft.putData();
 
OK,你现在可以抽烟,喝酒,泡妞.ft会为你完成所有的工作.

posted @ 2012-07-31 15:16 chen11-1 阅读(22725) | 评论 (9)编辑 收藏

用线程池启动定时器

(1)调用ScheduledExecutorService的schedule方法,返回的ScheduleFuture对象可以取消任务。
(2)支持间隔重复任务的定时方式,不直接支持绝对定时方式,需要转换成相对时间方式。

Java代码  
  1. Executors.newScheduledThreadPool(3).schedule(new Runnable() {          
  2.          @Override  
  3.            public void run() {   
  4.             System.out.println("响");           
  5.         }   
  6.           }, 10,TimeUnit.SECONDS);       //在10秒后响一次  
 
Java代码  
  1. Executors.newScheduledThreadPool(3).scheduleAtFixedRate(new Runnable() {        //频率   
  2.             @Override  
  3.             public void run() {   
  4.                 // TODO Auto-generated method stub   
  5.             System.out.println("响");           
  6.              }   
  7.            },    
  8.         6,   
  9.         2,   
  10.                 TimeUnit.SECONDS);       //在10秒后响之后,每隔2秒响一次  
 

posted @ 2012-07-27 15:04 chen11-1 阅读(1348) | 评论 (0)编辑 收藏

xml语法 学习

一个xml文件分为几部分内容:
文档声明
元素
属性
注释
CDATA区,特殊字符
处理指令

在编写xml文档,需要先使用文档声明,声明xml文档的类型。
最简单的声明语法:
<?xml version="1.0"?>
用encoding 属性说明文档的字符编码:
<?xml version="1.0" encoding="gb2312"?>
用standalone属性说明文档是否独立:
<?xml version="1.0" encoding="gb2312" standalone="yes"?>

元素
xml元素指的xml文件出现的标签,分为开始标签和结束标签。
一个xml元素可以包含字母,数字以及其他可见字符,但是遵守下面的一些规范:
区分大小写
不能以数字或特殊字符开头
不能以xml开头
不能包含空格
名称中间不能包含冒号

注释
xml文件的注释采用 <!--注释-->

CDATA区别
在编写xml文件时,有些内容可能不想让解析引擎解析执行,而是当作原始内容处理,把这些内容放在CDATA区。
对于CDATA区域内的内容,tb解析程序不会处理,而是直接原封不动的输出。
语法:
<![CDATA[内容]]>


转义字符
对于一些单个字符,如果显示原始样式,可以使用转义形式给于处理。
特殊符号    替代符号
&               &amp
<                &lt
>                &gt
"                &quot

处理指令
处理指令,简称PI。处理指令用来指挥解析引擎如何解析xml文档内容。
处理指令必须要以<?作为开头,以>作为结尾。

posted @ 2012-07-27 15:02 chen11-1 阅读(773) | 评论 (0)编辑 收藏

xml约束

xml约束
编写一个文档来约束一个xml文档的书写规范

常用的约束技术

XML DTD
XML Schema

DTD(Document Type Definition),全程为文档类型定义
举例:
文件清单:book.xml

Java代码  
  1. <?xml version="1.0" encoding="UTF-8"?>   
  2. <!DOCTYPE 图书 SYSTEM "book.dtd">          
  3. <图书>   
  4.      <书>   
  5.             <书名>西游记</书名>   
  6.             <作者>吴承恩</作者>     
  7.             <售价>18</售价>     
  8.      </书>   
  9.      <书>   
  10.           <书名>三国演义</书名>   
  11.           <作者>罗贯中</作者>     
  12.           <售价>20</售价>   
  13.      </书>    
  14. </图书>  

   文件清单:book.dtbd

Java代码  
  1. <?xml version="1.0" encoding="UTF-8"?>   
  2. <!ELEMENT 图书 (书+)>   
  3. <!ELEMENT 书 (书名,作者,售价)>   
  4. <!ELEMENT 书名 (#PCDATA)>   
  5. <!ELEMENT 作者 (#PCDATA)>   
  6. <!ELEMENT 售价 (#PCDATA)>  

 

 

ELEMENT 元素

PCDATA 的意思是已经解析的字符数据,文本中的标签会被当作标记来处理,而实体会被展开。
用book.dtd约束book.xml,如果在book.xml的书标签下添加出版日期,会报错,因为文档格式已经固定。
注意:DTD文件应使用utf-8保存或者encoding="gb2312",否则会报错。

引用DTD约束
xml文件使用DOCTYPE声明语句来指明它所遵循的DTD文件,声明语句有两种形式
(1)当引用的文件在本地时 ,采用如下方式:
<!DOCTYPE 文档根节点 system "DTD文件的URL"> 
例如:<!DOCTYPE 图书 SYSTEM "book.dtd">  
(2)当引用的文件是一个公共的文件时 ,采用如下方式:
<!DOCTYPE 文档根节点 public "DTD名称" "DTD文件的URL">
例如:<!DOCTYPE struts-config PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 1.3//EN"
 "http://struts.apache.org/dtds/struts-config_1_3.dtd">
 struts2的DTD文件,一般做框架都会用到DTD

DTD约束语法细节
元素定义
属性定义
实体定义

元素定义
在DTD文件中使用element声明一个xml元素,语法格式所示:
<!ELEMENT 元素名称 元素类型>
(1)元素类型可以是元素内容或者类型
如为元素内容:则需要使用()括起来,如
<!ELEMENT 书 (书名,作者,售价)>
<!ELEMENT 书名 (#PCDATA)>
(2)如为元素类型,则直接书写 ,DTD规范定义如下几种类型:
EMPTY:用于定义空元素,例如<br></br>
ANY:表示元素内容为任意类型
-----------------------------------------------------
元素内容可以使用如下方式,描述内容的组成关系用逗号分隔,表示内容的出现顺序必须与声明时一致
用逗号分隔,表示内容的出现顺序必须与声明时一致。
<!ELEMENT 书 (书名,作者,售价)>
用|分隔,表示任选其一,即多个只能出现一个
<!ELEMENT 书 (书名|作者|售价)>
在元素内容中也可以使用+,*,?等符号表示元素出现的次数:
+:一次或多次(书+)
0:0次或一次(书?)
*:0次或多次(书*)
什么都不写 (书)只出现一次

也可以使用原括号()批量设置,例
<!ELEMENT 书((书名*,作者?售价)*|COMMENT)>

属性定义
xml文档的标签性需要通过ATTLIST为其设置属性
语法格式:
<!ATTLIST 元素名
属性名1 属性值类型 设置说明
属性名2 属性值类型 设置说明
......
>
属性声明举例
<!ATTLIST 图书
  书名 CDATA #REQUIRED
  售价 CDATA #IMPLED
>
对应xml文件:
<图书 书名="三国演义" 售价="20">...</图书>
<图书 书名="西游记" 售价="18">...</图书>
设置说明:
#REQUIRED 必须设置该属性
#IMPLED 可以设置也可以不设置
#FIXED:说明该属性的值固定为一个值
直接使用默认值:在xml中可以设置该值也可以不设置该属性值。如果没设置则使用默认值
举例:
<!ATTLST 图书
书名 CDATA #REQUIRED
售价 CDATA #IMPLED
类别 CDATA #FIXED "文学"
评价 CDATA "好"
>
-----------------------------------------------
CDATA表示属性值为普通文本字符串
ENUMERATED(枚举)
ID,表示设置值为一个唯一值,ID属性的值只能由字母,下划线开始,不能出现空白字符
ENTITY(实体)


实体定义
实体用于为一段内容创建一个别名,以后在xml文档中就可以使用别名引用这段内容
在DTD定义一个实体,一条<!ENTITY>语句用于定义一个实体
实体可分为两种类型:引用实体个参数实体
(1)引用实体主要在xml文档中被应用
语法格式:
<!ENTITY 实体名称 "实体内容">: 直接转变成实体内容
引用方式:
&实体名称;
举例
<!ENTITY name "I am a student">
.....
&name;
(2)参数实体被DTD文件自身使用
语法格式:
<!ENTITY % 实体名称 "实体内容">
&实体名称;

 

在struts1里action标签必须要设置的属性:path

Java代码  
  1. <!ELEMENT action (icon?, display-name?, description?, set-property*, exception*, forward*)>   
  2. <!ATTLIST action         id             ID              #IMPLIED>   
  3. <!ATTLIST action         attribute      %BeanName;      #IMPLIED>   
  4. <!ATTLIST action         className      %ClassName;     #IMPLIED>   
  5. <!ATTLIST action         forward        %RequestPath;   #IMPLIED>   
  6. <!ATTLIST action         include        %RequestPath;   #IMPLIED>   
  7. <!ATTLIST action         input          %RequestPath;   #IMPLIED>   
  8. <!ATTLIST action         name           %BeanName;      #IMPLIED>   
  9. <!ATTLIST action         parameter      CDATA           #IMPLIED>   
  10. <!ATTLIST action         path           %RequestPath;   #REQUIRED>   
  11. <!ATTLIST action         prefix         CDATA           #IMPLIED>   
  12. <!ATTLIST action         roles          CDATA           #IMPLIED>   
  13. <!ATTLIST action         scope          %RequestScope;  #IMPLIED>   
  14. <!ATTLIST action         suffix         CDATA           #IMPLIED>   
  15. <!ATTLIST action         type           %ClassName;     #IMPLIED>   
  16. <!ATTLIST action         unknown        %Boolean;       #IMPLIED>   
  17. <!ATTLIST action         validate       %Boolean;       #IMPLIED>  

posted @ 2012-07-27 15:00 chen11-1 阅读(998) | 评论 (0)编辑 收藏

仅列出标题
共20页: First 上一页 8 9 10 11 12 13 14 15 16 下一页 Last