2002年初,因为公司的业务需要而学习java,并应用java开发项目。由于项目时间紧,没有充裕的时间系统学习java,对java的学习只能是项目需要用什么,就学什么,这种学习方法的上手快,但不扎实,在以后的工作中,因为java学的不扎实,吃了不少苦头。现在我学习应用java已经有一年半的时间,对java已经有了一定的体会,把自己的体会写出来,供网友分享。
以我个人的经验,学习java应分以下几个阶段:
- java的语法学习
- 面向对象观念的建立
- java基本类库的学习
- 学习设计模式
- 应用设计模式
- 经过大量的实践,可以设计模式
以上六个阶段,其中前三个阶段是针对java的,但java中,在很多设计模式的应用,同时有很多功能都支持设计模式,所以不懂设计模式的人是不会很好的应用java做开发的。第4、5个阶段的学习在前三个阶段的基础上,学习、应用成功的经验。从而进入第六个阶段,在软件设计这个领域尽情发挥。本人受能力所限,还处在第4个阶段的学习过程,所以会对前四个阶段说明。第五、六个阶段只是我根据我自己的知识做的推断,还没有经验无法说明。
在对这些学习阶段进行阐述之前,我先说一下我的学习方法。在学习新的知识时我通常是按以下三个阶段学的
- 理论学习。通过对理论的学习,尽量了解新知识的概念;学习之后只是粗略的了解概念,不能和实际很好的结合。
- 演绎阶段。根据理论学习的知识,考虑在什么场合下可以应用这个新知识,哪些地方已经应用了这个概念,建立对新知识的感性认识。
- 归纳阶段。从一个更深的层次理解理论。
以下根据java的六个学习阶段阐述我的体会,而每个阶段将按照理论学习、演绎和归纳三个小阶段讨论。
- java语法的学习
语法学习的理论学习阶段是最容易的阶段,70%以上的java书主要介绍的就是java语法,随意买来一本,通读一下就可以,主要理解以下内容:(1)数据类型,(2)操作符,(3)控制流程,(4)类和类再生,(5)包和接口,(6)异常操作。
在理论学习阶段,不必过于注重细节,只要对java的基本语法有一个整体认识,能读懂示例的源代码就可以了。
下一步就是演绎阶段,应用所学的语法知识,编写简单的程序。最好凭自己的记忆,将各语法要点都用一遍(编写代码最好用notepad),对自己不熟悉的语法要重新阅读,用编译器去检查语法错误。这个阶段的目标是脱离书本以及java API能编写简单的程序,阅读一个java源代码能说出执行结果。
完成这个阶段的学习,参加scjp的考试,应该获得较高的成绩。
在演绎阶段的基础上,根据自己犯过的错误,总结一下java的难点。重新阅读语法书,将一些自己不是很清楚的概念重新整理一下,这时你对java语法的理解比第一次阅读时更深了。
我在刚开始学java时,只是粗略的看看语法书,就开始编程序了,遇到不懂的就重新阅读语法书,这样,完全可以成为一个合格程序员,但是当我成为team leader时,为了培训组员java编程,却发现自己脱离了java语法书和Java API,竟然会的不多(java集成开发工具有提示功能),为了培训,我又重新学了一遍java语法,很有收获。
其实一个优秀的程序员,不但要能写出好的程序,更重要的是,对所写的程序能说的清楚:(1)说清楚程序的功能(2)说清楚程序的结构。而说清楚程序的结构的基础是对java的语法要熟悉。想成为优秀的程序员,一定要在学习语法的基础上,不断实践,不断总结,最终能脱离语法书,将java语法系统的讲解清楚。
- 面向对象观念的建立
Java是面向对象的开发工具,使用java开发应用时,一定要懂面向对象编程的概念。在学过了java语法之后,应该建立OOP的概念。
- 理论学习阶段,首先应当理解class和object,了解class、interface、abstract class,理解OOP的继承性,封装性(public, protected,private)和多态性。然后应当熟悉UML,可以阅读一些UML的简单资料,基本上了解类图、状态图和时序图就可以了。
- 演绎阶段,对OOP的实践。而OOP的成功范例应该是常见的23种设计模式。这个阶段需要阅读并体会设计模式UML图和示例代码,我推荐《java与模式》这本书,也可以访问http://www.jdon.com/designpatterns/index.htm 。不必读懂模式,只需要读懂每个模式的UML和代码。
- 归纳阶段,通过演绎阶段的学习,体会OOP带来的好处——对扩展开放,对修改关闭。同时学会如何在java中使用OOP的概念设计。
我在使用Java编程初期,一直使用面向过程的思想编程,对class、interface、abstract class以及public、protect、private的存在并没有理解,直到我阅读了Gof的设计模式,才理解OOP的优点。但是Gof的设计模式太晦涩了,我第一次读时,仅仅是有了面向对象的概念,而对设计模式并没有理解。相反《java与模式》容易读一些,但《java与模式》一书的废话多一些,有很多内容可以不读。
- java基本类库的学习
曾经面试过一些java程序员,我出的题目是在使用java时,经常用到哪些类,在哪个包里。很少有人能答好,甚至有人做了2年java程序都没有回答出,他们会用java,但必须依赖工具(指java集成开工具),我觉得他们可以编写出程序,但不能编写出特别好得程序。
我认为作为java程序员必须掌握java类库的两个包:java.lang和java.util这两个包。java.lang包提供的是java编程要用到的基本类包,java程序员天天在用,无非是看别人如何用,自己就如何用,但很少有人去总结一下,比如String 和StringBuffer这两个类有什么差别,应该有很多java程序员说不出来。另外Vector和HashMap这两个类大家都在用,有多少人能说清楚Vector和HashMap继承了哪些类,实现了哪些接口呢。
- 理论学习。认真阅读java API的以下内容:java.lang包中的String,StringBuffer,Number,Double,Float,Byte,Short,Integer,Long,Character,Boolean,Process,Runtime,System,Object,Cloneable,Class,ClassLoader,Thread,ThreadGroup,Runnable,Package类或接口。java.util包中的Collection,list,Set,ArrayList,LinkedList,Hashset,TreeSet,Iterator,Map,SortedMap,HashMap,TreeMap,Comparator,Arrays,Enumeration,Vector,Stack,Dictionary,Hashtable,Properties,StringTokenizer,BitSet,Date,Calendar,Locale,Random,Observer,Observable类和接口。主要理清楚这些类或接口的继承关系、主要功能。
- 演绎阶段。通过阅读代码,练习编程,学习并应用这些类和接口。其实这些类的大部分是经常用的,无非对这些类和接口说不清楚。在这些类中,对java.lang和java.util包中的类,最好将各个方法练习使用一次。而对java.util包中Collections framework中的类,最好理清楚各个类和接口之间的关系。常用的类的方法我就不具体介绍了,我举一个使用Observer和Obserable 的例子(摘自《The Complete Reference Java 2 》)。在Observer和Obserable中,java实现了对设计模式Observer的支持。
Watcher.java代码
import java.util.*;
class Watcher implements Observer
{
public void update(Observable obj, Object arg )
{
System.out.println("Update() called, count is " +
((Integer) arg).intValue());
}
}
BeingWatched.java代码
import java.util.*;
class BeingWatched extends Observable
{
void counter( int period )
{
for(;period >=0; period-- )
{
setChanged();
notifyObservers( new Integer ( period ) );
try
{
Thread.sleep(100);
}
catch( InterruptedException e)
{
System.out.println("Sleep interrupeted" );
}
}
}
};ObserverDemo.java代码
public class ObserverDemo
{
public static void main( String[] args )
{
BeingWatched observed = new BeingWatched();
Watcher observing = new Watcher();
observed.addObserver( observing);
observed.counter(10);
}
};执行结果
Update() called, count is 10
Update() called, count is 9
Update() called, count is 8
Update() called, count is 7
Update() called, count is 6
Update() called, count is 5
Update() called, count is 4
Update() called, count is 3
Update() called, count is 2
Update() called, count is 1
Update() called, count is 0 -
归纳阶段。总结使用经验,体会这两个包中类的继承关系,对设计模式的支持(如Iterator本身就是设计模式,同时也是工厂方法模式的应用),了解这些类提供的所有功能,比较功能相近类的异同。将这些类的api记在心中。
虽然集成开发环境支持方法提示功能,但我个人认为,对于java.lang和java.util这两个包的api应当熟记于心,java的其他类库在使用时可以查找api。当然如果从事不同的开发,对其他类库应当有相应的了解,如开发swing,就应当对javax.swing包了如执掌,开发b/s结构的程序,就要了解javax.servlet,依个人的应用来开发了。
本文的上一篇发表之后,承蒙各位网友关注,发表了很多评论,我感觉很多人对我写得文章有误解,大概是我表述不清楚的原因吧。这篇文章是对上一篇的补充,以一个示例阐述了解collection框架的重要性。
我在半年以前写过一个函数printAll(Vector vector),具体代码如下
import java.util.*;
public class UtilTool
{
public static void printAll ( Vector vector )
{
System.out.println( "the Collection is vector" );
System.out.println( vector.getClass().toString() );
Iterator iterator = vector.iterator();
while ( iterator.hasNext() )
{
System.out.println(iterator.next().toString());
}
}
public static void main( String[] arg )
{
Vector vector = new Vector();
vector.add( new Integer(1));
vector.add( new Integer(2));
vector.add( new Integer(3));
UtilTool.printAll(vector);
}
}
printAll这个函数设计的很不好——不够通用,假如,还想打印HashSet类型的数据,你就必须重载printAll函数,代码如下
public static void printAll ( HashSet hashSet )
{
System.out.println( "the Collection is hashSet" );
System.out.println( hashSet.getClass().toString() );
Iterator iterator = hashSet.iterator();
while ( iterator.hasNext() )
{
System.out.println(iterator.next().toString());
}
}
printAll函数的代码重用率低。其实Vector和 HashSet都是Collection的实现,可以将printAll的参数类型改为Collection,而不必重载。代码如下
public static void printAll ( Collection collection )
{
System.out.println( "the Collection is collection" );
System.out.println( collection.getClass().toString() );
Iterator iterator = collection.iterator();
while ( iterator.hasNext() )
{
System.out.println(iterator.next().toString());
}
}
这样就可以删除printAll(Vector vector)和printAll(HashSet hashSet)函数了。
在设计函数时,应优先使用接口,而不是类。当然必须了解Vector 是Collection的实现。
如果对Collection的继承关系不清楚,很容易滥用重载,以下代码是一个有问题的代码(摘自Effective Java Programming Language Guide)
public class CollectionClassifier{
public static String classify(Set s){
return "Set";
}
public static String classify(List l){
return "List";
}
public static String classify(Collection c){
return "Unknow Collection";
}
public static void main( String[] args )
Collection[] tests = new Collection[]{
new HashSet(),
new ArrayList(),
new HashMap().values()
}
for(int i=0;i<tests.length;i++)
System.out.println(classify(test[i]));
}
}
程序输出的是三次"Unknown Collection",而不是你期望的打印"Set","List"以及"Unknown Collection"。这个程序错误的根源是对Collection层次结构不熟悉,而滥用重载导致。
我使用java开发一年多,使用的应该还算熟练,最近在阅读《设计模式》和《Effective Java》时,又重新学了一下java的基本类库,对编程思想有了新的认识。java的基本类库是由专家设计的,理解基本类库一方面可以增加自己的开发效率,另外一方面可以学学专家的设计思路。在java的基本类库中,使用了很多的设计模式,在很多方面提供扩展机制,方便的支持设计模式。可以说java的基础类库,将面向对象设计的Open-Close principle (Software entities should be open for extension,but closed for modification)发挥到了极致。
在java的基础类库中,有些类设计的是为了给java开发者提供工具,直接让开发者使用的,有些类是专门为继承而设计的。对于第一种类型的类,使用集成开发工具很容易就能上手使用,而对于第二种类型的类,不主动去学它的API,很难掌握它的使用。我举一个例子。java 2 提供了对Proxy模式的支持,在以下示例中,演示了如何使用代理模式(摘自《java与模式》)。主要体会java.lang.reflect.InvocationHandler的用法
package com.javapatterns.proxy.reflect;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.lang.reflect.Method;
import java.util.Vector;
import java.util.List;
public class VectorProxy implements InvocationHandler
{
private Object proxyobj;
/** @link dependency */
/*#Proxy lnkProxy;*/
public VectorProxy(Object obj)
{
proxyobj = obj;
}
public static Object factory(Object obj)
{
Class cls = obj.getClass();
return Proxy.newProxyInstance( cls.getClassLoader(),
cls.getInterfaces(),
new VectorProxy(obj) );
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
{
System.out.println("before calling " + method);
if (args != null)
{
for (int i=0; i<args.length; i++)
{
System.out.println(args[i] + "");
}
}
Object o = method.invoke(proxyobj, args);
System.out.println("after calling " + method);
return o;
}
public static void main(String[] args)
{
List v = null;
v = (List) factory(new Vector(10));
v.add("New");
v.add("York");
}
}
前面的系列文章,只是我个人的体会,文章有些教条,仅希望能给还在java门外的人一点意见。学习、应用java的方向,我推荐看一下《谈java的学习方向?》,这篇文章写的不错(见http://www.csdn.net/develop/Read_Article.asp?Id=21393),我学习、应用java的经历和这篇文章介绍的大同小异,所推荐的书籍和资料我也大部分都读过了(差别是我没有读Oreilly公司的书,java 入门我读的是《java编程思想》和《the Complete Reference Java 2》两本java的经典教材,另外我也没有仔细研究过Specification)。如果将自己定位于j2ee方向,那么作者推荐的资料无疑相当不错,同时也比较全面。但我觉得也有一点缺憾:应该在某一个阶段学习一下设计模式和重构,毕竟设计模式和重构是面向对象开发的两本经典,而java是一个纯粹的面向对象的语言,在这里我只想再推荐几本书。
- 《java编程思想》是一本经典的java入门教程,在介绍语言的同时,也介绍了面向对象编程的一些思想。这本书是我学习java看的第一本书,我直到现在还经常翻开这本书,从中仍能找到一些以前没有深刻理解的内容,值得去品味。
- 《the Complete Reference Java 2》既是一本java的入门书籍,又是java的参考书籍,现在coding时,我仍然要经常参考这本书。
- 《java与模式》是向java开发人员介绍设计模式的书,在阅读这本书时,让我去回味以前做过得项目,体会以前做过的项目设计的成功与失败的地方,同时也促使我重新去阅读《java编程思想》和《the Complete Reference Java 2》两本书,阅读3遍之后,加深了对oop的理解。
- 《重构——改善既有代码的设计》,曾经有一个让我非常佩服的项目经理,指点我说一个项目结束后,将这个项目的源代码,重新阅读、清理、总结一下,是提高编程水平的一个手段,而我在以后的工作中,经常清理自己以及别人的一些垃圾代码,确实对编程水平的提高有很大的好处。而《重构》这本书,讲解了70多种清理、重构代码的方法,依照重构的方法去做,既能提高代码质量,又能提高编程水平,也是体会设计模式的一种手段。
- UML
在我这个系列文章写完之后,我突然发现我漏掉了面向对象设计应该掌握的重要内容——UML,虽然我在前面的文章中提起过UML,但UML对于java的重要程度,是应当单独列文说明的。
UML的重要性,我是没有办法用自己的语言表述清楚的,因而引用《UML设计核心技术》的前言来表述UML的重要性,分外在原因和内在原因。
外在原因:
- UML是国际统一的标准,用它表示的产品符合国际标准,产品能够得到广泛的认可,这将提高产品在市场上的竞争力;
- 作为国际标准,国际软件业和商业届对UML的支持时普遍的,因而采用它,将得到最广泛的技术支持和工具支持。
内在原因:
- UML采用图来描述系统的视图,图形化易于理解的特点有利于不同知识背景的客户、领域专家、系统分析、开发、设计人员之间的交流,促使他们的互相理解;
- UML是一种标准的表示方法,任何方法或过程都可以采用UML,它与具体的方法和过程无关,具有通用性;
- UML具有很好的扩展性,提供了加标签值、约束、版类等机制来进行自我扩展,可使用到不同的领域,在具有通用性的同时,还具有使自己专用化的能力;
- UML与最好的软件实践经验集成。它虽然没有描述任何方法或过程,但却要求使用它的过程具有以下特征:以架构为中心、用例驱动、支持迭代和递增的开发,这些特征体现了软件开发的成功经验;
- UML对软件设计和分析实践中涌现出的新思想和新方法提供了很好的支持,它支持模式、框架和组件等概念,提供从“概念模式到实现代码”的可跟踪性。
以上引用文字,说明了UML在OOA和OOD中的重要作用,我想在以下几点做一些说明:
- UML是进行系统分析、系统设计和系统表示的图形语言,在系统开发中,不同角色的人应重点掌握相应的视图,而非掌握全部。UML有9种视图,我都曾经学过,可是我由于系统设计做的多一些,因而对系统设计这部分的视图熟悉一些如类图、序列图、协作图以及对象图,但对其他的视图,这由于较少使用而有些淡忘。但对于自己经常用的图,要可以白板上熟练绘制相应的UML图。
- UML与白板。在系统分析和系统设计阶段,要经常在一起讨论,讨论的时候,白板是UML工具的一个较好选择,这要求熟练掌握UML语言。
- UML与UML工具软件。大多数UML工具软件都有将UML的类图和相应的代码相互转换的功能,UML类图——>代码,是代码生成,代码——>UML类图的过程是反向工程。我推荐在进行系统设计时使用UML工具软件。
- 常用的UML工具有rose、togetherJ和visio 2002,我用过rose和togetherJ,rose由于在很多方面做了增强,因而已经不是标准的UML语言,我不是很赞成使用rose。我比较喜欢使用togetherJ,在项目中,我比较喜欢用togetherJ做设计,设计好之后,自动生成代码框架,再用jbuilder对实现具体方法。