﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>语源科技BlogJava-Java征途漫漫</title><link>http://www.blogjava.net/hig/</link><description /><language>zh-cn</language><lastBuildDate>Sat, 25 Apr 2026 04:03:08 GMT</lastBuildDate><pubDate>Sat, 25 Apr 2026 04:03:08 GMT</pubDate><ttl>60</ttl><item><title>Java数组概要笔记</title><link>http://www.blogjava.net/hig/archive/2006/11/13/80945.html</link><dc:creator>hig</dc:creator><author>hig</author><pubDate>Mon, 13 Nov 2006 09:54:00 GMT</pubDate><guid>http://www.blogjava.net/hig/archive/2006/11/13/80945.html</guid><wfw:comment>http://www.blogjava.net/hig/comments/80945.html</wfw:comment><comments>http://www.blogjava.net/hig/archive/2006/11/13/80945.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/hig/comments/commentRss/80945.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/hig/services/trackbacks/80945.html</trackback:ping><description><![CDATA[
		<p>&lt;&lt;Thinking in java&gt;&gt;<br /><br />=========================================<br />第4张末节<br />=========================================</p>
		<p> </p>
		<p>【数组的初始化】</p>
		<p>1.int[] a1; int a2[];采用第一种方式较好<br />2.拥有的只是对数组的引用，没有给数组分配存储空间，要写初始化表达式。初始化动作可以在代码的任何地方。用一对花括号只能在创建数组的地方出现。<br />3.可以将一个数组赋值给另一个数组a1=a2;其实是复制了一个引用。<br />4.a1.length,a1的最大索引是length-1。java有边界检查，但是会在时间和代码上有所开销。<br />5.不能确定数组里有多少个元素，可以用new在数组里创建元素，尽管创建的是基本类型数组。不能用new创建单个的基本类型数据。<br />static Random rand = new Random();<br />int[] a;<br />a = new int[rand.nextInt(20)];<br />可见数组的创建是在运行时刻进行的，数组元素中的数据类型会自动初始化为“空”（数字和字符是0，boolean是false）。<br />6.数组在定义的时候也可以初始化int[] a = new int[rand.nextInt(20)];尽量如此做。<br />7.数组中的元素不是基本数据类型，那么你必须使用new。<br />Integer[] a = new Integer[rand.nextInt(20)];<br />它还只是个引用数组，指导通过创建新的Integer对象，并且把对象赋值给引用，初始化进程才结束：a[i]=new Integer[rand.nextInt(500))];<br />如果使用数组中的空引用，就会在运行时刻产生异常。<br />8.Integer[] a = {new Integer(1), new Integer(2), new Integer(3),};<br />Integer[] b = new Integer[]{new Integer(1), new Integer(2), new Integer(3),};<br />最后一个逗号可选。</p>
		<p>
				<br />【多维数组】<br />1.基本数据类型的多维数组<br />int[][] a1 = {{1,2,3,}, {4,5,6,},};<br />2.用new分配一个三位数组，这里正个数组分配是一次完成的。<br />int[][][] a2 = new int[2][3][4];<br />3.数组中用以构成矩阵的向量可以有任意的长度：<br />int[][][] a3 = new int[rand.nextInt(7)][][];<br />for(int i=0;i&lt;a3.length;i++){<br />    a3[i] = new int[rand.nextInt(5)];<br />    for(int j=0;j&lt;a3[i].length;j++){<br />        a3[i][j] = new int[rand.nextInt(5)];<br />    }<br />}<br />4.非基本数据类型的对象数组。<br />Integer[][] a4={{new Integer(1), new Integer(2)}, {new Integer(3), new Integer(4)}, {new Integer(5), new Integer(6)},};<br />5.逐步创建非基本类型的对象数组。<br />Integer[][] a5;<br />a5 = new Integer[3][];<br />for(int i=0;i&lt;a5.length;i++){<br />    a5[i] = new Integer[3];<br />    for(int j=0;j&lt;a5[i].length;j++){<br />        a5[i][j]=new Integer(i*j);<br />    }<br />}</p>
		<p>
				<br />=========================================<br />第11章<br />=========================================<br />数组和其他种类容器的区别：<br />效率高，确定类型，可持有基本类</p>
		<p>【数组是第一级对象】<br />1.数组标识符只是一个引用，指向在堆heap中创建的一个真实对象，这个数组对象用以保存指向其他对象的引用。<br />2.对象数组和基本数据类型数组在使用上基本一致，不同在于对象数组保存的是引用，基本类型数组直接保存基本类型。</p>
		<p>【返回一个数组】<br />C和C++不能返回一个数组，只能返回指向数组的指针，它使得控制数组的生命周期变得困难，并且容易造成内存泄漏。java允许直接返回一个数组，你需要它，就会一直存在，使用完后，垃圾回收器会负责清理。</p>
		<p>
				<br />【Arrays类】<br />1.java.util<br />有一套static方法：<br />equals()比较两个数组是否相等<br />fill()用某个值填充整个数组<br />sort()对数组进行排序<br />binarySearch()在已经排序得数组中查找元素<br />asList()接受任意得数组为参数，并将其转化为List容器</p>
		<p>2.StringBuffer比String更高效。</p>
		<p>3.System.exit(0)与System.exit(1)的区别。<br />（实例Arrays）</p>
		<p>
				<br />【填充数组】<br />java标准类库Arrays也有fill()方法，但是只能用同一个值填充各个位置，对于保存对象的数组，就是复制同一个引用进行填充。</p>
		<p> </p>
		<p>【赋值数组】<br />System.arraycopy()，它复制数组比for循环快很多。System.arraycopy()为所有类型作了重载。<br />public static void arraycopy(Object src,<br />                             int srcPos,<br />                             Object dest,<br />                             int destPos,<br />                             int length)</p>
		<p>基本类型数组和对象数组都可以复制，对象数组只是复制引用--不会出现两份对象的拷贝。这被称作浅复制(shallow copy)</p>
<img src ="http://www.blogjava.net/hig/aggbug/80945.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/hig/" target="_blank">hig</a> 2006-11-13 17:54 <a href="http://www.blogjava.net/hig/archive/2006/11/13/80945.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C#摘要笔记（一）</title><link>http://www.blogjava.net/hig/archive/2006/11/13/80944.html</link><dc:creator>hig</dc:creator><author>hig</author><pubDate>Mon, 13 Nov 2006 09:53:00 GMT</pubDate><guid>http://www.blogjava.net/hig/archive/2006/11/13/80944.html</guid><wfw:comment>http://www.blogjava.net/hig/comments/80944.html</wfw:comment><comments>http://www.blogjava.net/hig/archive/2006/11/13/80944.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/hig/comments/commentRss/80944.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/hig/services/trackbacks/80944.html</trackback:ping><description><![CDATA[
		<p>int a,b;(System.Int32 a, b;)<br />System.Console.WriteLine("a is {0}, b is {1}", a, b); //{0}{1}占位符，对应 </p>
		<p>后面的数据 </p>
		<p>=============================== </p>
		<p>class myClass{<br /> unsafe public static void Main(){<br />  sizeof(int);<br /> }<br />}<br />sizeof进入到内存，以确定变量或数据类型的大小。C#应该避免直接进入内存，所以 </p>
		<p>采用了unsafe关键字(否则编译器报错)。 </p>
		<p>=============================== </p>
		<p>sbyte      byte     (System.SByte,     System.Byte)<br />short      ushort   (System.Int16,     System.Uint16)<br />int        uint     (System.Int32,     System.Uint32)<br />long       ulong    (System.Int64,     System.Uint64)<br />char                 System.Char<br />float                System.Single<br />double               System.Double<br />bool                 System.Boolean<br />decimal   System.Decimal(16字节，精度28位，(1.0～7.9)×10(-28次方) </p>
		<p>=============================== </p>
		<p>int val1 = 2147483647;<br />int val2; </p>
		<p>unchecked   //编译器将不会检查下面大括号中的语句<br />{<br /> val2 = val1+1;<br />} </p>
		<p>================================ </p>
		<p>0000 1101&gt;&gt;2  结果：0000 0011(13右移2位，3) </p>
		<p> </p>
		<p>================================= </p>
		<p>文档注释<br />================================= </p>
		<p>System.Ramdom r = new System.Random();<br />int value = (int)r.next(1,10);  //返回1-9 </p>
		<p>
				<br />在switch中，若多个case对应一条语句，则case中不能有任何语句，否则编译出错。 </p>
		<p>C++中，有语句没有break也是可以的。 </p>
		<p>foreach语句和for语句类似，遍历数组等集合。 </p>
		<p>system.Math.Sqrt(double); </p>
		<p>类也有访问权限的控制，缺省或者public两种。方法也有访问控制，private， </p>
		<p>protected，public，缺省。 </p>
		<p>C#访问静态数据成员时，必须使用类名；而在C++中，访问静态数据成员可以用类名和 </p>
		<p>对象名。<br />C#似乎静态数据成员可以在类中定义赋值；而在C++中，不能如此，必须在.cpp文件中 </p>
		<p>赋值，但是const的int型可以在类中赋值。 </p>
		<p>文件名不必要和应用程序类名相同，而java中二者必须一致。 </p>
		<p>C#中有属性的概念，能够在内中创建面向对象的字段field，属性使用关键子get和set </p>
		<p>来取得和设置变量的值。 </p>
		<p>类的数量非常大，要对其进行组织。将类集中在一起，形成名称空间。名称空间是一 </p>
		<p>组被命名的类。似乎和java的package有类似功效。 </p>
		<p>System.Console.ReadLine(); </p>
		<p>名称空间可以嵌套，System包含了Drawing，Data，Windows.Forms等名称空间，using </p>
		<p>System.Data; </p>
		<p>==================================</p>
		<p>结构是值数据类型，类是引用数据类型，在参数传递时，值类型要进行拷贝，会影响 </p>
		<p>效率。一般数据成员的内存不超过16个字节时，使用结构。 </p>
		<p>结构体<br />Struct point<br />{<br />public int x; <br />public int y; </p>
		<p>public point(int x, int y)<br />{<br />this.x = x;<br />this.y = y;<br />}<br />}<br />point first_point = new point();<br />point second_point = new point();<br />也可以直接不用关键字new，直接point first_point；但class类不能如此。 </p>
		<p>结构只能有带参数的构造函数。<br />如point first_point( = new point()); //new 可不用<br />如point second_point = new point(8,8); //必须用new </p>
		<p>结构没有析构函数。<br />C++中，定义struct和class要用;结束，而C#则没有。<br />================================== </p>
		<p>疑问：局部变量定义没有赋初值，会编译错误。但是在类中的成员变量，没有赋初值 </p>
		<p>却不会报错，默认初始值为0。 </p>
		<p> </p>
		<p>方法中按引用传递，则在数据类型前面加上关键字ref(reference引用)；而C++中为&amp; </p>
		<p>。public static square(ref double x); </p>
		<p>================================== </p>
		<p>以输出方式访问参数<br />public void myMath(double x, out double half, out double squared, out </p>
		<p>double cubde){<br /> half = x/2;   //必须给所有的输出参数赋值，否则编译错误！<br /> squared = x*x;<br /> cubde = x*x*x;<br />} </p>
		<p>
				<br />调用时，必须先定义存储返回值的变量：<br />double xx = 30;<br />double half_return = 0;<br />double squared_return = 0;<br />double cubde_return = 0;<br />调用的过程中，必须声明out(省略了double)：<br />myMath(xx, out half_return, out squared_return, out cubde_return); </p>
		<p>如果定义了输出参数，则可以只定义，不初始化。(一般的变量不初始化会编译错误) </p>
		<p>； </p>
		<p>================================= </p>
		<p>属性存储器方法set，get能够使数据成员为私有的。 </p>
		<p>实例构造函数和静态构造函数，前者每个实例或对象被创建使调用，后者在类的第一 </p>
		<p>个对象被创建之前被调用。<br />构造函数名称与类名一直，访问限定符一般用public，不指定返回类型，用来初始化 </p>
		<p>设置。 </p>
		<p>
				<br />析构函数不使用限定符或者其他关键字。~test();<br />析构函数不一定被执行，常被称作结束器(finalizer)，与一个Finalize的方法有关。<br />C#运行阶段环境通常是在检查是否有内存可供释放前调用析构函数，如果在对象不再 </p>
		<p>使用之后到程序结束之前，没有执行这种内存检查，则析构函数不会被执行。可以强 </p>
		<p>行进行无用单元收集，但这还不如尽量少用析构函数。创建自己的代码进行扫尾工作 </p>
		<p>，显示地调用。 </p>
		<p>不能显示地调用构造函数和析构函数。 </p>
		<p>C++中可以调用析构函数么？(一般都不直接显示调用) </p>
		<p>================================= </p>
		<p>改变枚举的类型<br />enum Color : byte<br />{red, white, blue} </p>
		<p>Color myColor = Color.red; </p>
		<p>(byte)((rnd.NextDouble()*3)); //返回一个介于 0.0 和 1.0 之间的随机数 </p>
		<p>=================================<br />一维数组<br />数组的初始化：<br />decimal[] balance = new decimal[12]{1,2,3,4,5,6,7,8,9,0,0,12};<br />可以不指明数组的大小：<br />decimal[] balance = new decimal[]{1,2,3,4,5,6,7,8,9,0,0,12}; </p>
		<p>指明数组大小，可以不初始化所有元素，下面只初始化前两个元素：<br />decimal[] balance = new decimal[12]{1,2};<br />不指明大小，则以后不能增加元素：<br />decimal[] balance = new decimal[]{1,2}; //只有2个元素 </p>
		<p>=================================<br />多维数组,注意格式和C++/java的区别。<br />1.char[,] letters = new char[2,3]{{'a', 'b', 'c'},{'x', 'y', 'z'}}; </p>
		<p>letters[0].length = 2; letters.GetLength[0] = 2;<br />letters[1].length = 3; letters.GetLength[1] = 3; </p>
		<p>2.数组长度不同的数组<br />char[][] myname =  new char[3][];  //数组长度myname.Length = 3(GetLength)<br />myname[0] = new char[]{'B','r','d','e','y'}; //myname[0].Length = 5<br />myname[1] = new char[]{'L','.'};   //myname[1].Length = 2<br />myname[2] = new char[]{'J','o','E'};  //myname[1].Length = 3 </p>
		<p>如果用myname.GetLength[1]将出错，因为myname的第1维大小不固定；只能将其转换 </p>
		<p>乘一维数组再取长度myname[1].GetLength(0)。 </p>
		<p>1为矩形数组，2为锯齿状数组。2必须用myname[0][1]来引用，如果用myname[0,1]将 </p>
		<p>出错。 </p>
		<p>可以使用类，结构，或其他任何数据类型来创建数组。 </p>
		<p>char[] name = new name[]{'A','B','C'};<br />foreach(char x int name)    <br />{Console.Write("{0}",x);}<br />//遍历数组时，它依次将各个元素称为x，不需要使用name[i],只使用x。 </p>
		<p>=============================== </p>
		<p>方法的特征标，只能是方法参数的个数和类型。<br />方法返回类型不行，也不能一个方法使用数据类型，另一个方法使用数组。<br />int myMethod(int)<br />int myMethod(int [])    //错误！ </p>
		<p>也不能通过关键字params类区分特征标。在一个地方声明下面两个方法将出错：<br />void myMethod(string, float)<br />void myMethod(string, params float[]) </p>
		<p>=============================== </p>
		<p>
				<br />params关键字用于方法参数列表中，声明参数列表最后的值，params关键字与数组一 </p>
		<p>起使用，接受不同数目的参数。<br />public static long Add(params int[] args)<br />{<br />for(int i=0;i&lt;args.Length;i++)<br />{<br />......<br />}<br />} </p>
		<p>Add(1);Add(1,2,3);Add(1,2,3,4,5); </p>
		<p>params可以传递任何数据类型的值。<br />public static long Add(params object[] args) </p>
		<p>long l = 12345678L;<br />decimal d = 123.5M;<br />string str = "abc";<br />Add(l, d, str);Add(d, str, "xyz"); </p>
		<p>==============================<br />Main(string[] args)接受不同个数的命令行参数，参数将被加到字符串数组中。 </p>
		<p>static int x 和局部变量x会产生编译错误。C++和java中不会 </p>
		<p>类中没有指明访问权限，则它是private型。方法和函数之外定义的变量是全局的。C# </p>
		<p>不允许在类外定义变量。 </p>
		<p>一个类中成员变量和成员函数全部是静态的，则没有必要创建它的对象。可以用 </p>
		<p>private构造函数在阻止创建对象。 </p>
		<p>==============================<br />使用using namespace之后，可以避免使用全限定名称。<br />using System;<br />Console.WriteLine("aaa");<br />放在程序清单开始位置，在其他地方会编译出错。 </p>
		<p>使用using给名称空间甚至是类提供别名。<br />using doit System.Console;<br />doit.WriteLine("aaa"); </p>
		<p>=============================== </p>
		<p>
				<br />Static int x = 100;<br />再定义一个局部变量int x = 10;<br />后面用的时候，会出现冲突。但C++和java都可以局部变量优先使用。 </p>
		<p>try{}catch{} //catch后面不加任何参数，可以捕获所有异常。而BCB中catch(...)是 </p>
		<p>捕获所有异常。 </p>
		<p>try{}catch(System.Exception e){} //将异常作为参数接受，确定是哪种异常 </p>
		<p>一个try可以对应多个catch语句。前面捕获较具体的异常IndexOutOfRangeException </p>
		<p>，后面捕获较通用的异常Exception。如果颠倒将出错，后面具体的异常语句不会被执 </p>
		<p>行。 </p>
		<p>finally无论是否存在异常，是否有catch捕获都将被执行 </p>
		<p>System.IO<br />FileStream fs = new FileStream(args[0], FileMode.Open);<br />StreamReader sr = new StreamReader(fs);<br />sr.ReadLine(); </p>
		<p>throw抛出异常。throw (exception);throw exception;括号可有可无。 </p>
		<p>自定义异常类<br />class myException : Exception<br />{<br />public myException(){}<br />public myExcepiton(string e):base(e){}<br />public myExcepiton(string e, Exception inner):base(e, inner){}<br />} </p>
		<p>在方法1中有try catch 语句，方法2调用它也要知道发生异常，则方法1中必须重新引 </p>
		<p>发异常catch(Exception e){ throw(e); } </p>
		<p>checked,unchecked可以用作语句[un]checked{//statements}<br />或者用作运算符[un]checked(expression),其中要检查的表达式被放在()中(没有试验 </p>
		<p>通过)。 </p>
		<p>================================= <br /></p>
<img src ="http://www.blogjava.net/hig/aggbug/80944.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/hig/" target="_blank">hig</a> 2006-11-13 17:53 <a href="http://www.blogjava.net/hig/archive/2006/11/13/80944.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java,C#,C++在继承，覆盖和多态,抽象类等几个方面的比较归纳</title><link>http://www.blogjava.net/hig/archive/2006/11/13/80943.html</link><dc:creator>hig</dc:creator><author>hig</author><pubDate>Mon, 13 Nov 2006 09:52:00 GMT</pubDate><guid>http://www.blogjava.net/hig/archive/2006/11/13/80943.html</guid><wfw:comment>http://www.blogjava.net/hig/comments/80943.html</wfw:comment><comments>http://www.blogjava.net/hig/archive/2006/11/13/80943.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/hig/comments/commentRss/80943.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/hig/services/trackbacks/80943.html</trackback:ping><description><![CDATA[
		<p>关于C#,C++,Java在继承，覆盖和多态,抽象类等几个方面的比较归纳。<br />C#,C++用visual studio2005编译通过；java代码用JDK1.4.2编译通过。 </p>
		<p>
				<br />一、继承中的带参数构造函数<br />=============================<br />C#示例：<br />//myClass.cs </p>
		<p>using System;<br />using System.Collections.Generic;<br />using System.Text; </p>
		<p>namespace myClass<br />    class myFirst{<br />        int value_myFirst;<br />        public myFirst(int f)<br />        {<br />            value_myFirst = f;   <br />        }<br />    }<br />    <br />    class mySecond : myFirst{<br />        int value_mySecond;<br />        <br />        //构造函数传递参数时，采用base关键字，s在base()中不需重新声明类型int<br />        public mySecond(int s)<br />            : base(s)   <br />        {<br />            value_mySecond = s;       <br />        }<br />    }<br />        <br />    class Program<br />    {<br />        static void Main(string[] args)<br />        {<br />           <br />        }<br />    }<br />} </p>
		<p>
				<br />============================ </p>
		<p>C++示例：<br />#include "stdafx.h" </p>
		<p>class myFirst{<br />private:<br />    int value_myFirst;<br />public:<br />    myFirst(int f){<br />        value_myFirst = f;   <br />    }<br />}; </p>
		<p>//继承需要声明继承的方式，此处是public<br />class mySecond : public myFirst{  <br />private:<br />    int value_mySecond;<br />public:<br />    //构造函数传递参数时，用基类类名，s基类类名()中不需声明类型int<br />    mySecond(int s) : myFirst(s){ <br />        value_mySecond = s;       <br />    }<br />}; </p>
		<p>int _tmain(int argc, _TCHAR* argv[])<br />{<br /> return 0;<br />} </p>
		<p>============================= </p>
		<p>java示例：<br />package com; </p>
		<p>class myFirst{<br />    int value_myFirst;<br />    public myFirst(int f){<br />        value_myFirst = f;   <br />    }<br />} </p>
		<p>//继承采用extends关键字<br />class mySecond extends myFirst{<br />    int value_mySecond;<br />    public mySecond(int s){<br />        //传递给基类构造函数时，采用super关键字，而且必须是第一条语句。<br />        super(s);  <br />        value_mySecond = s;               <br />    }<br />} </p>
		<p>public class myCon{<br />    public static void main(String[] args){<br />        <br />    }<br />} </p>
		<p>注意：<br />1.注释中给出了三者的不同点。<br />2.另外，C++语法中定义的类后面必须加上分号";"<br />3.访问控制权限public等的格式，C#和java比较类似，C++相差很大。 </p>
		<p> </p>
		<p> </p>
		<p>二、方法覆盖与多态 </p>
		<p>C#示例：<br />//myClass.cs </p>
		<p>using System;<br />using System.Collections.Generic;<br />using System.Text; </p>
		<p>namespace myClass<br />{<br />    class myFirst<br />    {<br />        int value_myFirst;<br />        public myFirst(int f)<br />        {<br />            value_myFirst = f;<br />        }<br />        public void f1()<br />        {<br />            System.Console.WriteLine("myFirst.f1()!");<br />        }<br />        public virtual void f2()  //virtual也可以提到最前面<br />        {<br />            System.Console.WriteLine("myFirst.f2()!");<br />        }<br />    } </p>
		<p>    class mySecond : myFirst<br />    {<br />        int value_mySecond; </p>
		<p>        public mySecond(int s)<br />            : base(s)<br />        {<br />            value_mySecond = s;<br />        }<br />        <br />        //使用关键字new覆盖基类中的同名方法<br />        public new void f1()     //new也可以提到最前面<br />        {<br />            System.Console.WriteLine("mySeconde.f1()!");<br />        }<br />        <br />        //error当基类函数myFirst.f1()没有声明为virtual,abstract时不能override！<br />        //public override void f1()  <br />        //{<br />        //    System.Console.WriteLine("mySeconde.f1()!");<br />        //}<br />        <br />        //基类函数中虽然声明是virtual，但是仍然可以用new覆盖。<br />        //public new void f2()<br />        //{<br />        //    System.Console.WriteLine("mySeconde.f2()!");<br />        //}<br />        <br />        ////基类函数中虽然声明是virtual，用override覆盖。<br />        public override void f2()   //override也可以提到最前面<br />        {<br />            System.Console.WriteLine("mySeconde.f2()!");<br />        }<br />    } </p>
		<p>    class Program<br />    {<br />        static void Main(string[] args)<br />        {<br />            myFirst mf = new myFirst(1);<br />            mySecond ms = new mySecond(2);<br />            mf.f1(); //myFirst.f1()!<br />            mf.f2(); //myFirst.f2()!<br />            ms.f1(); //mySeconde.f1()!<br />            ms.f2(); //mySeconde.f2()! </p>
		<p>            mf = ms; //向上转型之后<br />            mf.f1(); //myFirst.f1()!<br />            <br />            //mySeconde.f2()! 这是用override的运行结果；<br />            //如果是new那么，结果是myFirst.f2()!<br />            mf.f2(); <br />        }<br />    }<br />} </p>
		<p>============================= </p>
		<p>C++示例 </p>
		<p>#include "stdafx.h"<br />#include &lt;iostream&gt;<br />using namespace std; </p>
		<p>class myFirst{<br />private:<br />    int value_myFirst;<br />public:<br />    myFirst(int f){<br />        value_myFirst = f;   <br />    } </p>
		<p> void f1(){<br />  cout&lt;&lt;"myFirst.f1()!"&lt;&lt;endl;<br /> }<br /> vitual void f2(){  //声明为虚函数<br />  cout&lt;&lt;"myFirst.f2()!"&lt;&lt;endl;<br /> }<br />}; </p>
		<p>class mySecond : public myFirst{<br />private:<br />    int value_mySecond;<br />public:<br />    mySecond(int s) : myFirst(s){<br />        value_mySecond = s;       <br />    }<br />    <br />    //直接覆盖基类函数，无需C#中的new<br /> void f1(){<br />  cout&lt;&lt;"mySecond.f1()!"&lt;&lt;endl;<br /> }<br />    <br />    //覆盖基类需函数<br /> void f2(){<br />  cout&lt;&lt;"mySecond.f2()!"&lt;&lt;endl;<br /> }<br />}; </p>
		<p>int _tmain(int argc, _TCHAR* argv[])<br />{<br /> myFirst *mf = new myFirst(1);<br /> mySecond *ms = new mySecond(1);<br /> mf-&gt;f1();  //myFirst.f1()!<br /> mf-&gt;f2();  //myFirst.f2()! </p>
		<p> ms-&gt;f1();  //mySecond.f1()! <br /> ms-&gt;f2();  //mySecond.f2()! </p>
		<p> mf = ms;  //向上转型<br /> mf-&gt;f1(); //myFirst.f1()!<br /> mf-&gt;f2(); //mySecond.f2()!<br /> <br /> myFirst mf1(1);  //也可以<br /> mf1.f1();<br /> <br /> return 0;<br />} </p>
		<p>============================= </p>
		<p>java示例<br />//myCon.java </p>
		<p>package com; </p>
		<p>class myFirst{<br />    int value_myFirst;<br />    public myFirst(int f){<br />        value_myFirst = f;   <br />    }<br />    public void f1(){<br />        System.out.println("myFirst.f1()!");    <br />    }       <br />} </p>
		<p>
				<br />class mySecond extends myFirst{<br />    int value_mySecond;<br />    public mySecond(int s){        <br />        super(s);  <br />        value_mySecond = s;               <br />    }<br />    public void f1(){<br />        System.out.println("mySecond.f1()!");    <br />    }    <br />} </p>
		<p>class myThird extends myFirst{<br />    int value_myThird;<br />    public myThird(int t){        <br />        super(t);  <br />        value_myThird = t;               <br />    }<br />    public void f1(){<br />        System.out.println("myThird.f1()!");    <br />    }     <br />} </p>
		<p>public class myCon{<br />    public static void main(String[] args){<br />        myFirst mf = new myFirst(1);<br />        mySecond ms = new mySecond(1);<br />        myThird mt = new myThird(1);<br />                <br />        mf.f1();  //myFirst.f1()!             <br />        ms.f1();  //mySecond.f1()!      <br />        mt.f1();  //myThird.f1()!      <br />        <br />        //向上转型，由于java的动态绑定机制，<br />        //使得java能够调用派生类mySecond的f1()       <br />        mf = ms;  <br />        mf.f1();  //mySecond.f1()!<br />        <br />        mf = mt;<br />        mf.f1();  //myThird.f1()!      <br />               <br />    }<br />} </p>
		<p>为了实现多态：<br />1.C#基类方法要声明为virtual，派生类覆盖时要用override；<br />2.C++基类方法要声明为virtual，派生类方法直接覆盖；<br />3.java直接覆盖就可以实现多态。 </p>
		<p> </p>
		<p>
				<br />三、抽象类 </p>
		<p>C#示例<br />上面已经说明，虽然基类方法声明为virtual，以便派生类用override覆盖，但是派生类仍然可以用<br />new关键字覆盖(不具有多态性)。<br />可以强制让派生类覆盖基类的方法，将基类方法声明为抽象的，采用abstract关键字。<br />抽象方法没有方法体，由派生类来提供。 </p>
		<p>如果派生类不实现基类的抽象方法，则派生类也需要声明为abstract类 </p>
		<p>//myClass.cs </p>
		<p>using System;<br />using System.Collections.Generic;<br />using System.Text; </p>
		<p>namespace myClass{<br />    <br />    //类中只要存在抽象方法，就必须声明为抽象类<br />    abstract class myFirst  <br />    {<br />        int value_myFirst;<br />        public myFirst(int f)<br />        {<br />            value_myFirst = f;<br />        }<br />        <br />        //抽象方法没有方法体，以分号结尾。<br />        public abstract void f1();<br />        <br />        public void f2()<br />        {<br />            System.Console.WriteLine("myFirst.f2()!");<br />        } </p>
		<p>        public virtual void f3()<br />        {<br />            System.Console.WriteLine("myFirst.f3()!");<br />        }<br />    } </p>
		<p>    class mySecond : myFirst<br />    {<br />        int value_mySecond; </p>
		<p>        public mySecond(int s)<br />            : base(s)<br />        {<br />            value_mySecond = s;<br />        }<br />        <br />        //覆盖基类抽象方法<br />        public override  void f1()   <br />        {<br />            System.Console.WriteLine("mySeconde.f1()!");<br />        } <br />         <br />        //覆盖基类一般方法     <br />        public new void f2()<br />        {<br />            System.Console.WriteLine("mySeconde.f2()!");<br />        } </p>
		<p>        //覆盖基类虚拟方法<br />        public override void f3()<br />        {<br />            System.Console.WriteLine("mySecond.f3()!");<br />        }<br />    } </p>
		<p>    class Program<br />    {<br />        static void Main(string[] args)<br />        {<br />            //抽象类和接口不能声明对象<br />            //myFirst mf = new myFirst(1);  <br />            mySecond ms = new mySecond(2);<br />            <br />            ms.f1();  //mySeconde.f1()!<br />            ms.f2();  //mySeconde.f2()!<br />            ms.f3();  //mySecond.f3()! </p>
		<p>            //这里向上转型采用强类型转换的方式<br />            ((myFirst)ms).f1();   //mySeconde.f1()! <br />            ((myFirst)ms).f2();   //myFirst.f2()!<br />            ((myFirst)ms).f3();   //mySecond.f3()!<br />            <br />        }<br />    }<br />} </p>
		<p>============================= </p>
		<p>C++示例 </p>
		<p>纯虚函数是在基类中只宣布某个虚函数的原型，并且为了明确通知编译系统，<br />该虚函数在基类中不再定义具体操作代码，而在函数原型结束分号的左侧写<br />"=0"标识。这个不包含任何代码的虚函数被成为纯虚函数。 </p>
		<p>抽象类是含有纯虚函数的类，这种类不能声明任何对象，其作用就是为它的<br />派生类提供一种规定输入数据和返回类型接口的模板。 </p>
		<p>从抽象类派生的派生类，必须对基类的纯虚函数进行覆盖；否则编译系统将<br />报错。 </p>
		<p>基类中虚函数被派生类覆盖，则派生类对象调用的是派生类中重新定义的函<br />数代码。<br />基类中虚函数没有被派生类覆盖，则派生类对象调用的是基类中定义的函数<br />代码。<br />基类的纯虚函数在其派生类中必须被覆盖。 </p>
		<p>#include "stdafx.h"<br />#include &lt;iostream&gt;<br />using namespace std; </p>
		<p>class myFirst{   //抽象类<br />private:<br />    int value_myFirst;<br />public:<br />    myFirst(int f){<br />        value_myFirst = f;   <br />    } </p>
		<p> void f1(){            //一般函数<br />  cout&lt;&lt;"myFirst.f1()!"&lt;&lt;endl;<br /> }<br /> virtual void  f2(){   //虚函数<br />  cout&lt;&lt;"myFirst.f2()!"&lt;&lt;endl;<br /> } </p>
		<p> virtual void f3()=0;  //纯虚函数<br />}; </p>
		<p>class mySecond : public myFirst{<br />private:<br />    int value_mySecond;<br />public:<br />    mySecond(int s) : myFirst(s){<br />        value_mySecond = s;       <br />    } </p>
		<p> void f1(){         //覆盖基类一般函数<br />  cout&lt;&lt;"mySecond.f1()!"&lt;&lt;endl;<br /> } </p>
		<p> void f2(){         //覆盖基类虚函数<br />  cout&lt;&lt;"mySecond.f2()!"&lt;&lt;endl;<br /> }<br /> void f3(){         //覆盖基类纯虚函数<br />  cout&lt;&lt;"mySecond.f3()!"&lt;&lt;endl;<br /> }<br />}; </p>
		<p>int _tmain(int argc, _TCHAR* argv[])<br />{<br /> //myFirst *mf = new myFirst(1);  //抽象类不能创建对象<br /> mySecond *ms = new mySecond(1);  </p>
		<p> ms-&gt;f1();  //mySecond.f1()!<br /> ms-&gt;f2();  //mySecond.f2()!<br /> ms-&gt;f3();  //mySecond.f3()! </p>
		<p>    //向上转型采用强类型转换<br /> ((myFirst *)ms)-&gt;f1(); //myFirst.f1()!<br /> ((myFirst *)ms)-&gt;f2(); //mySecond.f2()!<br /> ((myFirst *)ms)-&gt;f3(); //mySecond.f3()! </p>
		<p> return 0;<br />} </p>
		<p>============================= </p>
		<p>java示例 </p>
		<p>java提供了抽象方法的机制abstract method，这种方法不完整，仅有声明<br />没有方法体<br />abstract void f();<br />包含抽象方法的类叫抽象类，如果类中包含一个或多个抽象方法，则该类必<br />须被声明为抽象类，用abstract来修饰抽象类。<br />如果从一个抽象类继承，并创建这个新类的对象，必须给抽象基类中所有抽<br />象方法提供方法定义，否则，派生类也是抽象类，也用abstract修饰。 </p>
		<p>package com; </p>
		<p>abstract class myFirst{<br />    int value_myFirst;<br />    public myFirst(int f){<br />        value_myFirst = f;   <br />    }<br />    public void f1(){<br />        System.out.println("myFirst.f1()!");    <br />    } <br />    public abstract void f2();    //抽象方法   <br />} </p>
		<p>//继承采用extends关键字<br />class mySecond extends myFirst{<br />    int value_mySecond;<br />    public mySecond(int s){<br />        //传递给基类构造函数时，采用super关键字，而且必须是第一条语句。<br />        super(s);  <br />        value_mySecond = s;               <br />    }<br />    public void f1(){<br />        System.out.println("mySecond.f1()!");    <br />    } <br />    <br />    public void f2(){  //覆盖基类抽象方法<br />        System.out.println("mySecond.f2()!");     <br />    }   <br />} </p>
		<p>//如果不实现基类抽象方法，那么此派生类也必须用abstract修饰<br />abstract class myThird extends myFirst{ <br />    int value_myThird;<br />    public myThird(int t){        <br />        super(t);  <br />        value_myThird = t;               <br />    }<br />    public void f1(){<br />        System.out.println("myThird.f1()!");    <br />    }     <br />} </p>
		<p>public class myCon{<br />    public static void main(String[] args){<br />        <br />        //myFirst mf = new myFirst(1); //抽象函数不能创建对象<br />        mySecond ms = new mySecond(1);<br />        //myThird mt = new myThird(1); <br />        <br />        ms.f1();  //mySecond.f1()!<br />        ms.f2();  //mySecond.f2()!<br />        <br />        ((myFirst)ms).f1();  //mySecond.f1()!<br />        ((myFirst)ms).f2();  //mySecond.f2()!<br />    }<br />} </p>
		<p>
				<br />关于抽象方法和抽象类java和C#比较类似；<br />而C++叫纯虚函数和抽象类。 </p>
		<p>
				<br />四、接口<br />C++中的没有接口的概念，它本身就可以多继承。 </p>
		<p>java中接口interface比抽象类abstract更进了一步，可看做"纯粹的抽象类"。<br />它允许创建者为一个类建立其形式，方法名，参数列表，返回类型，但没有<br />任何方法体。接口中也可以包含成员函数，但是他们都是隐含的public和<br />final。 </p>
		<p>创建接口时用interface来代替class，前面可以有public，如果不加访问权<br />限，那么它就是默认的包访问权限。<br />接口中的方法默认为public。 </p>
		<p>类实现接口要用implements关键字。 </p>
		<p>接口便于实现多重继承的效果,此处不作具体讨论。 </p>
		<p>package com; </p>
		<p>interface myFirst{<br />    int value_myFirst=1;    <br />    public void f1();<br />} </p>
		<p>class mySecond implements myFirst{<br />    int value_mySecond;<br />    public mySecond(int s){        <br />        value_mySecond = s;               <br />    }<br />    public void f1(){<br />        System.out.println("mySecond.f1()!");    <br />    }<br />} </p>
		<p>public class myCon{<br />    static void play(myFirst mf){<br />        mf.f1();   <br />    }<br />    public static void main(String[] args){<br />        <br />        <br />        //myFirst mf = new myFirst(1);<br />        mySecond ms = new mySecond(1); <br />        <br />        ms.f1();   //mySecond.f1()!       <br />        play(ms);  //向上转型 mySecond.f1()!<br />        <br />        ((myFirst)ms).f1(); ////向上转型 mySecond.f1()!<br />    }<br />}</p>
<img src ="http://www.blogjava.net/hig/aggbug/80943.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/hig/" target="_blank">hig</a> 2006-11-13 17:52 <a href="http://www.blogjava.net/hig/archive/2006/11/13/80943.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>转：Java学习之路：不走弯路，就是捷径 </title><link>http://www.blogjava.net/hig/archive/2006/11/13/80941.html</link><dc:creator>hig</dc:creator><author>hig</author><pubDate>Mon, 13 Nov 2006 09:49:00 GMT</pubDate><guid>http://www.blogjava.net/hig/archive/2006/11/13/80941.html</guid><wfw:comment>http://www.blogjava.net/hig/comments/80941.html</wfw:comment><comments>http://www.blogjava.net/hig/archive/2006/11/13/80941.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/hig/comments/commentRss/80941.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/hig/services/trackbacks/80941.html</trackback:ping><description><![CDATA[
		<p>0．引言 </p>
		<p>在ChinaITLAB导师制辅导中，笔者发现问得最多的问题莫过于"如何学习编程？Java该如何学习？"。类似的问题回答多了，难免会感觉厌烦，就萌生了写下本文的想法。到时候再有人问起类似的问题，我可以告诉他（她），请你去看看《Java学习之路》。拜读过台湾蔡学镛先生的《Java夜未眠》，有些文章如《Java学习之道》等让我们确实有共鸣，本文题目也由此而来。 </p>
		<p>软件开发之路是充满荆棘与挑战之路,也是充满希望之路。Java学习也是如此，没有捷径可走。梦想像《天龙八部》中虚竹一样被无崖子醍醐灌顶而轻松获得一甲子功力，是很不现实的。每天仰天大叫"天神啊，请赐给我一本葵花宝典吧"，殊不知即使你获得了葵花宝典，除了受自宫其身之苦外，你也不一定成得了"东方不败"，倒是成"西方失败"的几率高一点。 </p>
		<p>"不走弯路，就是捷径"，佛经说的不无道理。 </p>
		<p>1．如何学习程序设计？ </p>
		<p>Java是一种平台，也是一种程序设计语言，如何学好程序设计不仅仅适用于Java，对C++等其他程序设计语言也一样管用。有编程高手认为，Java也好C也好没什么分别，拿来就用。为什么他们能达到如此境界？我想是因为编程语言之间有共通之处，领会了编程的精髓，自然能够做到一通百通。如何学习程序设计理所当然也有许多共通的地方。 </p>
		<p>1.1　培养兴趣 </p>
		<p>兴趣是能够让你坚持下去的动力。如果只是把写程序作为谋生的手段的话，你会活的很累，也太对不起自己了。多关心一些行业趣事，多想想盖茨。不是提倡天天做白日梦，但人要是没有了梦想，你觉得有味道吗？可能像许多深圳本地农民一样，打打麻将，喝喝功夫茶，拜拜财神爷；每个月就有几万十几万甚至更多的进帐，凭空多出个"食利阶层"。你认为，这样有味道吗？有空多到一些程序员论坛转转，你会发现，他们其实很乐观幽默，时不时会冒出智慧的火花。 </p>
		<p>1.2　慎选程序设计语言 </p>
		<p>男怕入错行，女怕嫁错郎。初学者选择程序设计语言需要谨慎对待。软件开发不仅仅是掌握一门编程语言了事，它还需要其他很多方面的背景知识。软件开发也不仅仅局限于某几个领域，而是已经渗透到了各行各业几乎每一个角落。 </p>
		<p>如果你对硬件比较感兴趣，你可以学习C语言/汇编语言，进入硬件开发领域。如果你对电信的行业知识及网络比较熟悉，你可以在C/C++等之上多花时间，以期进入电信软件开发领域。如果你对操作系统比较熟悉，你可以学习C/Linux等等,为Linux内核开发/驱动程序开发/嵌入式开发打基础。 </p>
		<p>如果你想介入到应用范围最广泛的应用软件开发（包括电子商务电子政务系统）的话，你可以选择J2EE或.NET，甚至LAMP组合。每个领域要求的背景知识不一样。做应用软件需要对数据库等很熟悉。总之，你需要根据自己的特点来选择合适你的编程语言。 </p>
		<p>1.3　要脚踏实地,快餐式的学习不可取 </p>
		<p>先分享一个故事。 </p>
		<p>有一个小朋友，他很喜欢研究生物学，很想知道那些蝴蝶如何从蛹壳里出来，变成蝴蝶便会飞。有一次，他走到草原上面看见一个蛹，便取了回家，然后看着，过了几天以后，这个蛹出了一条裂痕，看见里面的蝴蝶开始挣扎，想抓破蛹壳飞出来。 这个过程达数小时之久，蝴蝶在蛹里面很辛苦地拼命挣扎，怎么也没法子走出来。这个小孩看着看着不忍心，就想不如让我帮帮它吧，便随手拿起剪刀在蛹上剪开，使蝴蝶破蛹而出。 但蝴蝶出来以后，因为翅膀不够力，变得很臃肿，飞不起来。 </p>
		<p>这个故事给我们的启示是：欲速则不达。 </p>
		<p>浮躁是现代人最普遍的心态，能怪谁？也许是贫穷落后了这么多年的缘故，就像当年的大跃进一样，都想大步跨入共产主义社会。现在的软件公司、客户、政府、学校、培训机构等等到处弥漫着浮躁之气。就拿笔者比较熟悉的深圳IT培训行业来说吧，居然有的打广告宣称"参加培训，100%就业"，居然报名的学生不少，简直是藐视天下程序员。社会环境如是，我们不能改变，只能改变自己,闹市中的安宁，弥足珍贵。许多初学者C++/Java没开始学，立马使用VC/JBuilder,会使用VC/JBuilder开发一个Hello World程序，就忙不迭的向世界宣告，"我会软件开发了"，简历上也大言不惭地写上"精通VC/Java"。结果到软件公司面试时要么被三两下打发走了，要么被驳的体无完肤，无地自容。到处碰壁之后才知道捧起《C++编程思想》《Java编程思想》仔细钻研，早知如此何必当初呀。 </p>
		<p>"你现在讲究简单方便，你以后的路就长了"，好象也是佛经中的劝戒。</p>
		<p>1.4　多实践,快实践 </p>
		<p>彭端淑的《为学一首示子侄》中有穷和尚与富和尚的故事。 </p>
		<p>从前，四川边境有两个和尚，一个贫穷，一个有钱。一天，穷和尚对富和尚说："我打算去南海朝圣，你看怎么样？"富和尚说："这里离南海有几千里远，你靠什么去呢？"穷和尚说："我只要一个水钵，一个饭碗就够了。"富和尚为难地说："几年前我就打算买条船去南海，可至今没去成，你还是别去吧！" 一年以后，富和尚还在为租赁船只筹钱，穷和尚却已经从南海朝圣回来了。 </p>
		<p>这个故事可解读为：任何事情，一旦考虑好了，就要马上上路，不要等到准备周全之后，再去干事情。假如事情准备考虑周全了再上路的话，别人恐怕捷足先登了。软件开发是一门工程学科，注重的就是实践，"君子动口不动手"对软件开发人员来讲根本就是错误的，他们提倡"动手至上"，但别害怕，他们大多温文尔雅，没有暴力倾向，虽然有时候蓬头垢面的一副"比尔盖茨"样。有前辈高人认为，学习编程的秘诀是：编程、编程、再编程，笔者深表赞同。不仅要多实践，而且要快实践。我们在看书的时候，不要等到你完全理解了才动手敲代码，而是应该在看书的同时敲代码，程序运行的各种情况可以让你更快更牢固的掌握知识点。 </p>
		<p>1.5　多参考程序代码 </p>
		<p>程序代码是软件开发最重要的成果之一，其中渗透了程序员的思想与灵魂。许多人被《仙剑奇侠传》中凄美的爱情故事感动,悲剧的结局更有一种缺憾美。为什么要以悲剧结尾？据说是因为写《仙剑奇侠传》的程序员失恋而安排了这样的结局，他把自己的感觉融入到游戏中，却让众多的仙剑迷扼腕叹息。 </p>
		<p>多多参考代码例子，对Java而言有参考文献[4.3],有API类的源代码(JDK安装目录下的src.zip文件)，也可以研究一些开源的软件或框架。 </p>
		<p>1.6　加强英文阅读能力 </p>
		<p>对学习编程来说，不要求英语, 但不能一点不会,。最起码像Java API文档(参考文献[4.4])这些东西还是要能看懂的,连猜带懵都可以；旁边再开启一个"金山词霸"。看多了就会越来越熟练。在学Java的同时学习英文，一箭双雕多好。另外好多软件需要到英文网站下载，你要能够找到它们，这些是最基本的要求。英语好对你学习有很大的帮助。口语好的话更有机会进入管理层，进而可以成为剥削程序员的"周扒皮"。 </p>
		<p>1.7　万不得已才请教别人 </p>
		<p>笔者在ChinaITLab网校的在线辅导系统中解决学生问题时发现，大部分的问题学生稍做思考就可以解决。请教别人之前，你应该先回答如下几个问题。 </p>
		<p>你是否在google中搜索了问题的解决办法？ </p>
		<p>你是否查看了Java API文档？ </p>
		<p>你是否查找过相关书籍？ </p>
		<p>你是否写代码测试过？ </p>
		<p>如果回答都是"是"的话，而且还没有找到解决办法，再问别人不迟。要知道独立思考的能力对你很重要。要知道程序员的时间是很宝贵的。 </p>
		<p>1.8　多读好书 </p>
		<p>书中自有颜如玉。比尔?盖茨是一个饱读群书的人。虽然没有读完大学，但九岁的时候比尔?盖茨就已经读完了所有的百科全书，所以他精通天文、历史、地理等等各类学科，可以说比尔?盖茨不仅是当今世界上金钱的首富，而且也可以称得上是知识的巨富。 </p>
		<p>笔者在给学生上课的时候经常会给他们推荐书籍，到后来学生实在忍无可忍开始抱怨，"天呐，这么多书到什么时候才能看完了"，"学软件开发，感觉上了贼船"。这时候，我的回答一般是，"别着急，什么时候带你们去看看我的书房，到现在每月花在技术书籍上的钱400元，这在软件开发人员之中还只能够算是中等的"，学生当场晕倒。（注：这一部分学生是刚学软件开发的） </p>
		<p>对于在Java开发领域的好书在笔者另外一篇文章中会专门点评。该文章可作为本文的姊妹篇。 <br />1.9　使用合适的工具 </p>
		<p>工欲善其事必先利其器。软件开发包含各种各样的活动，需求收集分析、建立用例模型、建立分析设计模型、编程实现、调试程序、自动化测试、持续集成等等，没有工具帮忙可以说是寸步难行。工具可以提高开发效率，使软件的质量更高BUG更少。组合称手的武器。到飞花摘叶皆可伤人的境界就很高了，无招胜有招，手中无剑心中有剑这样的境界几乎不可企及。在笔者另外一篇文章中会专门阐述如何选择合适的工具（该文章也可作为本文的姊妹篇）。 </p>
		<p>2．软件开发学习路线 </p>
		<p>两千多年的儒家思想孔孟之道，中庸的思想透入骨髓，既不冒进也不保守并非中庸之道，而是找寻学习软件开发的正确路线与规律。 </p>
		<p>从软件开发人员的生涯规划来讲，我们可以大致分为三个阶段，软件工程师→软件设计师→架构设计师或项目管理师。不想当元帅的士兵不是好士兵，不想当架构设计师或项目管理师的程序员也不是好的程序员。我们应该努力往上走。让我们先整理一下开发应用软件需要学习的主要技术。 </p>
		<p>A．基础理论知识，如操作系统、编译原理、数据结构与算法、计算机原理等，它们并非不重要。如不想成为计算机科学家的话，可以采取"用到的时候再来学"的原则。 </p>
		<p>B．一门编程语言，现在基本上都是面向对象的语言，Java/C++/C#等等。如果做WEB开发的话还要学习HTML/JavaScript等等。 </p>
		<p>C．一种方法学或者说思想，现在基本都是面向对象思想（OOA/OOD/设计模式）。由此而衍生的基于组件开发CBD/面向方面编程AOP等等。 </p>
		<p>D．一种关系型数据库，ORACLE/SqlServer/DB2/MySQL等等 </p>
		<p>E．一种提高生产率的IDE集成开发环境JBuilder/Eclipse/VS.NET等。 </p>
		<p>F．一种UML建模工具，用ROSE/VISIO/钢笔进行建模。 </p>
		<p>G．一种软件过程，RUP/XP/CMM等等，通过软件过程来组织软件开发的众多活动，使开发流程专业化规范化。当然还有其他的一些软件工程知识。 </p>
		<p>H．项目管理、体系结构、框架知识。 </p>
		<p>正确的路线应该是：B→C→E→F→G→H。 </p>
		<p>还需要补充几点： </p>
		<p>1）．对于A与C要补充的是，我们应该在实践中逐步领悟编程理论与编程思想。新技术虽然不断涌现，更新速度令人眼花燎乱雾里看花；但万变不离其宗，编程理论与编程思想的变化却很慢。掌握了编程理论与编程思想你就会有拨云见日之感。面向对象的思想在目前来讲是相当关键的，是强势技术之一，在上面需要多投入时间，给你的回报也会让你惊喜。 </p>
		<p>2）．对于数据库来说是独立学习的，这个时机就由你来决定吧。 </p>
		<p>3）．编程语言作为学习软件开发的主线，而其余的作为辅线。 </p>
		<p>4）．软件工程师着重于B、C、E、D；软件设计师着重于B、C、E、D、F；架构设计师着重于C、F、H。 </p>
		<p>3．如何学习Java? </p>
		<p>3.1 Java学习路线 </p>
		<p>3.1.1 基础语法及Java原理 </p>
		<p>基础语法和Java原理是地基，地基不牢靠，犹如沙地上建摩天大厦，是相当危险的。学习Java也是如此，必须要有扎实的基础，你才能在J2EE、J2ME领域游刃有余。参加SCJP（SUN公司认证的Java程序员）考试不失为一个好方法，原因之一是为了对得起你交的1200大洋考试费，你会更努力学习，原因之二是SCJP考试能够让你把基础打得很牢靠，它要求你跟JDK一样熟悉Java基础知识；但是你千万不要认为考过了SCJP就有多了不起，就能够获得软件公司的青睐，就能够获取高薪，这样的想法也是很危险的。获得"真正"的SCJP只能证明你的基础还过得去，但离实际开发还有很长的一段路要走。<br />3.1.2 OO思想的领悟 </p>
		<p>掌握了基础语法和Java程序运行原理后，我们就可以用Java语言实现面向对象的思想了。面向对象，是一种方法学;是独立于语言之外的编程思想;是CBD基于组件开发的基础;属于强势技术之一。当以后因工作需要转到别的面向对象语言的时候，你会感到特别的熟悉亲切，学起来像喝凉水这么简单。 </p>
		<p>使用面向对象的思想进行开发的基本过程是： </p>
		<p>●调查收集需求。 </p>
		<p>●建立用例模型。 </p>
		<p>●从用例模型中识别分析类及类与类之间的静态动态关系，从而建立分析模型。 </p>
		<p>●细化分析模型到设计模型。 </p>
		<p>●用具体的技术去实现。 </p>
		<p>●测试、部署、总结。 </p>
		<p>3.1.3 基本API的学习 </p>
		<p>进行软件开发的时候，并不是什么功能都需要我们去实现，也就是经典名言所说的"不需要重新发明轮子"。我们可以利用现成的类、组件、框架来搭建我们的应用，如SUN公司编写好了众多类实现一些底层功能，以及我们下载过来的JAR文件中包含的类,我们可以调用类中的方法来完成某些功能或继承它。那么这些类中究竟提供了哪些方法给我们使用？方法的参数个数及类型是？类的构造器需不需要参数？总不可能SUN公司的工程师打国际长途甚至飘洋过海来告诉你他编写的类该如何使用吧。他们只能提供文档给我们查看，Java DOC文档（参考文献4.4）就是这样的文档，它可以说是程序员与程序员交流的文档。 </p>
		<p>基本API指的是实现了一些底层功能的类，通用性较强的API，如字符串处理/输入输出等等。我们又把它成为类库。熟悉API的方法一是多查Java DOC文档（参考文献4.4），二是使用JBuilder/Eclipse等IDE的代码提示功能。 </p>
		<p>3.1.4 特定API的学习 </p>
		<p>Java介入的领域很广泛，不同的领域有不同的API，没有人熟悉所有的API，对一般人而言只是熟悉工作中要用到的API。如果你做界面开发，那么你需要学习Swing/AWT/SWT等API；如果你进行网络游戏开发，你需要深入了解网络API/多媒体API/2D3D等；如果你做WEB开发，就需要熟悉Servlet等API啦。总之，需要根据工作的需要或你的兴趣发展方向去选择学习特定的API。 </p>
		<p>3.1.5 开发工具的用法 </p>
		<p>在学习基础语法与基本的面向对象概念时，从锻炼语言熟练程度的角度考虑，我们推荐使用的工具是Editplus/JCreator+JDK,这时候不要急于上手JBuilder/Eclipse等集成开发环境，以免过于关注IDE的强大功能而分散对Java技术本身的注意力。过了这一阶段你就可以开始熟悉IDE了。 </p>
		<p>程序员日常工作包括很多活动，编辑、编译及构建、调试、单元测试、版本控制、维持模型与代码同步、文档的更新等等，几乎每一项活动都有专门的工具，如果独立使用这些工具的话，你将会很痛苦，你需要在堆满工具的任务栏上不断的切换，效率很低下，也很容易出错。在JBuilder、Eclipse等IDE中已经自动集成编辑器、编译器、调试器、单元测试工具JUnit、自动构建工具ANT、版本控制工具CVS、DOC文档生成与更新等等，甚至可以把UML建模工具也集成进去，又提供了丰富的向导帮助生成框架代码，让我们的开发变得更轻松。应该说IDE发展的趋势就是集成软件开发中要用到的几乎所有工具。 </p>
		<p>从开发效率的角度考虑，使用IDE是必经之路，也是从一个学生到一个职业程序员转变的里程碑。 </p>
		<p>Java开发使用的IDE主要有Eclipse、JBuilder、JDeveloper、NetBeans等几种；而Eclipse、JBuilder占有的市场份额是最大的。JBuilder在近几年来一直是Java集成开发环境中的霸主，它是由备受程序员尊敬的Borland公司开发，在硝烟弥漫的Java IDE大战中,以其快速的版本更新击败IBM的Visual Age for Java等而成就一番伟业。IBM在Visual Age for Java上已经无利可图之下，干脆将之贡献给开源社区，成为Eclipse的前身，真所谓"柳暗花明又一村"。浴火重生的Eclipse以其开放式的插件扩展机制、免费开源获得广大程序员（包括几乎所有的骨灰级程序员）的青睐，极具发展潜力。 </p>
		<p>3.1.6 学习软件工程 </p>
		<p>对小型项目而言，你可能认为软件工程没太大的必要。随着项目的复杂性越来越高，软件工程的必要性才会体现出来。参见"软件开发学习路线"小节。 </p>
		<p>3.2学习要点 </p>
		<p>确立的学习路线之后，我们还需要总结一下Java的学习要点，这些要点在前文多多少少提到过，只是笔者觉得这些地方特别要注意才对它们进行汇总，不要嫌我婆婆妈妈啊。 </p>
		<p>3.2.1勤查API文档 </p>
		<p>当程序员编写好某些类，觉得很有成就感,想把它贡献给各位苦难的同行。这时候你要使用"Javadoc"工具（包含在JDK中）生成标准的Java DOC文档,供同行使用。J2SE/J2EE/J2ME的DOC文档是程序员与程序员交流的工具，几乎人手一份，除了菜鸟之外。J2SE DOC文档官方下载地址：<a href="http://Java.sun.com/j2se/1.5.0/download.jsp">http://Java.sun.com/j2se/1.5.0/download.jsp</a>，你可以到google搜索CHM版本下载。也可以在线查看：<a href="http://Java.sun.com/j2se/1.5.0/docs/api/index.html">http://Java.sun.com/j2se/1.5.0/docs/api/index.html</a>。 </p>
		<p>对待DOC文档要像毛主席语录，早上起床念一遍，吃饭睡觉前念一遍。 </p>
		<p>当需要某项功能的时候，你应该先查相应的DOC文档看看有没有现成的实现，有的话就不必劳神费心了直接用就可以了，找不到的时候才考虑自己实现。使用步骤一般如下： </p>
		<p>●找特定的包，包一般根据功能组织。 </p>
		<p>●找需要使用类，类命名规范的话我们由类的名字可猜出一二。 </p>
		<p>●选择构造器，大多数使用类的方式是创建对象。 </p>
		<p>●选择你需要的方法。 </p>
		<p>3.2.2 查书/google-&gt;写代码测试-&gt;查看源代码-&gt;请教别人 </p>
		<p>当我们遇到问题的时候该如何解决？ </p>
		<p>这时候不要急着问别人，太简单的问题，没经过思考的问题，别人会因此而瞧不起你。可以先找找书，到google中搜一下看看，绝大部分问题基本就解决了。而像"某些类/方法如何使用的问题"，DOC文档就是答案。对某些知识点有疑惑是，写代码测试一下，会给你留下深刻的印象。而有的问题，你可能需要直接看API的源代码验证你的想法。万不得已才去请教别人。 </p>
		<p>3.2.3学习开源软件的设计思想 </p>
		<p>Java领域有许多源代码开放的工具、组件、框架，JUnit、ANT、Tomcat、Struts、Spring、Jive论坛、PetStore宠物店等等多如牛毛。这些可是前辈给我们留下的瑰宝呀。入宝山而空手归，你心甘吗？对这些工具、框架进行分析，领会其中的设计思想，有朝一日说不定你也能写一个XXX框架什么的，风光一把。分析开源软件其实是你提高技术、提高实战能力的便捷方法。 </p>
		<p>3.2.4 规范的重要性 </p>
		<p>没有规矩，不成方圆。这里的规范有两层含义。第一层含义是技术规范，多到<a href="http://www.jcp.org">http://www.jcp.org</a>下载JSRXXX规范，多读规范，这是最权威准确最新的教材。第二层含义是编程规范，如果你使用了大量的独特算法，富有个性的变量及方法的命名方式；同时，没给程序作注释，以显示你的编程功底是多么的深厚。这样的代码别人看起来像天书，要理解谈何容易，更不用说维护了，必然会被无情地扫入垃圾堆。Java编码规范到此查看或下载<a href="http://Java.sun.com/docs/codeconv/">http://Java.sun.com/docs/codeconv/</a>，中文的也有，啊，还要问我在哪，请参考3.2.2节。 </p>
		<p>3.2.5 不局限于Java </p>
		<p>很不幸，很幸运，要学习的东西还有很多。不幸的是因为要学的东西太多且多变，没时间陪老婆家人或女朋友，导致身心疲惫，严重者甚至导致抑郁症。幸运的是别人要抢你饭碗绝非易事，他们或她们需要付出很多才能达成心愿。 </p>
		<p>Java不要孤立地去学习，需要综合学习数据结构、OOP、软件工程、UML、网络编程、数据库技术等知识，用横向纵向的比较联想的方式去学习会更有效。如学习Java集合的时候找数据结构的书看看；学JDBC的时候复习数据库技术；采取的依然是"需要的时候再学"的原则。 </p>
		<p>4．结束语 </p>
		<p>需要强调的是，学习软件开发确实有一定的难度，也很辛苦，需要付出很多努力，但千万不要半途而废。本文如果能对一直徘徊在Java神殿之外的朋友有所帮助的话，笔者也欣慰了。哈哈，怎么听起来老气横秋呀？没办法，在电脑的长期辐射之下，都快变成小老头了。最后奉劝各位程序员尤其是MM程序员，完成工作后赶快远离电脑，据《胡播乱报》报道，电脑辐射会在白皙的皮肤上面点缀一些小黑点，看起来鲜艳无比……    </p>
		<p> </p>
<img src ="http://www.blogjava.net/hig/aggbug/80941.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/hig/" target="_blank">hig</a> 2006-11-13 17:49 <a href="http://www.blogjava.net/hig/archive/2006/11/13/80941.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>