发布新日志

  • 我的学习方法

    2012-11-08 13:09:06

    目的

    目的就是这个技术完成什么功能,解决哪类问题。拿JSON举个例子:

    http://www.json.org/ 写道
    JSON (JavaScript. Object Notation) is a lightweight data-interchange format. It is easy for humans to read and write. It is easy for machines to parse and generate. It is based on a subset of the JavaScript. Programming Language, Standard ECMA-262 3rd Edition - December 1999. JSON is a text format that is completely language independent but uses conventions that are familiar to programmers of the C-family of languages, including C, C++, C#, Java, JavaScript, Perl, Python, and many others. These properties make JSON an ideal data-interchange language.



    JSON(JavaScript. Object Notation) 是一种轻量级的数据交换格式。易于人阅读和编写,同时也易于机器解析和生成。它基于JavaScript(Standard ECMA-262 3rd Edition - December 1999)的一个子集。 JSON采用完全独立于语言的文本格式,但是也使用了类似于C语言家族的习惯(包括C, C++, C#, Java, JavaScript, Perl, Python等)。这些特性使JSON成为理想的数据交换语言。

     

    从定义我们可以总结出几个关键点:

       轻量级

       数据交换格式

       易于编写和阅读

       基于JavaScript的一个子集

       纯文本独立于语言和平台

    重点是它以纯文本存储,可以独立于任何语言和平台,且主要用于数据交换。

     

    再比如Spring:

     http://www.oschina.net/p/spring/写道
    Spring Framework 是一个开源的Java/Java EE全功能栈(full-stack)的应用程序框架,以Apache许可证形式发布,也有.NET平台上的移植版本。该框架基于 Expert One-on-One Java EE Design and Development(ISBN 0-7645-4385-7)一书中的代码,最初由 Rod Johnson 和 Juergen Hoeller等开发。Spring Framework 提供了一个简易的开发方式,这种开发方式,将避免那些可能致使底层代码变得繁杂混乱的大量的属性文件和帮助类。
    Spring 中包含的关键特性:
    ……请前往http://www.oschina.net/p/spring/浏览

        Spring Framework官网 http://www.springsource.org/spring-framework

     

    从定义我们可以总结几个关键点:

    Java/JavaEE一站式解决方案(即不管是开发普通Java应用还是JavaEE企业应用都能提供解决方案)    

    框架基于 Expert One-on-One Java EE Design and Development(告诉我们需要去读这本书 这本书介绍了Spring设计思想)

    IoC容器(此时我们需要问什么是IoC容器)

    数据库事务的一般化抽象层(此时需要问自己怎么个一般化抽象)

    JDBC 抽象层(怎么个抽象法,比普通JDBC调用有哪些好处)

    等等……

     

    再比如Jsoup:

    http://jsoup.org/ 写道
    jsoup 是一款 Java 的HTML 解析器,可直接解析某个URL地址、HTML文本内容。它提供了一套非常省力的API,可通过DOM,CSS以及类似于JQuery的操作方法来取出和操作数据。

     从定义上可以总结几个关键点:

       Java版的HTML解析器

       提供了类似于DOM、CSS及类似于Jquery的操作方法来取出和操作数据(重点是DOM、CSS、Jquery我们都有所了解,再学这个应该不难)

     

    从一个技术的定义上,找关键词,我们能总结出它的核心目的。而且能提出一系列问题,有了这一系列问题我们能知道我们接下来要学习什么,只有了解了这些功能才能真正理解设计的目的和是什么。

     

    适用场景

    就是我们这个技术的适应的环境,可以在哪些场景中使用。

     

    比如JSON适用于:

      数据交换,尤其跨平台的数据交换 

      表示JavaScript对象

     

    比如Spring:

      在Java/JavaEE开发的整个过程中都有帮助。此时需要问有哪些帮助?为什么?

     

    比如Jsoup:

      只要我们想在Java里解析HTML就可以考虑使用它。

     

     

    如何使用

    到这一步其实是最简单的,可以按照如下步骤学习:

    1、根据官网的hello world进行简单入门,了解最基本的使用,到此我们入门了;

    2、如果官网提供了单元测试用例,最好的学习方式就是跟着单元测试挨着试,到此该技术的所有特性就有所了解了;

    3、写自己的功能,根据之前学的知识开始开发自己需要的功能;

    4、如果需要经常使用/涉及项目核心技术,一定要读读官方文档,有时间读读API做到心中有数。

     

    此处就不给例子了。

     

    类似的技术

    每当我们学习完一个新技术的时候,都要留一手,防止一个技术有bug/性能问题造成后续无替代方案。

     

    比如Jsoup类似的技术有:

    HTMLParser 

    NekoHTML

    这两个解析工具功能十分强大,但是使用上没有Jsoup简单。

     

    比如我要实现论坛内容过滤功能:

      过滤掉所有的事件注册,如<a nclick="……"> 需要删除onclick

      删除form相关的表单元素,防止恶意用户注入表单窃取用户数据

    这个功能我使用Jsoup实现的。

     

    比如我要抓取iteye的论坛内容(主题、内容、发布人、发布时间)等,使用Jsoup十分方便,因为它的选择器语法类似于Jquery语法,十分方便,而且学习成本很低,基本上只要会Jquery,10几分钟就能上手。

     

    优缺点

    我们应该对我们经常使用的核心技术做到心中有数,即了解优缺点,对于普通的技术只要基本会用即可(有时间可以做对比)。

     

    比如hibernate和ibatis,springMVC和struts2等等,做个对比,总结不出来几点说明自己对这个玩意还是了解不深,需要继续学习和研究。

     

    为什么

    对于一些项目中使用的核心技术,需要掌握:

    做好了解为什么,即为什么有这个东西,即了解发展历史和产生的背景

    如何实现的,读源码,知其所以然

    重复发明个轮子,这样可以更好的了解原理,而且学习效果更佳,这样比读N遍源码效果更好

     

    有朋友会说我看不到咋办?不会写啊! 

       告诉你个笨办法:

          之前我学习CGLIB,是照着人家单元测试挨着敲和试的;

          还有学习源码建议从低版本开始,因为功能少都是核心,好研究。

     

     

    在此学习过程中一定要把握度:

     有些东西只需了解目的和怎么如何即可; 

      有些需要理解到为什么,像spring、junit、slf4j/logback、ehcache、proxool、tomcat、ibatis等等,有时间多读点源代码或者自己造个轮子;尽量做到每一个方面都有涉及(出问题我不怕),但要专一,如spring。

     

     

    我的学习历程

    写自己的代码

    代码量非常重要,前期要写足一定量代码,再看一些书籍/读一些源码才有感觉。我是如何写代码的:

    1、项目代码,这个没得说,在写的过程中思考我们在读书时遇到的一些问题;

    2、在写项目的时候我们可能发现我们经常重复做一些事情,此时就需要考虑建立自己的代码工具库,如通用代码库、代码生成工具、常用工具类等; 不要重复自己,遇到重复的就考虑往自己工具箱添加可复用的组件;

    3、按照自己兴趣发展一个方向,此时可以考虑写一些相关的轮子;通过轮子再反过来深入学习其他相关的技术。

    4、如果有能力就考虑构建自己的平台,简化重复劳动,提升开发效率。

     

    发明轮子我觉得是很有必要的,光看不练没什么多大效果,发明个轮子可以帮助我们更好的理解,轮子不一定非得用到我们的项目,此时的轮子是帮助我们学习的。

     

    阅经典的书籍

    读大师经典著作,如

    《国外程序员推荐:每个程序员都应读的书》

    《一些经典的计算机书籍》

    或者关注如iteye等网站,推荐的一些好书。 我经常到 互动  itpub  图灵社区 等看一些新书。

     

    读书不是到用的时候再读,而是按照自己的方向和兴趣选择相关的书籍进行阅读,学习前人经验和思想,开阔自己思路。

     

    读书不是只读一遍,有些好书如《Effective Java》、《设计模式——可复用面向对象软件的基础》、《企业应用架构模式》、《敏捷软件开发:原则、模式与实践》、《面向对象软件构造》等需要重复读,因为时间段不同积累的经验不同,理解会产生改变,每次读都有不同的收获。

     

    读书读不懂没关系,先放一放,过一段时间再来看,经验到了自然就明白,不要刻意去背,刻意去记,一定要理解着记,记住要理论指导实践,实践检验理论,不可脱节。

     

    不能心急,一下子啃N页,像看小说似的,这样什么都学不到,记不住,即使今天记住了过了几天就忘了,所以要温故而知新。

     

    读书要思考自己之前遇到过类似的场景吗?对比着记更容易,而且记忆的成本会很低。

     

    不要光看自己使用的技术相关的,其他方面的如产品,测试,数据库等相关书籍也建议阅读。在此推荐一本产品入门书:

    《Don't Make Me Think》

     

    尤其在学习Java技术时,建议大家有时间把JDK的核心API(如java.lang/java.util等这些我们经常用的)读一下/还有相关的规范(规范是最权威的指南)。

     

    读优秀的代码

    阅读优秀的源代码可以帮助我们消化书籍中学到的理论,更好的去使用它,而且能开阔我们的思路,完善我们的思想。

     

    读源代码思路:

    1、从使用进行阅读,按照调用关系深入到源代码中,不要一口吃胖子;

    2、跟着单元测试走;

    3、只需读最核心部分即可,无需读所有代码;

    4、从简单的源码入手,刚开始放低难度,如阅读junit、slf4j、ehcache等相对简单的源码,再深入阅读如spring等源代码;

    5、阅读源代码要分而治之,一次读一块,不要混读,不要杂读。

     

    记自己的博客

    记博客可以思维缜密,完善知识体系,扎实技术;而且可以分享自己的经验想法,如果有错误会有朋友指正,非常好的学习方式。

     

    记博客思路:

    1、记录自己工作中遇到的问题及解决方案;自己既然遇到了别人也可能遇到;

    2、不要怕写的简单,没面子,我觉得要厚脸皮 

    3、任何东西都可以记,留作回忆。

     

    向同事的学习

    既然能作为同事,说明大家水平差不多,学习同事的优点。

     

    向同事学习思路:

    1、没事聊聊技术,听听它的想法;

    2、看他的源代码,从中学习;

    3、如果你的老大/同事都不上进,你又是很上进的,建议物以类聚,人以群分,换个环境好好发展自己。

     

    善于观察细节

    善于观察细节,比如从最基本的同事怎么操作的那么快(观察他是如何进行操作的,如发现自己不会的快捷键)?

     

    观察细节思路:

    1、眼要尖,善于发现自己不会的;

    2、嘴要勤,善于问自己不了解的(此处不是没事就去问,而是自己思考过,实在不会的,不要憋在肚子里,问一下又不会怀孕);

    3、没事读同事的源代码,这个可是免费的,从中能学到好的编码习惯和好的解决问题思路。

     

     

    学习没有捷径,我不聪明,但我刻苦;刻苦还是不够,得善于思考和总结。

    学习不要怕丢人,学到手是自己的,学会厚脸皮。

     

    希望对需要的人有所帮助,每个人都有自己的学习方法,可以借鉴学习,但不要临摹,适合自己的才是最好的。

     

    下一篇会《分享我是如何解决问题的》。

     

    PS:以上是本人总结,不对之处谢谢指正。

     

    新的一天又来了,上班去啦。,各位天天好心情!

     

    http://jinnianshilongnian.iteye.com/blog/1709268

  • Address already in use JVM_Bindnull80 解决方案

    2012-11-08 11:16:14

    1.  打开 开始---运行---cmd

    2.  进入Dos界面,输入  netstat -ano

    3.  查看被占用端口的 pid

    4.  然后进入任务管理器  查看---选择列--勾选PID

    5.  找到对应的PID,结束进程。 

  • java中Iterator的用法

    2011-10-29 15:24:03

    java中Iterator的用法  

    java.util包中包含了一系列重要的集合类。本文将从分析源码入手,深入研究一个集合类的内部结构,以及遍历集合的迭代模式的源码实现内幕。

       下面我们先简单讨论一个根接口Collection,然后分析一个抽象类AbstractList和它的对应Iterator接口,并仔细研究迭代子模式的实现原理。

       本文讨论的源代码版本是JDK 1.4.2,因为JDK 1.5在java.util中使用了很多泛型代码,为了简化问题,所以我们还是讨论1.4版本的代码。

      集合类的根接口Collection

       Collection接口是所有集合类的根类型。它的一个主要的接口方法是:

    DE>boolean add(Object c)DE>
       add()方法将添加一个新元素。注意这个方法会返回一个boolean,但是返回值不是表示添加成功与否。仔细阅读doc可以看到,Collection规定:如果一个集合拒绝添加这个元素,无论任何原因,都必须抛出异常。这个返回值表示的意义是add()方法执行后,集合的内容是否改变了(就是元素有无数量,位置等变化),这是由具体类实现的。即:如果方法出错,总会抛出异常;返回值仅仅表示该方法执行后这个Collection的内容有无变化。

       类似的还有:

    DE>boolean addAll(Collection c);
    boolean remove(Object o);
    boolean removeAll(Collection c);
    boolean remainAll(Collection c);
    DE>
       Object[] toArray()方法很简单,把集合转换成数组返回。Object[] toArray(Object[] a)方法就有点复杂了,首先,返回的Object[]仍然是把集合的所有元素变成的数组,但是类型和参数a的类型是相同的,比如执行:

    DE>String[] o = (String[])c.toArray(new String[0]);DE>
       得到的o实际类型是String[]。

       其次,如果参数a的大小装不下集合的所有元素,返回的将是一个新的数组。如果参数a的大小能装下集合的所有元素,则返回的还是a,但a的内容用集合的元素来填充。尤其要注意的是,如果a的大小比集合元素的个数还多,a后面的部分全部被置为null。

       最后一个最重要的方法是iterator(),返回一个Iterator(迭代子),用于遍历集合的所有元素。

      用Iterator模式实现遍历集合
     
       Iterator模式是用于遍历集合类的标准访问方法。它可以把访问逻辑从不同类型的集合类中抽象出来,从而避免向客户端暴露集合的内部结构。

       例如,如果没有使用Iterator,遍历一个数组的方法是使用索引:

    DE>for(int i=0; i<array.size(); i++) { ... get(i) ... }DE>
       而访问一个链表(LinkedList)又必须使用while循环:

    DE>while((e=e.next())!=null) { ... e.data() ... }DE>
       以上两种方法客户端都必须事先知道集合的内部结构,访问代码和集合本身是紧耦合,无法将访问逻辑从集合类和客户端代码中分离出来,每一种集合对应一种遍历方法,客户端代码无法复用。

       更恐怖的是,如果以后需要把ArrayList更换为LinkedList,则原来的客户端代码必须全部重写。

       为解决以上问题,Iterator模式总是用同一种逻辑来遍历集合:

    DE>for(Iterator it = c.iterater(); it.hasNext(); ) { ... }DE>
       奥秘在于客户端自身不维护遍历集合的"指针",所有的内部状态(如当前元素位置,是否有下一个元素)都由Iterator来维护,而这个Iterator由集合类通过工厂方法生成,因此,它知道如何遍历整个集合。

       客户端从不直接和集合类打交道,它总是控制Iterator,向它发送"向前","向后","取当前元素"的命令,就可以间接遍历整个集合。

       首先看看java.util.Iterator接口的定义:

    DE>public interface Iterator {
      boolean hasNext();
      Object next();
      void remove();
    }
    DE>
       依赖前两个方法就能完成遍历,典型的代码如下:

    DE>for(Iterator it = c.iterator(); it.hasNext(); ) {
      Object o = it.next();
      // 对o的操作...
    }
    DE>
       在JDK1.5中,还对上面的代码在语法上作了简化:

    DE>// Type是具体的类型,如String。
    for(Type t : c) {
    // 对t的操作...
    }
    DE>
       每一种集合类返回的Iterator具体类型可能不同,Array可能返回ArrayIterator,Set可能返回SetIterator,Tree可能返回TreeIterator,但是它们都实现了Iterator接口,因此,客户端不关心到底是哪种Iterator,它只需要获得这个Iterator接口即可,这就是面向对象的威力。

      Iterator源码剖析

       让我们来看看AbstracyList如何创建Iterator。首先AbstractList定义了一个内部类(inner class):

    DE>private class Itr implements Iterator {
    ...
    }
    DE>
       而iterator()方法的定义是:

    DE>public Iterator iterator() {
      return new Itr();
    }
    DE>
       因此客户端不知道它通过Iterator it = a.iterator();所获得的Iterator的真正类型。

       现在我们关心的是这个申明为private的Itr类是如何实现遍历AbstractList的:

    DE>private class Itr implements Iterator {
      int cursor = 0;
      int lastRet = -1;
      int expectedModCount = modCount;
    }
    DE>
       Itr类依靠3个int变量(还有一个隐含的AbstractList的引用)来实现遍历,cursor是下一次next()调用时元素的位置,第一次调用next()将返回索引为0的元素。lastRet记录上一次游标所在位置,因此它总是比cursor少1。

       变量cursor和集合的元素个数决定hasNext():

    DE>public boolean hasNext() {
      return cursor != size();
    }
    DE>
       方法next()返回的是索引为cursor的元素,然后修改cursor和lastRet的值:

    DE>public Object next() {
      checkForComodification();
      try {
       Object next = get(cursor);
       lastRet = cursor++;
       return next;
      } catch(IndexOutOfBoundsException e) {
       checkForComodification();
       throw new NoSuchElementException();
      }
    }
    DE>
       expectedModCount表示期待的modCount值,用来判断在遍历过程中集合是否被修改过。AbstractList包含一个modCount变量,它的初始值是0,当集合每被修改一次时(调用add,remove等方法),modCount加1。因此,modCount如果不变,表示集合内容未被修改。

       Itr初始化时用expectedModCount记录集合的modCount变量,此后在必要的地方它会检测modCount的值:

    DE>final void checkForComodification() {
      if (modCount != expectedModCount)
       throw new ConcurrentModificationException();
    }
    DE>
       如果modCount与一开始记录在expectedModeCount中的值不等,说明集合内容被修改过,此时会抛出ConcurrentModificationException。

       这个ConcurrentModificationException是RuntimeException,不要在客户端捕获它。如果发生此异常,说明程序代码的编写有问题,应该仔细检查代码而不是在catch中忽略它。

       但是调用Iterator自身的remove()方法删除当前元素是完全没有问题的,因为在这个方法中会自动同步expectedModCount和modCount的值:

    DE>public void remove() {
    ...
    AbstractList.this.remove(lastRet);
    ...
    // 在调用了集合的remove()方法之后重新设置了expectedModCount:
    expectedModCount = modCount;
    ...
    }
    DE>
       要确保遍历过程顺利完成,必须保证遍历过程中不更改集合的内容(Iterator的remove()方法除外),因此,确保遍历可靠的原则是只在一个线程中使用这个集合,或者在多线程中对遍历代码进行同步。

       最后给个完整的示例:

    DE>Collection c = new ArrayList();
    c.add("abc");
    c.add("xyz");
    for(Iterator it = c.iterator(); it.hasNext(); ) {
      String s = (String)it.next();
      System.out.println(s);
    }
    DE>
        如果你把第一行代码的ArrayList换成LinkedList或Vector,剩下的代码不用改动一行就能编译,而且功能不变,这就是针对抽象编程的原则:对具体类的依赖性最小。

    http://blog.163.com/heu_wgc/blog/static/463517620091051166545/

Open Toolbar