??xml version="1.0" encoding="utf-8" standalone="yes"?>日韩亚洲人成在线综合,亚洲国产美女精品久久,久久亚洲av无码精品浪潮http://www.tkk7.com/Pudgy/<SCRIPT> var dict_width = 'auto' var dict_height = '72px' var dict_background = 'transparent' var dict_border = '0px dotted #000000' var dict_textColor = '#6FBC4C' var dict_fontSize = '100%' var dict_encoding = 'Utf-8' </SCRIPT> <SCRIPT src="http://livid.cn/services/fortune"></SCRIPT> <script src="http://www.google-analytics.com/urchin.js" type="text/javascript"> </script>zh-cnSat, 10 May 2025 19:37:28 GMTSat, 10 May 2025 19:37:28 GMT602005.08.30http://www.tkk7.com/Pudgy/archive/2005/08/30/11543.htmlPudgy's WorldPudgy's WorldTue, 30 Aug 2005 05:09:00 GMThttp://www.tkk7.com/Pudgy/archive/2005/08/30/11543.htmlhttp://www.tkk7.com/Pudgy/comments/11543.htmlhttp://www.tkk7.com/Pudgy/archive/2005/08/30/11543.html#Feedback0http://www.tkk7.com/Pudgy/comments/commentRss/11543.htmlhttp://www.tkk7.com/Pudgy/services/trackbacks/11543.html
  • 把SwingWorker 的Thread 参数弄明?/li>
  • U程l的调用.


  • Pudgy's World 2005-08-30 13:09 发表评论
    ]]>
    Thumbnail.java - Load an image, scale it to thumbnail size and save it as JPEGhttp://www.tkk7.com/Pudgy/archive/2005/08/29/11457.htmlPudgy's WorldPudgy's WorldMon, 29 Aug 2005 08:12:00 GMThttp://www.tkk7.com/Pudgy/archive/2005/08/29/11457.htmlhttp://www.tkk7.com/Pudgy/comments/11457.htmlhttp://www.tkk7.com/Pudgy/archive/2005/08/29/11457.html#Feedback0http://www.tkk7.com/Pudgy/comments/commentRss/11457.htmlhttp://www.tkk7.com/Pudgy/services/trackbacks/11457.htmlFrom http://schmidt.devlib.org/java/save-jpeg-thumbnail.html

    Thumbnail.java - Load an image, scale it to thumbnail size and save it as JPEG

    This programm loads an image via java.awt.Toolkit, scales it down to a user-defined resolution and saves it as a JPEG file. The first part, the loading of the original image, is done the same way as in Viewer. So if you don't know yet how loading images with Toolkit works you might want to study that program first.

    Different from Viewer, this program (Thumbnail) works on the command line. So you won't get any windows or other graphical user interface components. The only visual feedback is the word Done. after the program successfully terminated.

    To use this program do the following:

    • Save the program's source code as Thumbnail.java (regard case).
    • Open a shell (prompt), go to the directory where Thumbnail.java is and compile it:
      javac Thumbnail.java
      You should now have a new class file Thumbnail.class.
    • Run the program with five parameters for image file, thumbnail file, thumbnail width and thumbnail height and quality (a value from 0 to 100, 100 being the best and 0 the worst quality), e.g.:
      java Thumbnail c:\image.jpg c:\thumbnail.jpg 120 80 75
      The file image.jpg must exist already, thumbnail.jpg will be created (and any existing file of that name overwritten).

    You will need Java 1.2 or higher to successfully run this program. The com.sun.image.codec.jpeg package that will be used for saving the thumbnail is not available with all Java development kits, but as long as you are using a Sun JDK, it should be present.

    With Java 1.4 a new way of writing JPEG files was introduced, the image I/O library in the package javax.imageio. See the Screenshot.java example program. It saves as PNG, but all you have to do is change the second argument of ImageIO.write from png to jpg. The advantage of ImageIO: It is available with each 1.4+ JDK and JRE, not only those coming from Sun.

    Explanation

    Now let's see how this program works. First, it is checked that we have exactly five arguments. If this is not the case, an error message is printed to output and the program terminates.

    Next, the input image is loaded via Toolkit and MediaTracker just as it was done in Viewer.

    The third and fourth program argument contain the maximum size of the thumbnail to be created. The actual size of the thumbnail will be computed from that maximum size and the actual size of the image (all sizes are given as pixels). The code that does this is not really very readable, and also not essential to loading and saving image files. But it is necessary to create a thumbnail that is scaled correctly.

    As an example, if the two arguments for the maximum thumbnail size are both 100 and the image that was loaded is 400 times 200 pixels large, we want the thumbnail to be 100 times 50 pixels large, not 100 times 100, because the original image is twice as wide as it is high. A 100 times 100 pixel thumbnail would contain a very skewed version of the original image.

    Now that we have determined the size of the thumbnail we create a BufferedImage of that size, named thumbImage. We ask for a Graphics2D object for that new thumbnail image and call its drawImage method to draw the original image on that new image. The call to drawImage does the actual scaling. The rendering hints for bilinear interpolation can be left out if quality is not that necessary and speed more important. For nicer results (at least in some cases) try RenderingHints.VALUE_INTERPOLATION_BICUBIC instead of RenderingHints.VALUE_INTERPOLATION_BILINEAR.

    In order to save the scaled-down image to a JPEG file, we create a buffered FileOutputStream with the second argument as name and initialize the necessary objects from the com.sun.image.codec.jpeg package. The quality argument from the command line is converted from the interval 0 to 100 to the interval 0.0f to 1.0f, because that's what the codec expects (I mostly use 0.75f). The higher that quality number is, the better the resulting thumbnail image quality, but also the larger the resulting file.

    The call to System.exit(0); is unfortunately necessary for some Java runtime environments (because of a bug that keeps the AWT thread from terminating).

    Source code of Thumbnail.java

     
    import com.sun.image.codec.jpeg.*;
    import java.awt.
    *
    ;
    import java.awt.image.
    *
    ;
    import java.io.
    *
    ;

    /*
    *
     * Thumbnail.java (requires Java 1.2+)
     * Load an image, scale it down and save it as a JPEG file.
     * @author Marco Schmidt
     
    */

    public class Thumbnail {
      
    public static void
     main(String[] args) throws Exception {
        
    if (args.length != 5
    ) {
          System.err.println(
    "Usage: java Thumbnail INFILE " +

            
    "OUTFILE WIDTH HEIGHT QUALITY");
          System.exit(
    1
    );
        }
        
    // load image from INFILE

        Image image = Toolkit.getDefaultToolkit().getImage(args[0]);
        MediaTracker mediaTracker 
    = new MediaTracker(new
     Container());
        mediaTracker.addImage(image, 
    0
    );
        mediaTracker.waitForID(
    0
    );
        
    // determine thumbnail size from WIDTH and HEIGHT

        int thumbWidth = Integer.parseInt(args[2]);
        
    int thumbHeight = Integer.parseInt(args[3
    ]);
        
    double thumbRatio = (double)thumbWidth / (double
    )thumbHeight;
        
    int imageWidth = image.getWidth(null
    );
        
    int imageHeight = image.getHeight(null
    );
        
    double imageRatio = (double)imageWidth / (double
    )imageHeight;
        
    if (thumbRatio <
     imageRatio) {
          thumbHeight 
    = (int)(thumbWidth /
     imageRatio);
        } 
    else
     {
          thumbWidth 
    = (int)(thumbHeight *
     imageRatio);
        }
        
    //
     draw original image to thumbnail image object and
        
    // scale it to the new size on-the-fly

        BufferedImage thumbImage = new BufferedImage(thumbWidth, 
          thumbHeight, BufferedImage.TYPE_INT_RGB);
        Graphics2D graphics2D 
    =
     thumbImage.createGraphics();
        graphics2D.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
          RenderingHints.VALUE_INTERPOLATION_BILINEAR);
        graphics2D.drawImage(image, 
    00, thumbWidth, thumbHeight, null
    );
        
    // save thumbnail image to OUTFILE

        BufferedOutputStream out = new BufferedOutputStream(new
          FileOutputStream(args[
    1]));
        JPEGImageEncoder encoder 
    = JPEGCodec.createJPEGEncoder(out
    );
        JPEGEncodeParam param 
    =
     encoder.
          getDefaultJPEGEncodeParam(thumbImage);
        
    int quality = Integer.parseInt(args[4
    ]);
        quality 
    = Math.max(0, Math.min(quality, 100
    ));
        param.setQuality((
    float)quality / 100.0ffalse
    );
        encoder.setJPEGEncodeParam(param);
        encoder.encode(thumbImage);
        
    out
    .close(); 
        System.
    out.println("Done."
    );
        System.exit(
    0
    );
      }
    }


    Pudgy's World 2005-08-29 16:12 发表评论
    ]]>
    时标和历?/title><link>http://www.tkk7.com/Pudgy/archive/2005/08/29/11420.html</link><dc:creator>Pudgy's World</dc:creator><author>Pudgy's World</author><pubDate>Mon, 29 Aug 2005 03:42:00 GMT</pubDate><guid>http://www.tkk7.com/Pudgy/archive/2005/08/29/11420.html</guid><wfw:comment>http://www.tkk7.com/Pudgy/comments/11420.html</wfw:comment><comments>http://www.tkk7.com/Pudgy/archive/2005/08/29/11420.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.tkk7.com/Pudgy/comments/commentRss/11420.html</wfw:commentRss><trackback:ping>http://www.tkk7.com/Pudgy/services/trackbacks/11420.html</trackback:ping><description><![CDATA[<!--StartFragment --> 转自<A >http://fmddlmyy.home4u.china.com/text8.html</A> <H2>时标和历?/H2> <H3>1、时?/H3>时标QTime ScaleQ就是标度时间的Ҏ。在旉的标度上Q存在着两个怺独立的需求:一斚wQ我们希望时间标度能与地球的自{相吻合,可以UC天文学需求;另一斚wQ我们要求时间标度的单位是精的Q便于大家获得准的旉。由于地球自转的不均匀性,从这两个需求出发制定的时标会有l微的差异?BR>世界ӞUT1Q是Z地球自{的时标,下文会详l介l。国际原子时QTAIQ是Z单位旉的时标,它以“铯-133原子基态两个超_能间跃q辐?9,192,631,770周所持箋的时间”ؓ一U,可以UC原子时标。原子时标的准确度ؓ每日数纳U,而世界时的准度只有数毫U? <P></P> <H4>1.1 本初子午U?/H4>对于Z天文观测的时标,地球上位于不同经度的观测者,在同一瞬间得的结果是不同的。因此需要统一的地理经度基准?BR>1884q在华盛D行的国际子午U会议决定,采用英国伦敦格林威治QGreenwichQ天文台埃里中星仪所在的子午U作为时间和l度计量的标准参考子午线Q称为本初子午线Q又U格林威d午线。格林威d文台?948q迁到苏塞克斯郡QSussexQ的Herstmonceux CastleQ但旧址l箋被用?度经U的位置?BR>1957q国际上以若q天文测时结果长期稳定性较好的天文台数据ؓ参考,求得q_天文台经度原炏V?968q国际上把通过地极原点和^均天文台l度原点的子午线UCؓ本初子午Uѝ可见,本初子午U的定义已经不依赖于格林威治天文台旧址? <P></P> <H4>1.2 世界?/H4>世界时的制定基准是太阳的周日视运动。视q动是我们看到的运动。本来是地球l着地up向东转动。但如果观测者以׃动,可以认为太阛_׃向西转动Q这是太阳的周日视q动?BR>地球在自转的同时q围l太阛_转,因ؓ地球公{轨道是椭圆的Q所以太阳的周日视运动是不均匀的。天文学家制定了以太阛_日视q动的^均速度为基的^太阳Ӟq_x的基本单位是q_x。国际天文学联合会于1928q决定,由格林威治q_夜v的q_xUCؓ世界ӞUUT?BR>UT0是天文台观测到的原始数据。UT1在UT0的基上,消除了地轴摆动的影响。还有一个修正了地球自{速度季节性变动的UT2Q现在已l不用了。其实UT0、UT1、UT2的差异很,不超q?.03U。现在提到的世界时一般指UT1? <P></P> <H4>1.3 时区</H4>世界时区的划?是以本初子午Uؓ标准Q从西经7?分到东经7?分ؓ零时区;从零时区的边界分别向东和向西Q每隔经?5度划一个时区。东、西各划?12个时区,东十二时Z西十二时区相重合。全球共划分?4个时区。各时区都以中央l线的地Ҏ为本区的区时Q相M时区的区时相差一时?BR>在太qx中靠q?80l线附近有一条国际规定的国际日期变更U?U日界线)。此U两侧的日期不同。由东向西过日界U,日期要增加一天(即略M天不)Q由西向东过日界U,日期要减一?x期重复一?? <P></P> <H4>1.4 协调世界ӞUTCQ和闰秒</H4>Z调和天文学需求和单位旉需求的差异Q一U称为协调世界时QUTCQ的折衷时标?972q面世。UTC的秒长与国际原子ӞTAIQ相同。但在必要时QUTC会增?U或L1U,使UTC和世界时(UT1)的时M差保持在u0.9U以内。这一技术措施被UCؓ闰秒QLeap SecondQ?BR>因此QUTC与TAI之间会出现若q整数秒的差别。位于巴黎的国际地球自{事务中央局(IERS)负责军_何时加入闰秒。TAI是从1958q??? ??U开始计时的。在本文写作Ӟ2005q?月)QUTC旉比TAI旉?2U。最q一ơ闰U调整是1999q??日。下ơ闰U调整是 2006q??日?BR>我们提到的地区标准时是在UTC上加上时差得到的本地旉? <P></P> <H4>1.5 格林威治旉QGMTQ?/H4>格林威治旉QGMTQ是一个比较模p的概念。在1928q_GMT是世界时。在UTC被广泛采用后Q我们提到的GMT实际上是UTC旉Q或者说零时区的标准时? <P></P> <H4>1.6 GPS旉</H4>GPS旉可以看作没有闰秒调整的UTC旉Qƈ?980q?????UؓL。目前GPS旉比UTC旉?3U?BR>协调世界ӞUTCQ将?005q底实施一个正闰秒。届Ӟ所有的旉拨?U。GPS旉不做闰秒调整Q所以将比UTC旉?4U。从GPS旉计算本地旉Q需要减ȝ前篏计的闰秒Q再加上本地的时差? <P></P> <H4>1.7 结</H4>在所有时标中Q日和秒的关p都是固定的Q每?6400U。确定了U的长度Q就定了日的长度,反之亦然。原子时标以Uؓ基准Q秒和日的长度都是固定的。世界时以日为基本单位,每日的长度会有毫U的差异。UTC既保证了单位旉的精,又通过闰秒调整与天文观的旉保持不大于?.9U的误差。我们日常生zM使用的时间都以UTC旉为标准?BR>时标作ؓ旉的刻度,为时间长沛_立了一根以U或日ؓ单位的坐标u。虽Ӟ“GPS旉280948U”可以标志一个唯一的时刻,但用于日常生zL免不太方ѝ在日常生活中,我们需要更方便的标记时间的ҎQ这是下面要谈到的历法? <P></P> <H3>2、历?/H3>所谓历法,是通过合理地安排年、月、日q三个基本量的关p,为时间徏立标记的Ҏ? <P></P> <H4>2.1 回归q和朔望?/H4>前面说过Q地球自转可以看作太阳的周日视运动。同理,地球l太阳的公{Q可以被看作太阳的周q视q动。周q视q动的轨道被UC黄道Q黄道面和赤道面的夹角是2327‌Ӏ随着太阳在黄道上的位|不同,地球上的季节也由春到夏,以至U冬?BR>黄道和赤道的两个交点分别被称作春分点和秋分点Q这两点在黄道上的两个中点分别被UC夏至点和冬至炏V太阳从春分点出发,l黄道一周,又回到春分点所q旉被称为回归年。目前测量的回归q长度是365.242189日?BR>月亮的盈亏变化,产生了月。月亮绕地球旋{Q当转到正对着太阳的位|,我们׃观测到满月,q就是望Q当转到背对太阳的位|,我们会完全看不到Q这是朔。月亮从朔到朔,或从望到望所q旉被称作朔望月。目前测量的朔望月长度是29.530588853000001日? <P></P> <H4>2.2 历法的分c?/H4>仅以太阳q动Z据的历法被称作阳历或太阳历。例如我们现在用的公历。阳历以回归qؓ基本周期Q与月亮q动没有M关系?BR>仅以月亮q动Z据的历法被称作阴历或太阴历。例如伊斯兰教国家和地区使用的回历。阴历以朔望月ؓ基本周期Q与太阳q动没有M关系?BR>同时考虑太阳和月亮运动的历法被称作阴阛_Q例如我国的农历。在我国Q农历习惯上也被UC阴历。阴阛_把回归年和朔望月q列为制历的基本周期?BR>׃回归q、朔望月的长度都不是日的整数倍,所以各U历法都要通过增加闰日或闰月,来调整自׃基本周期的差异。下面介l几U常用的历法? <P></P> <H4>2.3 儒略?/H4>公元?6q_|马执政官儒略·凯撒颁布了儒略历。儒略历每年12个月Q^q?65天,闰年366天。除2月外Q单数月?1天,偶数月䆾30天?月䆾q_29天,闰年30天。每?q置一闰年?BR>儒略历是U太阛_Q每q的q_长度?65.25天。每400q_儒略历与回归q大U相?天,卻I<BR>(365.25-365.242189)*400 = 3.1244<BR>凯撒ZU念改历成功Q将他出生的7月从QuintilisҎ自己的名字Julius? <P></P> <H4>2.4 奥古斯都?/H4>奥古斯都是“神圣”的意思,q是当时Z对罗马统治者屋大维的尊U?BR>从公元前42q到公元?q_儒略历被错误地执行ؓ“每3q置一闰年”。儒略·凯撒的侄子屋大l纠正了q个错误Q同时将自己出生?月从Sextilis Ҏ自己的称号AugustusQ将8月改?1天,??0?1?2月的大小月对换,q从2月䆾扣去一天,成ؓq_28天,闰年29天?BR>奥古斯都历的月䆾讄和现在的公历已经完全相同了? <P></P> <H4>2.5 格里高利历——公?/H4>公元1582q??日,|马教皇格里高利十三世颁布了格里高利历,不能被4整除的世U年作q_Q这是我们现在使用的公历?BR>在公历中Q每400q有97个闰q_q_每年的长度是Q?BR>(365*400+97)/400 = 365.2425 ?BR>?00q_公历与回归年大约相差0.1244天,卻I<BR>(365.2425-365.242189)*400 = 0.1244 <P></P> <H4>2.6 儒略日和化儒略日</H4>在天文学有一U连l纪日的儒略日(JDQ,它以儒略历公元前4713q??日的GMT正午为第0日的开始。还有一U简化儒略日QMJDQ:<BR>MJD=JD-2400000.5<BR>MJD的第0日是从公?858q?1?7日的GMT零时开始的。我写完前一个句h的MJD?3583.22260。小数部分是以UTC旉在当天逝去的秒数除?6400得到的?.22260UؓUTC旉?:20Q加上中国的时区是13:20?BR>需要注意:儒略历公元前4713q??日相当于公历公元?713q?1?4日。在香港天文台的|页上,儒略历说成以“公元前4713q??日格林尼d^时正午”v,是错误的? <P></P> <H4>2.7 农历</H4> <H5>2.7.1 月的划分</H5>农历的月是严格按照朔的时ȝ定的Q朔所在日是初一。由于朔望月的长度约?9.A日(小数部分记作AQ,假设朔发生在(30-29.A)日以内的时刻Q两个朔之间只?9天,该月是月Q否则两个朔之间?0天,该月是大月? <P></P> <H5>2.7.2 设计</H5>我们已经Ҏ月亮的运动规律将旉长u划分Z个个月,下面要做的就是确定将哪些月组合成q。设计要求是Q该设计应四季在每q的位置相对E_?BR>设计思\是这LQ四季变化以回归qؓ周期Q回归年的长度约?65.242189日?2个朔望月的长度约?54.367066236日,13个朔望月的长度约?83.897655089。如果我们让有的q䆾?2个朔望月Q有的年份有13个朔望月Qƈ按照一定周期@环;在一个周期内Q年的^均长度接q回归年的长度,p实现我们的设计目标。例如:我们?9q中Q让7q有13个月Q其它年?2个月Q则?9q的周期里,每年的^均长度是Q?BR>(29.530588853000001*(12*19+7))/19 ?365.246756866 ?BR>q个l果与回归年的长度已l比较接q。包?2个朔望月的年份被UCq_Q包?3个朔望月的年份被UC闰年Q闰q多加的一个月被称作闰月,q就是《尚书·尧典》中所说的“以闰月定四时成岁”?BR>那么Q闰月加在哪里呢Q在介绍|闰的规则前Q必d介绍一下节气? <P></P> <H5>2.7.3 二十四节?/H5>以春分点为黄l?度,黄道分成二十四{分Q每{分占黄l?5度,太阳通过{分点的时刻是对应节气的时刅R二十四节气只与太阳的运动有养I所以它们在公历中的日期变化不大?BR>二十四节气从立春Q黄l?0度)开始,依次为立春、雨水、惊蛰、春分、清明、谷雨、立夏、小满、芒U、夏臟뀁小暑、大暑、立U、处暑、白霌Ӏ秋分、寒霌Ӏ霜降、立冬、小雪、大雪、冬臟뀁小寒、大寒?BR>立春作为第1个节气,依次~号。偶数编L节气被称为“中气”(major solar termsQ,奇数~号的节气仍UC“节气”(minor solar termsQ。我们在日常生活中将节气和中气统UCؓ节气Qsolar termsQ。中气是|闰的重要依据? <P></P> <H5>2.7.4 |闰</H5>在农历中Q从前一q正月初一C一q正月初一被称作年。显Ӟ必须先确定了闰月Q才能确定年的范_我们不可能在|闰规则中用到“年”。实际上Q我们用C另一个概念:岁。从前一个冬臛_下一个冬臌UC岁。“岁”的长度是回归q的长度?BR>冬至所在的月被定义?1月。如果在两个11月间?2个完整的月,那么q两?1月间的岁pUC闰岁。因两个11月间只有11个中气,所以闰岁的12个月中至有一个月没有中气?BR>闰岁的第一个不含中气的月,是闰月。至此,我们已经描述了编制农历的完整规则? <P></P> <H5>2.7.5 闰年和Y2033问题</H5>包含闰月的年被称作闰q。如果闰月出现在11月,可能出现前一q是闰年Q但不是闰岁Q后一q是闰岁Q但不是闰年。一个典型的例子是Y2033问题?BR>?033q的W?个月vQ第8个月没有中气Q第11个月有两个中气,W?2个月没有中气Q第13个月有两个中气,W?4个月没有中气。在2032q的 11月和2033q?1月间只有11个完整的月,不是闰岁。在2033q的11月和2034q?1月间?2个完整的月,是闰岁?BR>按照|闰规则Q第12个月被作为闰月,即闰11月?月没有中气,又不是闰月,被称作伪闰月QFake leap monthQ?034q是闰岁Q但不是闰年?034岁的闰月已经?033q加q了?BR>国内1990q以前的万年历都?033q设为闰7月,q个错误被称作Y2033问题。以后出版的万年历都Ҏ了闰11月。但|上的一些万q历E序现在q在使用错误的农历数据? <P></P> <H4>2.7 回历</H4>作ؓ太阴历的例子Q简单介l一下回历。回历是伊斯兰教国家和地区采用的历法。它以朔望月为基本周期,每年12个月。^q奇数月30天,偶数?9天,?54天?BR>?0qؓ一周,?1个闰日。在30q@环周期中Q第2???0?3?6?8?1?4?6?9qؓ闰年。闰q在12月底增加一??55天?BR>在回历中Q月的^均长度是Q?BR>(354*30+11)/30/12 ?29.53 ?BR>q和朔望月长度非常接q,很好地符合了月亮的运动规律。年的^均长度是Q?BR>(354*30+11)/30 ?354.366667 ?BR>q和回归q约?1天。因此回历的新年在公历中会逐年提早Q@环周期ؓ<BR>365.242189/(365.242189-354.366667) ?33.5838766176 q?BR>回历的v始历元被UC伊斯兰教U元Q定在穆|默德从麦加q到麦地那的一天,卛_略历公元622q??6日,在公历中是公?22q??9日。例如:伊斯兰教U元1426q??日是公元2005q??0日。伊斯兰教纪?427q??日是公元2006q??1日? <P></P> <H4>2.8 结</H4>公历和回历的计算都很单。但公历的月不能W合月亮的运动规律。回历的q不能符合太阳的q动规律。农历较好地W合了太阛_月亮的运动规律,但计比较复杂?BR>在网上可以找到计各国历法的E序。我曄其中一个JavaE序库的农历部分改写成C/C++E序Q以提高q算速度。在我的个h主页上有关于农历计算E序的进一步讨?<A >http://fmddlmyy.home4u.china.com/cal.html</A>)。不q这些内容已l超Z本文的范围?BR>在写q篇文章前,我不知道“时标”,对历法的概念也很模糊。通过查资料、写作,我对相关概念的了解越来越清晰。这文章的写作目的是将时标、历法的一些基本概늮单、清晰地描述出来Q希望有更多的读者像我一样从中受益? <P></P><img src ="http://www.tkk7.com/Pudgy/aggbug/11420.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.tkk7.com/Pudgy/" target="_blank">Pudgy's World</a> 2005-08-29 11:42 <a href="http://www.tkk7.com/Pudgy/archive/2005/08/29/11420.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>谈谈Unicode~码Q简要解释UCS、UTF、BMP、BOM{名?/title><link>http://www.tkk7.com/Pudgy/archive/2005/08/29/11419.html</link><dc:creator>Pudgy's World</dc:creator><author>Pudgy's World</author><pubDate>Mon, 29 Aug 2005 03:39:00 GMT</pubDate><guid>http://www.tkk7.com/Pudgy/archive/2005/08/29/11419.html</guid><wfw:comment>http://www.tkk7.com/Pudgy/comments/11419.html</wfw:comment><comments>http://www.tkk7.com/Pudgy/archive/2005/08/29/11419.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.tkk7.com/Pudgy/comments/commentRss/11419.html</wfw:commentRss><trackback:ping>http://www.tkk7.com/Pudgy/services/trackbacks/11419.html</trackback:ping><description><![CDATA[<!--StartFragment --> 转自<A >http://fmddlmyy.home4u.china.com/text6.html</A> <H2>谈谈Unicode~码Q简要解释UCS、UTF、BMP、BOM{名?/H2> <P>q是一程序员写给E序员的味ȝ。所谓趣x指可以比较轻村֜了解一些原来不清楚的概念,增进知识Q类g打RPG游戏的升U。整理这文章的动机是两个问题:</P> <DL> <DT>问题一Q?/DT> <DD> <P>使用WindowsC本的“另存ؓ”,可以在GBK、Unicode、Unicode big endian和UTF-8q几U编码方式间怺转换。同htxt文gQWindows是怎样识别~码方式的呢Q?/P> <P>我很早前发现Unicode、Unicode big endian和UTF-8~码的txt文g的开头会多出几个字节Q分别是FF、FEQUnicodeQ?FE、FFQUnicode big endianQ?EF、BB、BFQUTF-8Q。但q些标记是基于什么标准呢Q?/P></DD> <DT>问题二:</DT> <DD>最q在|上看到一个ConvertUTF.cQ实CUTF-32、UTF-16和UTF-8q三U编码方式的怺转换。对于Unicode(UCS2)?GBK、UTF-8q些~码方式Q我原来׃解。但q个E序让我有些p涂Q想不v来UTF-16和UCS2有什么关pR?/DD></DL> <P>查了查相兌料,ȝ这些问题弄清楚了,带也了解了一些Unicode的细节。写成一文章,送给有过cM疑问的朋友。本文在写作时尽量做到通俗易懂Q但要求读者知道什么是字节Q什么是十六q制?/P> <H3>0、big endian和little endian</H3> <P>big endian和little endian是CPU处理多字节数的不同方式。例如“汉”字的Unicode~码?C49。那么写到文仉ӞI竟是将6C写在前面Q还是将49写在前面Q如果将6C写在前面Q就是big endian。如果将49写在前面Q就是little endian?/P> <P>“endian”这个词《格列佛游记》。小人国的内战就源于吃鸡蛋时是究竟从大头(Big-Endian)敲开q是从小?Little-Endian)敲开Q由此曾发生q六ơ叛乱,一个皇帝送了命,另一个丢了王位?/P> <P>我们一般将endian译成“字节序”,big endian和little endianUC“大䏀和“小䏀?/P> <H3>1、字W编码、内码,带介绍汉字~码</H3> <P>字符必须~码后才能被计算机处理。计机使用的缺省编码方式就是计机的内码。早期的计算Z?位的ASCII~码Qؓ了处理汉字,E序员设计了用于体中文的GB2312和用于繁体中文的big5?/P> <P>GB2312(1980q?一共收录了7445个字W,包括6763个汉字和682个其它符受汉字区的内码范围高字节从B0-F7Q低字节从A1-FEQ占用的码位?2*94=6768。其中有5个空位是D7FA-D7FE?/P> <P>GB2312支持的汉字太?995q的汉字扩展规范GBK1.0收录?1886个符P它分为汉字区和图形符号区。汉字区包括21003个字W?/P> <P>从ASCII、GB2312到GBKQ这些编码方法是向下兼容的,卛_一个字W在q些Ҏ中L有相同的~码Q后面的标准支持更多的字W。在q些~码中,英文和中文可以统一地处理。区分中文编码的Ҏ是高字节的最高位不ؓ0。按照程序员的称|GB2312、GBK都属于双字节字符?(DBCS)?/P> <P>2000q的GB18030是取代GBK1.0的正式国家标准。该标准收录?7484个汉字,同时q收录了藏文、蒙文、维向ְ文等主要的少数民族文字。从汉字字汇上说QGB18030在GB13000.1?0902个汉字的基础上增加了CJK扩展A?582个汉字(Unicode?0x3400-0x4db5Q,一共收录了27484个汉字?/P> <P>CJK是中日韩的意思。UnicodeZ节省码位Q将中日韩三国语a中的文字l一~码。GB13000.1是ISO/IEC 10646-1的中文版Q相当于Unicode 1.1?/P> <P>GB18030的编码采用单字节、双字节?字节Ҏ。其中单字节、双字节和GBK是完全兼容的?字节~码的码位就是收录了CJK扩展A?582个汉字?例如QUCS?x3400在GB18030中的~码应该?139EF30QUCS?x3401在GB18030中的~码应该?139EF31?/P> <P>微Y提供了GB18030的升U包Q但q个升包只是提供了一套支持CJK扩展A?582个汉字的新字体:新宋?18030Qƈ不改变内码。Windows 的内码仍然是GBK?/P> <P>q里q有一些细节:</P> <UL> <LI> <P>GB2312的原文还是区位码Q从Z码到内码Q需要在高字节和低字节上分别加上A0?/P></LI> <LI> <P>对于M字符~码Q编码单元的序是由~码Ҏ指定的,与endian无关。例如GBK的编码单元是字节Q用两个字节表示一个汉字?q两个字节的序是固定的Q不受CPU字节序的影响。UTF-16的编码单元是wordQ双字节Q,word之间的顺序是~码Ҏ指定的,word内部的字节排列才会受到endian的媄响。后面还会介lUTF-16?/P></LI> <LI> <P>GB2312 的两个字节的最高位都是1。但W合q个条g的码位只?28*128=16384个。所以GBK和GB18030的低字节最高位都可能不?。不q这不媄响DBCS字符的解析Q在dDBCS字符时Q只要遇到高位ؓ1的字节,可以将下两个字节作Z个双字节~码Q而不用管低字节的高位是什么?/P></LI></UL> <H3>2、Unicode、UCS和UTF</H3> <P>前面提到从ASCII、GB2312、GBK到GB18030的编码方法是向下兼容的。而Unicode只与ASCII兼容Q更准确地说Q是与ISO-8859-1兼容Q,与GB码不兼容。例如“汉”字的Unicode~码?C49Q而GB码是BABA?/P> <P>Unicode也是一U字W编码方法,不过它是由国际组l设计,可以容纳全世界所有语a文字的编码方案。Unicode的学名是"Universal Multiple-Octet Coded Character Set"Q简UCؓUCS。UCS可以看作?Unicode Character Set"的羃写?/P> <P>Ҏl基癄全书(http://zh.wikipedia.org/wiki/)的记载:历史上存在两个试囄立设计Unicode的组l,卛_际标准化l织QISOQ和一个Y件制造商的协会(unicode.orgQ。ISO开发了ISO 10646目QUnicode协会开发了Unicode目?/P> <P>?991q前后,双方都认识到世界不需要两个不兼容的字W集。于是它们开始合q双方的工作成果Qƈ为创立一个单一~码表而协同工作。从Unicode2.0开始,Unicode目采用了与ISO 10646-1相同的字库和字码?/P> <P>目前两个目仍都存在Qƈ独立地公布各自的标准。Unicode协会现在的最新版本是2005q的Unicode 4.1.0。ISO的最新标准是ISO 10646-3:2003?/P> <P>UCS只是规定如何~码Qƈ没有规定如何传输、保存这个编码。例如“汉”字的UCS~码?C49Q我可以?个ascii数字来传输、保存这个编码;也可以用utf-8~码:3个连l的字节E6 B1 89来表C它。关键在于通信双方都要认可。UTF-8、UTF-7、UTF-16都是被广泛接受的Ҏ。UTF-8的一个特别的好处是它与ISO-8859-1完全兼容。UTF是“UCS Transformation Format”的~写?/P> <P>IETF的RFC2781和RFC3629以RFC的一贯风|清晰、明快又不失严}地描qCUTF-16和UTF-8的编码方法。我LC得IETF是Internet Engineering Task Force的羃写。但IETF负责l护的RFC是Internet上一切规范的基础?/P> <H4>2.1、内码和code page</H4> <P>目前Windows的内核已l支持Unicode字符集,q样在内怸可以支持全世界所有的语言文字。但是由于现有的大量E序和文档都采用了某U特定语a的编码,例如GBKQWindows不可能不支持现有的编码,而全部改用Unicode?/P> <P>Windows使用代码?code page)来适应各个国家和地区。code page可以被理解ؓ前面提到的内码。GBK对应的code page是CP936?/P> <P>微Y也ؓGB18030定义了code pageQCP54936。但是由于GB18030有一部分4字节~码Q而Windows的代码页只支持单字节和双字节~码Q所以这个code page是无法真正用的?/P> <H3>3、UCS-2、UCS-4、BMP</H3> <P>UCS有两U格式:UCS-2和UCS-4。顾名思义QUCS-2是用两个字节编码,UCS-4是?个字节(实际上只用了31位,最高位必须?Q编码。下面让我们做一些简单的数学游戏Q?/P> <P>UCS-2?^16=65536个码位,UCS-4?^31=2147483648个码位?/P> <P>UCS-4Ҏ最高位?的最高字节分?^7=128个group。每个group再根据次高字节分?56个plane。每个planeҎW?个字节分?56?(rows)Q每行包?56个cells。当然同一行的cells只是最后一个字节不同,其余都相同?/P> <P>group 0的plane 0被称作Basic Multilingual Plane, 即BMP。或者说UCS-4中,高两个字节ؓ0的码位被UCBMP?/P> <P>UCS-4的BMPL前面的两个零字节得CUCS-2。在UCS-2的两个字节前加上两个零字节,得CUCS-4的BMP。而目前的UCS-4规范中还没有M字符被分配在BMP之外?/P> <H3>4、UTF~码</H3> <P></P> <P>UTF-8是?位ؓ单元对UCSq行~码。从UCS-2到UTF-8的编码方式如下:</P> <TABLE width="75%" border=1> <TBODY> <TR> <TD>UCS-2~码(16q制)</TD> <TD>UTF-8 字节?二进?</TD></TR> <TR> <TD>0000 - 007F</TD> <TD>0xxxxxxx</TD></TR> <TR> <TD>0080 - 07FF</TD> <TD>110xxxxx 10xxxxxx</TD></TR> <TR> <TD>0800 - FFFF</TD> <TD>1110xxxx 10xxxxxx 10xxxxxx</TD></TR></TBODY></TABLE> <P>例如“汉”字的Unicode~码?C49?C49?800-FFFF之间Q所以肯定要?字节模板了:<FONT color=#0000ff>1110</FONT>xxxx <FONT color=#0000ff>10</FONT>xxxxxx <FONT color=#0000ff>10</FONT>xxxxxx。将6C49写成二进制是Q?110 110001 001001Q?用这个比Ҏ依次代替模板中的xQ得刎ͼ<FONT color=#0000ff>1110</FONT>0110 <FONT color=#0000ff>10</FONT>110001 <FONT color=#0000ff>10</FONT>001001Q即E6 B1 89?/P> <P>读者可以用C本测试一下我们的~码是否正确。需要注意,UltraEdit在打开utf-8~码的文本文件时会自动{换ؓUTF-16Q可能生؜淆。你可以在设|中xq个选项。更好的工具是Hex Workshop?/P> <P>UTF-16?6位ؓ单元对UCSq行~码。对于小?x10000的UCS码,UTF-16~码q于UCS码对应的16位无W号整数。对于不于0x10000的UCS码,定义了一个算法。不q由于实际用的UCS2Q或者UCS4的BMP必然于0x10000Q所以就目前而言Q可以认?UTF-16和UCS-2基本相同。但UCS-2只是一个编码方案,UTF-16却要用于实际的传输,所以就不得不考虑字节序的问题?/P> <H3>5、UTF的字节序和BOM</H3> <P>UTF-8以字节ؓ~码单元Q没有字节序的问题。UTF-16以两个字节ؓ~码单元Q在解释一个UTF-16文本前,首先要弄清楚每个~码单元的字节序。例如“奎”的Unicode~码?94EQ“乙”的Unicode~码?E59。如果我们收到UTF-16字节?94E”,那么q是“奎?q是“乙”?</P> <P>Unicode规范中推荐的标记字节序的方法是BOM。BOM不是“Bill Of Material”的BOM表,而是Byte Order Mark。BOM是一个有点小聪明的想法:</P> <P>在UCS~码中有一个叫?ZERO WIDTH NO-BREAK SPACE"的字W,它的~码是FEFF。而FFFE在UCS中是不存在的字符Q所以不应该出现在实际传输中。UCS规范我们在传输字节流前,先传输字W?ZERO WIDTH NO-BREAK SPACE"?/P> <P>q样如果接收者收到FEFFQ就表明q个字节是Big-Endian的;如果收到FFFEQ就表明q个字节是Little-Endian的。因此字W?ZERO WIDTH NO-BREAK SPACE"又被UCBOM?/P> <P>UTF-8不需要BOM来表明字节顺序,但可以用BOM来表明编码方式。字W?ZERO WIDTH NO-BREAK SPACE"的UTF-8~码是EF BB BFQ读者可以用我们前面介绍的编码方法验证一下)。所以如果接收者收CEF BB BF开头的字节,q道这是UTF-8~码了?/P> <P>Windows是使用BOM来标记文本文件的~码方式的?/P> <H3>6、进一步的参考资?/H3> <P>本文主要参考的资料?"Short overview of ISO-IEC 10646 and Unicode" (http://www.nada.kth.se/i18n/ucs/unicode-iso10646-oview.html)?/P> <P>我还找了两篇看上M错的资料Q不q因为我开始的疑问都找C{案Q所以就没有看:</P> <OL> <LI>"Understanding Unicode A general introduction to the Unicode Standard" (http://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&item_id=IWS-Chapter04a)</LI> <LI>"Character set encoding basics Understanding character set encodings and legacy encodings" (http://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&item_id=IWS-Chapter03)</LI></OL> <P>我写qUTF-8、UCS-2、GBK怺转换的Y件包Q包括用Windows API和不使用Windows API的版本。以后有旉的话Q我会整理一下放到我的个Z上(http://fmddlmyy.home4u.china.com)?/P> <P>我是x楚所有问题后才开始写q篇文章的,原以Z会儿p写好。没惛_考虑措辞和查证细节花费了很长旉Q竟然从下午1:30写到9:00。希望有读者能从中受益?/P> <H3>附录1 再说说区位码、GB2312、内码和代码?/H3> <P>有的朋友Ҏ章中q句话还有疑问:<BR>“GB2312的原文还是区位码Q从Z码到内码Q需要在高字节和低字节上分别加上A0。?/P> <P>我再详细解释一下:</P> <P>“GB2312的原文”是指国?980q的一个标准《中华h民共和国国家标准 信息交换用汉字编码字W集 基本?GB 2312-80》。这个标准用两个数来~码汉字和中文符受第一个数UCؓ“区”,W二个数UCؓ“位”。所以也UCؓZ码?-9区是中文W号Q?6-55 区是一U汉字,56-87区是二汉字。现在Windows也还有区位输入法Q例如输?601得到“啊”。(q个Z输入法可以自动识?6q制?GB2312?0q制的区位码Q也是说输入B0A1同样会得到“啊”。)</P> <P>内码是指操作pȝ内部的字W编码。早期操作系l的内码是与语言相关的。现在的Windows在系l内部支持UnicodeQ然后用代码适应各种语言Q“内码”的概念比较模p了。微软一般将~省代码|定的~码说成是内码?/P> <P>内码q个词汇Qƈ没有什么官方的定义Q代码页也只是微软这个公司的叫法。作为程序员Q我们只要知道它们是什么东西,没有必要q多地考证q些名词?/P> <P>所谓代码页(code page)是针对一U语a文字的字W编码。例如GBK的code page是CP936QBIG5的code page是CP950QGB2312的code page是CP20936?/P> <P>Windows中有~省代码늚概念Q即~省用什么编码来解释字符。例如Windows的记事本打开了一个文本文Ӟ里面的内Ҏ字节:BA、BA、D7、D6。Windows应该L么解释它呢Q?/P> <P>是按照Unicode~码解释、还是按照GBK解释、还是按照BIG5解释Q还是按照ISO8859-1去解释?如果按GBK去解释,׃得到“汉字”两个字。按照其它编码解释,可能找不到对应的字符Q也可能扑ֈ错误的字W。所谓“错误”是指与文本作者的本意不符Q这时就产生了ؕ码?/P> <P>{案是Windows按照当前的缺省代码页去解释文本文仉的字节流。缺省代码页可以通过控制面板的区域选项讄。记事本的另存ؓ中有一ANSIQ其实就是按照缺省代码页的编码方法保存?/P> <P>Windows的内码是UnicodeQ它在技术上可以同时支持多个代码c只要文件能说明自己使用什么编码,用户又安装了对应的代码页QWindowsp正确昄Q例如在HTML文g中就可以指定charset?/P> <P>有的HTML文g作者,特别是英文作者,认ؓ世界上所有h都用英文,在文件中不指定charset。如果他使用?x80-0xff之间的字W,中文Windows又按照缺省的GBK去解释,׃出现q。这时只要在q个html文g中加上指定charset的语句,例如Q?BR><meta http-equiv="Content-Type" content="text/html; charset=ISO8859-1"><BR>如果原作者用的代码和ISO8859-1兼容Q就不会出现q了?/P> <P>再说Z码,啊的Z码是1601Q写?6q制?x10,0x01。这和计机q泛使用的ASCII~码冲突。ؓ了兼?0-7f的ASCII ~码Q我们在Z码的高、低字节上分别加上A0。这样“啊”的~码成为B0A1。我们将加过两个A0的编码也UCؓGB2312~码Q虽然GB2312的原文根本没提到q一炏V?</P><img src ="http://www.tkk7.com/Pudgy/aggbug/11419.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.tkk7.com/Pudgy/" target="_blank">Pudgy's World</a> 2005-08-29 11:39 <a href="http://www.tkk7.com/Pudgy/archive/2005/08/29/11419.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Gmail Invitation Sendhttp://www.tkk7.com/Pudgy/archive/2005/08/27/11283.htmlPudgy's WorldPudgy's WorldSat, 27 Aug 2005 02:43:00 GMThttp://www.tkk7.com/Pudgy/archive/2005/08/27/11283.htmlhttp://www.tkk7.com/Pudgy/comments/11283.htmlhttp://www.tkk7.com/Pudgy/archive/2005/08/27/11283.html#Feedback5http://www.tkk7.com/Pudgy/comments/commentRss/11283.htmlhttp://www.tkk7.com/Pudgy/services/trackbacks/11283.html

    Pudgy's World 2005-08-27 10:43 发表评论
    ]]>
    DotDashBorder 可以实现点划U的CustomBorderhttp://www.tkk7.com/Pudgy/archive/2005/08/27/11278.htmlPudgy's WorldPudgy's WorldSat, 27 Aug 2005 02:19:00 GMThttp://www.tkk7.com/Pudgy/archive/2005/08/27/11278.htmlhttp://www.tkk7.com/Pudgy/comments/11278.htmlhttp://www.tkk7.com/Pudgy/archive/2005/08/27/11278.html#Feedback0http://www.tkk7.com/Pudgy/comments/commentRss/11278.htmlhttp://www.tkk7.com/Pudgy/services/trackbacks/11278.html一个Custom Border
    可以实现点划U的Border.
    代码如下Q?BR>
    import java.awt.*;
    import javax.swing.
    *;
    import javax.swing.border.
    *;
     
    /**
     * DotDashBorder is a java.swing.border.Border implementation 
     * that draws a dotted and/or dashed line border.  The dot/dash pattern is 
     * defined as an array of ints, with every two indices defining the number 
     * of pixels for each dot/dash and space.  E.g.: 

     * { 1, 1 } == 1-pixel-dot, 1-pixel-space, 1-pixel-dot, 1-pixel-space, etc.

     * { 4, 2 } == 4-pixel-dash, 2-pixel-space, 4-pixel-dash, 2-pixel-space, etc.

     
    */
    public class DotDashBorder extends AbstractBorder {
        
    /**
         * Defines a dotted line pattern:  
    . . . .

         
    */
        
    public static final int[] DOT = { 11 };
     
        
    /**
         * Defines a dashed line pattern:  
    - - - -

         
    */
        
    public static final int[] DASH_SHORT = { 44 };
     
        
    /**
         * Defines a long dashed line pattern:  
    ---   ---   ---

         
    */
        
    public static final int[] DASH_LONG = { 1010 };
     
        
    /**
         * Defines a long/short dashed line pattern:  
    -- - -- - -- -

         
    */
        
    public static final int[] DASH_LONG_SHORT = { 6333 };
     
        
    /**
         * Defines a long/short/short dashed line pattern:  
    -- - - -- - - -- - -

         
    */
        
    public static final int[] DASH_LONG_SHORT_SHORT = { 633333 };
     
        
    /**
         * The dot/dash pattern.
         
    */
        
    private int[] pattern = DOT;
     
        
    /**
         * The border thickness
         
    */
        
    private int thickness = 1;
     
        
    /**
         * The foreground color.  If not specified, the component's foreground 
         * color is used.  
         
    */
        
    private Color colorFG = null;
     
        
    /**
         * The background color.  If not specified, the component's background 
         * color is used.  
         
    */
        
    private Color colorBG = null;
     
        
    /**
         * Thicken border pattern relative to thickness flag.  
         
    */
        
    private boolean thicken = false;
     
        
    /**
         * Create a new 1-pixel thick DotDashBorder using the component's 
         * background color.
         * @param  pattern  int[]: the dot/dash-space pattern
         * @param  fg  Color: the foreground (dot/dash) color
         
    */
        
    public DotDashBorder(int[] pattern, Color fg) {
            
    this(pattern, 1,  fg, null);
        }
     
        
    /**
         * Create a new DotDashBorder using the component's foreground and 
         * background colors.
         * @param  pattern  int[]: the dot/dash-space pattern
         * @param  thickness  int: the border thickness
         
    */
        
    public DotDashBorder(int[] pattern, int thickness) {
            
    this(pattern, thickness, nullnull);
        }
     
        
    /**
         * Create a new DotDashBorder using the component's 
         * background color.
         * @param  pattern  int[]: the dot/dash-space pattern
         * @param  thickness  int: the border thickness
         * @param  fg  Color: the foreground (dot/dash) color
         
    */
        
    public DotDashBorder(int[] pattern, int thickness, Color fg) {
            
    this(pattern, thickness,  fg, null);
        }
     
        
    /**
         * Create a new DotDashBorder.
         * @param  pattern  int[]: the dot/dash-space pattern
         * @param  thickness  int: the border thickness
         * @param  fg  Color: the foreground (dot/dash) color
         * @param  bg  Color: the background (space) color
         
    */
        
    public DotDashBorder(int[] pattern, int thickness, Color fg, Color bg) {
            
    for(int i = 0; i < pattern.length; i++) {
                
    if(pattern[i] <= 0) {
                    
    throw new IllegalArgumentException("Pattern cannot have values <= 0.");
                }
            }
            
    this.pattern = pattern;
            
    if(thickness <= 0) {
                
    throw new IllegalArgumentException("Thickness cannot be <= 0.");
            }
            
    this.thickness = thickness;
            
    this.colorFG = fg;
            
    this.colorBG = bg;
        }
     
        
    /**
         * Get the insets for the border.
         * @param  Component c: the component the border is for
         * @return  Insets: the insets for the border
         * @see  #getBorderInsets(Component, Insets)
         
    */
        
    public Insets getBorderInsets(Component c) {
            
    return new Insets(thickness, thickness, thickness, thickness);
        }
     
        
    /**
         * Get the insets for the border.
         * @param  Component c: the component the border is for
         * @param  insets  Insets: the insets
         * @return  Insets: the insets for the border
         * @see  #getBorderInsets(Component)
         
    */
        
    public Insets getBorderInsets(Component c, Insets insets) {
            
    return new Insets(thickness, thickness, thickness, thickness);
        }
     
        
    /**
         * Check if the border is opaque.
         * @return  boolean: true if the border is opaque
         
    */
        
    public boolean isBorderOpaque() {
            
    return true;
        }
     
        
    /**
         * Check if pattern will be thickened by thickness.
         * @return  boolean: true if pattern will be thickened by thickness
         * @see  #setThickenPattern(boolean)
         
    */
        
    public boolean isThickenPattern() {
            
    return this.thicken;
        }
     
        
    /**
         * Set if the pattern should be thickened by thickness.  If true, a 
         * pattern of { 1, 1 } and thickness of 5, the pattern would be expanded 
         * to { 5, 5 }.  This allows setting a pattern based on small pixel 
         * measurements that grows proportionally with the thickness.  
         * @param  boolean t: true if pattern should be thickened by thickness
         * @see  #isThickenPattern()
         
    */
        
    public void setThickenPattern(boolean t) {
            
    this.thicken = t;
        }
     
        
    /**
         * Paint the border.
         * @param  Component c: the component the border is for
         * @param  Graphics g: the graphics object to draw on
         * @param  x  int: the border y position
         * @param  y  int: the border x position
         * @param  width  int: the border width
         * @param  height  int: the border height
         
    */
        
    public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) {
            Color colorFGX 
    = c.getBackground();
            
    if(colorFG != null) {
                colorFGX 
    = colorFG;
            }
            Color colorBGX 
    = c.getBackground();
            
    if(colorBG != null) {
                colorBGX 
    = colorBG;
            }
            g.setColor(colorFGX);
            g.fillRect(x, x, width, thickness);                
    // top
            g.fillRect(x, y+height-thickness, width, thickness);    // bottom
            g.fillRect(x, y, thickness, height);                // left
            g.fillRect(x+width-thickness, y, thickness, height);    // right
            g.setColor(colorBGX);
            
    // top/bottom
            int cx = 0;
            
    // get real pattern
            int[] realPattern = new int[pattern.length];
            
    for(int i = 0; i < pattern.length; i++) {
                
    if(thicken) {
                    realPattern[i] 
    = pattern[i]*thickness;
                } 
    else {
                    realPattern[i] 
    = pattern[i];
                }
            }
            
    for(int i = 0, j = 0; i < width; i++, j+=2) {
                
    if(j >= realPattern.length) {
                    j 
    = 0;
                }
                cx 
    += realPattern[j];
                g.fillRect(cx, y, realPattern[j
    +1], thickness);                // top
                g.fillRect(cx, y+height-thickness, realPattern[j+1], thickness);    // bottom
                cx += realPattern[j+1];
            }
            
    // left/right
            int cy = 0;
            
    for(int i = 0, j = 0; i < height; i++, j+=2) {
                
    if(j >= realPattern.length) {
                    j 
    = 0;
                }
                cy 
    += realPattern[j];
                g.fillRect(x, cy, thickness, realPattern[j
    +1]);                // left
                g.fillRect(x+width-thickness, cy, thickness, realPattern[j+1]);    // right
                cy += realPattern[j+1];
            }
        }
    }


    Pudgy's World 2005-08-27 10:19 发表评论
    ]]>
    一个简单的SplashScreenhttp://www.tkk7.com/Pudgy/archive/2005/08/22/10734.htmlPudgy's WorldPudgy's WorldMon, 22 Aug 2005 13:29:00 GMThttp://www.tkk7.com/Pudgy/archive/2005/08/22/10734.htmlhttp://www.tkk7.com/Pudgy/comments/10734.htmlhttp://www.tkk7.com/Pudgy/archive/2005/08/22/10734.html#Feedback2http://www.tkk7.com/Pudgy/comments/commentRss/10734.htmlhttp://www.tkk7.com/Pudgy/services/trackbacks/10734.html最q编写项目,用到一个Splash Screen?BR>现奉献给大家?BR>
    import java.awt.Dimension;
    import java.awt.Toolkit;
    import java.net.URL;

    import javax.swing.ImageIcon;
    import javax.swing.JFrame;
    import javax.swing.JLabel;

    public class SplashScreen extends JFrame {
        
    /**Date 08.17.2005
         * 
         * Splash Screen
         * Very Simple
         * @author Pudgy
         * @version 0.01
         * 
         * 
         
    */
        
    private static final long serialVersionUID = 5124L;

        
    public SplashScreen() {
            super(
    "Starting jDicomSee");
            Toolkit toolkit 
    = Toolkit.getDefaultToolkit();
            Dimension screenSize 
    = toolkit.getScreenSize();
            URL imageURL 
    = searchFile("splash.png");
            
    if (imageURL != null) {
                getContentPane().add(
    new JLabel(new ImageIcon(imageURL)));

            }
            setUndecorated(
    true);
            pack();
            setLocation((screenSize.width 
    - getWidth()) / 2,
                    (screenSize.height 
    - getHeight()) / 2);
            setVisible(
    true);
            
    try {
                Thread.sleep(
    1500);
            } 
    catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        
    private URL searchFile(String fileName) {
            URL url 
    = getClass().getClassLoader().getResource(fileName);
            
    if (url == null)
                url 
    = getClass().getClassLoader().getResource("images/" + fileName);
            
    return url;
        }
    }


    Pudgy's World 2005-08-22 21:29 发表评论
    ]]>Fat Jar Eclipse Plug-In Tutorialhttp://www.tkk7.com/Pudgy/archive/2005/08/22/10727.htmlPudgy's WorldPudgy's WorldMon, 22 Aug 2005 12:31:00 GMThttp://www.tkk7.com/Pudgy/archive/2005/08/22/10727.htmlhttp://www.tkk7.com/Pudgy/comments/10727.htmlhttp://www.tkk7.com/Pudgy/archive/2005/08/22/10727.html#Feedback5http://www.tkk7.com/Pudgy/comments/commentRss/10727.htmlhttp://www.tkk7.com/Pudgy/services/trackbacks/10727.htmlFat Jar Eclipse Plug-In [FJEP] (http://fjep.sourceforge.net/) 是应用One-Jar(http://one-jar.sourceforge.net/)技术的一个Eclipse 插g。利用FatJarQ可以极大地方便发布Java应用E序与Applet?br>下面是我写的一个教E,Ƣ迎指教?br>
    1.介绍
    一个非常简单的软g打包解决ҎQ它利用 Java 的定制类装入器,动态地从单一档案文g中装入应用程序所有的c,同时保留支持 JAR 文g的结构。随着 FatJar Eclipse 插g FJEP 的推出, Eclipse 的用L在只要在向导中选中一个复选框Q就可以创徏 One-JAR 应用E序。依赖的库被放进 lib/ 目录Q主E序和类被放q?main/main.jarQƈ自动写好 META-INF/MANIFEST.MF 文g?br>
    2.
    安装
    安装很简单,只需把解压出来的文g攑ֈEclipse 的目录中卛_?br>
    3.使用图解
    我以打包我的E序文g作ؓ例子?br>
    (1)在包览器面板中Q选中Build Fat Jar?br>o_FatJar-1.png

    (2)选择ȝ入口。注意选中Merge individual-sections of all MANIFEST.MF Files.?br>o_FatJar-2.png

    (3)选择你要打包的独立JAR文gQ这些文件会打包q入最后的Fat-Jar?br>o_FatJar-3.png

    (4)成功了?br>o_FatJar-4.png
    4.SWT E序的打?br>同样的步骤,只不q最后发布时Q连带SWT-XXX.DLL攑֜同一目录下即可?br>参见http://fjep.sourceforge.net/fjepfaq.html

    5.下蝲
    http://fjep.sourceforge.net/
    也可下蝲我已打包好的文g?br>http://www.tkk7.com/Files/Pudgy/net.sf.fjep.fatjar_0.0.18.rar



    Pudgy's World 2005-08-22 20:31 发表评论
    ]]>
    ZBatik的SVG应用: 关于几何变换http://www.tkk7.com/Pudgy/archive/2005/08/20/10572.htmlPudgy's WorldPudgy's WorldSat, 20 Aug 2005 00:55:00 GMThttp://www.tkk7.com/Pudgy/archive/2005/08/20/10572.htmlhttp://www.tkk7.com/Pudgy/comments/10572.htmlhttp://www.tkk7.com/Pudgy/archive/2005/08/20/10572.html#Feedback0http://www.tkk7.com/Pudgy/comments/commentRss/10572.htmlhttp://www.tkk7.com/Pudgy/services/trackbacks/10572.html

    摘自http://www-128.ibm.com/developerworks/cn/xml/x-BatikSvg/?ca=dwcn-newsletter-xml
    陈柯

    技术ȝ, 南京安元U技
    2005 q?1 ?

    本文是作者在 SVGGIS pȝ的开发实践过E中关于 SVG 坐标转换的ȝ。在描述 SVG 坐标变换原理的同Ӟ使用 Apache Batik 目实现了相关例子?/BLOCKQUOTE>

    SVG 是一U用 xml 语言来描qCl图形对象的语言QSVG 允许三种囑Ş对象Q?Q矢量图形,2Q图片,3Q文本对象。这三种囑Ş对象都可以支持分l,使用样式渲染Q进行几何变换?/P>

    SVG q能够通过脚本来实C互操作和动态显C。可以通过定义动画对象或用script 脚本来实现动甅R?/P>

    1. SVG 下几U常见的几何变换方式

    1.1 一?SVG 例子
    我们首先来看一?SVG 的例子,H口右上角有四个色块Q每个色块是一?0×50的矩形?/P>

    ?1. 一?SVG 的样?/B>
    ?1. 一?SVG 的样? src=

    ?2. h文档
    
    <?xml version="1.0"?>
    <svg >
        <g> 
    	<rect x="0" y="0" width="50" height="50" style="fill:red" />
    	<rect x="50" y="0" width="50" height="50" style="fill:yellow" />
    	<rect x="0" y="50" width="50" height="50" style="fill:green" />
    	<rect x="50" y="50" width="50" height="50" style="fill:black" />
        </g>
    </svg>
    

    1.2 使用 Adobe SVG Viewer 展示?SVG 文档中实现的几何变换
    ~放<g transform="scale(2)">

    ?3. 攑֤一?/B>
    ?3. 攑֤一? src=

    q移<g transform="translate(200 ,200)">

    ?4. q移200Q?00个像?/B>
    ?4. q移200Q?00个像? src=

    旋{<g transform="rotate(45)">

    ?5. 时针旋?5?/B>
    ?5. 时针旋?5? src=

    横切<g transform="skewX(45)">

    ?6. ?y 轴ؓ基线?X 方向横切45?/B>
    ?6. ?y 轴ؓ基线?X 方向横切45? src=

    2. ?Batik 下实?SVG 的几何变?/SPAN>

    2.1 Batik 的基知识
    2.1.1 Batik 的用?/B>

    Batik 是基?java 语言实现的一?SVG 应用的工具集Q用于实现对 SVG 对象的显C、编辑以及将 SVG 囑Ş对象转换成其他图片格式,?jpg、gif {?/P>

    q个目的目标就是给开发h员一套用于处理或应用 SVG 对象的基核心模型。作为Apache 目成员之一Q该目也ؓ开发h员提供了一个开发的可扩展的q_。同?batik 也维护了一个可以查?SVG 文g的浏览器。虽?batik q没有完全实?SVG 的所有标准语法和标记Q但通过比较不同版本的区别就会发玎ͼ他正在以很高的效率覆?SVG 所有的标准?/P>

    2.1.2 让我们实C个简单的 Batik E序

    首先让我们实C个简单的Z Batik ?SVG 览器。Batik 装了org.apache.batik.swing.JSVGCanvas 对象可以用于?swing 中嵌?SVG 昄容器Qƈ可以通过 org.apache.batik.swing.JSVGCanvas 提供的方法对 SVG 文档和图像进行操作。这个浏览器可以支持大部?SVG 的语法和标准包括脚本交互的功能,但暂时还没有引入动画。关于动d脚本交互的内Ҏ们会在以后的文章中讲qͼ今天先集中解军_何变换的问题?/P>

    ?7. q行E序打开我们~写?SVG 的例?/B>
    ?7. q行E序打开我们~写?SVG 的例? src=

    可以通过该页面引D行该E序Q?
    从附件中可以查看该程序的完整代码Q也可通过 |上下蝲地址 q行该程序?

    ?8. 一?SVGCanvas d到界?/B>
    
    private javax.swing.JPanel SVGPanel = new javax.swing.JPanel();
    private JSVGCanvas svgCanvas = new org.apache.batik.swing.JSVGCanvas();
    SVGPanel.add("Center", svgCanvas);
    

    2.2 通过 Batik ?GVT 模型实现 SVG 的几何变?/SPAN>
    2.2.1 Z么要使用 Batik 来实?SVG 的几何变?/B>

    当我们用 Batik 工具集作?SVG 客户端的解决ҎӞ如羃攑^U这L操作在所隑օ了。但 Batik q没有直接支持如 Adobe SVG Viewer 那样的鼠标拖动几何变换的操作Q这p求我们对q些功能q行~程处理?/P>

    在分?SVG 的几何变换的l节之前Q先让我们了解一下基本的操作~程方式?/P>

    2.2.2 Batik 下通过 java.awt.geom.AffineTransform 来实?SVG 的几何变?/B>

    JSVGCanvas 提供Ҏ可以获取 java.awt.geom.AffineTransform 对象。AffineTransform 是用于实?D 几何囑Ş坐标变换处理的对象,可以通过该对象进行二l几何空间中两个坐标pȝ怺映射和变换?/P>

    q移:


    
    //向左和向下^U?0个像?
    java.awt.geom.AffineTransform  rat = svgCanvas.getRenderingTransform();
    rat.translate(50,50);
    svgCanvas.setRenderingTransform(rat);
    

    ~放:


    
    //以屏q左上角原点为固定点q行~放操作
    java.awt.geom.AffineTransform  rat = svgCanvas.getRenderingTransform();
    rat.scale(0.5,0.5);
    svgCanvas.setRenderingTransform(rat);
    

    旋{:


    
    //以屏q左上角原点为固定点q行旋{~放
    java.awt.geom.AffineTransform  rat = svgCanvas.getRenderingTransform();
    rat.rotate(3.1415926/4);
    svgCanvas.setRenderingTransform(rat);
    

    复合变换:


    
    //一个综合^UR放大和旋{90度的复合变换
    java.awt.geom.AffineTransform  rat = svgCanvas.getRenderingTransform();
    rat.translate(50Q?0);
    rat.scale(2Q?);
    rat.rotate(3.1415926/4);
    svgCanvas.setRenderingTransform(rat);
    

    3. 当我们需要进行复合几何变换的时?/SPAN>

    3.1 先来让我们通过不同的变换代码组合实现复合几何变?/SPAN>
    先让我们看第一个例?

    //攑֤一倍和q移50个像素的复合变换
    
    AffineTransform rat = svgCanvas.getRenderingTransform();
    
            rat.scale(2,2);
    rat.translate(50,50);
    svgCanvas.setRenderingTransform(rat);
    
          

    ?9. 复合变换一
    ?9. 复合变换一

    可以看得出来Q这个变换的最l效果是Q图形的形状攑֤一倍,原图形的Q?Q?Q原点坐标^U?00个像素?/P>

    再来看第二个例子:


    
    //攑֤一倍和q移50个像素的复合变换
    AffineTransform rat = svgCanvas.getRenderingTransform();
    
            rat.translate(50,50);
    rat.scale(2,2);
    svgCanvas.setRenderingTransform(rat);
    
          

    ?10. 复合变换?/B>
    ?10. 复合变换? src=

    q个变换的最l效果是Q图形的形状攑֤一倍,原图形的Q?Q?Q原点坐标^U?0个像素?/P>

    3.2 关键是顺?/SPAN>
    比较一下这两种q移后的效果会发?只是因ؓ~放和^Uȝ序不同Q变换后的结果就发生了区别。第一个例子实际^Uȝ不是50个像?而是100个像素。而第二个例子则是q移?0个像素?/P>

    有兴的读者可以添加其他几何变换方式,q测试不同的变换序Q会发现复合变换的顺序与复合变换的最l效果是紧密相关的。那么如何分析和计算复合变换的变换结果呢Q这里我们需要补充一Ҏ学知识了?/P>

    3.3 对单一的几何变换进行数学模型分?/SPAN>
    对计机囑Ş学中囑Ş变换相关理论很熟悉的人可以蟩q这部分直接?Batik 的实现方式。这节用的齐次式图片引用自 SVG标准中关于坐标变换的齐次式的例子插图?

    首先我们来了解一下图形变换的齐次式计方法:

    ?11. 基本几何 变换齐次?/B>
    ?11. 基本几何 变换齐次? src=

    q是一个基本图形变换齐ơ式。等式的最双是一个坐标点未变换前的坐标矩阵,最左边是该坐标点变换后所在位|的一个三行一列的坐标矩阵Q中间那个三行三列的矩阵是变换矩阵。不同的变换方式对应不同的变换矩阵Q图形^UL果就是通过q样一个变换齐ơ式来实现的?/P>

    q移:如果需要将囑Şq移QtxQtyQ个坐标Ӟ采用如下的变换矩阵带入变换方E?/P>

    ?12. q移变换矩阵
    ?12. q移变换矩阵

    ~放Q如果需要在 x 轴方向实?sx 倍羃放,?y 轴方向实?sy 轴羃放时Q采用如下的变换矩阵带入变换方程?/P>

    ?13. ~放变换矩阵
    ?13. ~放变换矩阵

    旋{:如果需要将囑փ旋{ a 度时Q用如下的变换矩阵带入变换方程?/P>

    ?14. 旋{变换矩阵
    ?14. 旋{变换矩阵

    3.4 采用复合几何变换的数学模型分?/SPAN>
    3.4.1 数学分析

    当两l变换同时作用于同一个图像时Q连l用该{式Q得出如下等式。由于做变换的时候是变换矩阉|在矩늧的左边,所以对于复合变换的式子Q应该从叛_左进行读。对于如下的式子Q从双左依ơ是变换前的坐标Q第一ơ{换的转换矩阵Q第二次转换的{换矩阵,转换后的坐标倹{?/P>

    ?15. q行两次变换的复合矩?/B>
    ?15. q行两次变换的复合矩? src=

    q一步推?n ơ几何变换的复合变换{式Q?/P>

    ?16. nơ变换的复合矩阵
    ?16. nơ变换的复合矩阵

    3.4.2 来实践一?/B>

    ?17. 变换前效?/B>
    ?17. 变换前效? src=

    使用q样一个复合变换方式:

    <g transform="translate(50,90) rotate(-45) translate(130,160)">

    Ҏ前面的分析结果带入变换方E,得出如下{式

    ?18. 推导矩阵
    ?18. 推导矩阵

    Ҏ计算后的变换矩阵Q可得变换结果是囑Ş整体q移刎ͼ255.03,111.21Q,同时囑Ş自n沉K旉方向旋{45度。查看实际变换结果,q里我们可以发现Q对?SVG 的变换来_虽然我们习惯上从左往叛_变换参数的,实际上图形做变换的时候是从右边的变换参数开始依ơ进行图形变换的?/P>

    ?19. 变换后效?/B>
    ?19. 变换后效? src=

    3.5 分析一?Batik 是如何实?SVG 的复合几何变换的
    3.5.1 先看W一个例子:

    q个变换是先攑֤后^Uȝ变换Q其变换效果最l是Q先图形的形状攑֤一倍,然后图形整个^U?00个像素。这里我们可以看出,虽然我们是先q行的放大变换,后进行的q移操作Q但当我们进行复合变换的时候由于实际运时上是先进行了q移Q后q行了羃放。或者简单的理解Z左向叛_写羃攄阵,再写q移矩阵Q这样得出的变换矩阵可以对变换后的效果q行计算了?/P>
    
    //攑֤一倍和q移50个像素的复合变换
    //<g transform=" scale(2 ) translate(50 50)">
    AffineTransform rat = svgCanvas.getRenderingTransform();
    
            rat.scale(2,2);
    rat.translate(50,50);
    svgCanvas.setRenderingTransform(rat);
    
          

    我们可以这个变换对应的计算矩阵写出来:

    ?20. 复合变换例一的变换矩?/B>
    ?20. 复合变换例一的变换矩? src=

    Ҏ上面的分析我们可以看的出Q先q行~放变换在进行^Ud换的复合变换Ӟ变换后原囑օ的坐标会映射到新的位|,其中Q?/P>

    X1=Sx(X+dx)
    Y1=Sy(Y+dy)

    3.5.2 再来看第二个例子Q?/B>

    q个变换是先攑֤后^Uȝ变换Q其变换效果最l是Q先图形整个^U?0个像素,然后图形的形状攑֤一倍?/P>
    
    //攑֤一倍和q移50个像素的复合变换
    //<g transform="translate(50Q?0) scale(2 )">
    AffineTransform rat = svgCanvas.getRenderingTransform();
    
            rat.translate(50,50);
    rat.scale(2,2);
    svgCanvas.setRenderingTransform(rat);
    
          

    我们可以这个变换对应的 svg 文档实现写出来:

    <g transform="translate(50 50) scale(2 )">

    ?21. 复合变换例二的变换矩?/B>
    ?21. 复合变换例二的变换矩? src=

    Ҏ上面的分析我们可以看的出Q先q行q移变换再进行羃攑֏换的复合变换Ӟ变换后原囑օ的坐标会映射到新的位|,其中Q?/P>

    X1=Sx*X+dx
    Y1=Sy*Y+dy

    3.5.3 实用q两个例子的成果

    假设我们需要将囑Ş原点的位|移动到Q?50Q?00Q,同时形状攑֤到原来的3倍,该如何进行变换来实现q样的效果呢Q?/P>

    ?22. 变换效果
    ?22. 变换效果

    使用W一个例子的分析l果Q先q行~放变换Q再q行q移变换的方E变换:

    ?23. 方程推演
    ?23. 方程推演

    Ҏ推导可知需先进?倍的~放变换Q再q移Q?0Q?00Q个坐标可以实现指定的变换效果。实现程序如?/P>
    
    //<g transform=" scale(3 ) translate(50Q?00)">
    AffineTransform rat = svgCanvas.getRenderingTransform();
    
            rat.scale(3,3);
    rat.translate(50,100);
    svgCanvas.setRenderingTransform(rat);
    
          

    若先q行q移变换Q再q行~放变换的话Q根据第二个例子的推导结果:

    ?24. 方程推演
    ?24. 方程推演

    可知应先q行Q?50Q?00Q的q移操作Q再实现3倍的~放操作。实现程序如下:


    
    //<g transform=" translate(150Q?00) scale(3 )">
    AffineTransform rat = svgCanvas.getRenderingTransform();
    
            rat.translate(150,300);
    rat.scale(3,3);
    svgCanvas.setRenderingTransform(rat);
    
          

    4. 一个常用复合变换实例的实现--定点变换
    上边我们分析?Batik 实现 SVG 囑Ş变换的原理和计算Ҏ。下面我们用分析的结果实C个常用的变换实例Q定点变换。变换的U类包括~放Q旋转(一般不考虑定点q移q个概念Q?/P>

    所谓定点变换就是在囑Ş变换中指定一个固定的点,在变换结束后Q该点的位置不发生变化。定点变换在 GIS 的实际运用中很常见,比如地图放大到指定倍数而保持地囄某个位置Q如Q鼠标点ȝ位置Q不发生变化。我们以定点~放Z描述定点变换的用方法?/P>

    假设我们?x1,y1)Ҏ做定点变换的基准点进行几何变换,要求实现变换后(x1,y1Q的位置不变?/P>

    定点变换的基本思想是基于这样一个特性:当图像进行羃放,或旋转变换的时候,坐标原点的位|ƈ不发生变化。定点变换的实现Ҏ是Q先基准点Qx1,y1Q^Ud原点卛_一ơ[-x1,-y1]变换Q进行变换后再将变换后的原点q移刎ͼx1,y1Q即再进行一ơ[x1,y1]变换?/P>

    ?25. ZQx1,y1Q定点变?/B>
    ?25. ZQx1,y1Q定点变? src=

    实际~程的时候,我们无需对定点变换做如此复杂的运。例如可以采用如下的方式实现针对Q?0,50Q的定点变换Q?/P>
    
    //以(50Q?0Q点为基准点q行几何变换
    //<g transform="translate(50Q?0) …………?translate(-50Q?50)">
    AffineTransform rat = svgCanvas.getRenderingTransform();
    
            rat.translate(50Q?0);
    //其他变换方式
    ……………?
    ……………?
    ……………?
    rat.translate(-50,-50);
    svgCanvas.setRenderingTransform(rat);
    
          

    参考资?



    Pudgy's World 2005-08-20 08:55 发表评论
    ]]>log4j Tutorialshttp://www.tkk7.com/Pudgy/archive/2005/08/18/10449.htmlPudgy's WorldPudgy's WorldThu, 18 Aug 2005 08:58:00 GMThttp://www.tkk7.com/Pudgy/archive/2005/08/18/10449.htmlhttp://www.tkk7.com/Pudgy/comments/10449.htmlhttp://www.tkk7.com/Pudgy/archive/2005/08/18/10449.html#Feedback1http://www.tkk7.com/Pudgy/comments/commentRss/10449.htmlhttp://www.tkk7.com/Pudgy/services/trackbacks/10449.html

    目录

    使用log4j大概涉及3个主要概?

    日志记录?Logger)是日志处理的核心lg。log4jh5U正常?Level)?日志记录?Logger)的可用?span class="strong">Level (不包括自定义U别 Level)Q?以下内容是摘自log4j API (http://jakarta.apache.org/log4j/docs/api/index.html):

    • static Level DEBUG

      DEBUG Level指出l粒度信息事件对调试应用E序是非常有帮助的?/p>

    • static Level INFO

      INFO level表明 消息在粗_度U别上突出强调应用程序的q行q程?

    • static Level WARN

      WARN level表明会出现潜在错误的情Ş?/p>

    • static Level ERROR

      ERROR level指出虽然发生错误事gQ但仍然不媄响系l的l箋q行?/p>

    • static Level FATAL

      FATAL level指出每个严重的错误事件将会导致应用程序的退出?/p>

    另外Q还有两个可用的特别的日志记录? (以下描述来自log4j API http://jakarta.apache.org/log4j/docs/api/index.html):

    • static Level ALL

      ALL Level是最低等U的Q用于打开所有日志记录?

    • static Level OFF

      OFF Level是最高等U的Q用于关闭所有日志记录?

    日志记录器(LoggerQ的行ؓ是分{的。如下表所C:

    日志记录器(LoggerQ将只输出那些别高于或{于它的U别的信息。如果没有设|日志记录器QLoggerQ的U别Q那么它会l承最q的先的别。因此,如果在包com.foo.bar中创Z个日志记录器QLoggerQƈ且没有设|别,那它会l承在包com.foo中创建的日志记录器(LoggerQ的U别。如果在com.foo中没有创建日志记录器QLoggerQ的?那么?span class="strong">com.foo.bar中创建的日志记录器(LoggerQ将l承root 日志记录器(LoggerQ的U别Qroot日志记录器(LoggerQ经常被实例化而可用,它的U别?span class="strong">DEBUG?

    有很多方法可以创Z个日志记录器QLoggerQ,下面Ҏ可以取回root日志记录?

    Logger logger = Logger.getRootLogger();

    q可以这样创Z个新的日志记录器:

    Logger logger = Logger.getLogger("MyLogger");

    比较常用的用法,是Ҏcd实例化一个静态的全局日志记录?

    static Logger logger = Logger.getLogger(test.class);

    所有这些创建的?logger"的日志记录器都可以用下面Ҏ讄U别:

    logger.setLevel((Level)Level.WARN);

    可以使用7个别中的Q何一? Level.DEBUG, Level.INFO, Level.WARN, Level.ERROR, Level.FATAL, Level.ALL and Level.OFF.

    Appender 控制日志怎样输出。下面列Z些可用的Appender(log4j API中所描述?http://jakarta.apache.org/log4j/docs/api/index.html):

    1. ConsoleAppender:使用用户指定的布局(layout) 输出日志事g到System.out或?System.err。默认的目标是System.out?

    2. DailyRollingFileAppender 扩展FileAppenderQ因此多个日志文件可以以一个用户选定的频率进行@环日志记录?

    3. FileAppender 把日志事件写入一个文?

    4. RollingFileAppender 扩展FileAppender备䆾定w辑ֈ一定大的日志文g?/p>

    5. WriterAppenderҎ用户的选择把日志事件写入到Writer或者OutputStream?

    6. SMTPAppender 当特定的日志事g发生Ӟ一般是指发生错误或者重大错误时Q发送一邮件?

    7. SocketAppender l远E日志服务器Q通常是网l套接字节点Q发送日志事ӞLoggingEventQ对象?/p>

    8. SocketHubAppender l远E日志服务器组Q通常是网l套接字节点Q发送日志事ӞLoggingEventQ对象?/p>

    9. SyslogAppenderl远E异步日志记录的后台_E序(daemon)发送消息?

    10. TelnetAppender 一个专用于向只ȝl套接字发送消息的log4j appender?

    q可以实?Appender 接口Q创Z自己的方式进行日志输出的Appender?

    q里是一个非常简单的例子Q程序实CSimpleLayout和FileAppender:

    import org.apache.log4j.Level;
    import org.apache.log4j.Logger;
    import org.apache.log4j.SimpleLayout;
    import org.apache.log4j.FileAppender;
    public class simpandfile {
    static Logger logger = Logger.getLogger(simpandfile.class);
    public static void main(String args[]) {
    SimpleLayout layout = new SimpleLayout();
    FileAppender appender = null;
    try {
    appender = new FileAppender(layout,"output1.txt",false);
    } catch(Exception e) {}
    logger.addAppender(appender);
    logger.setLevel((Level) Level.DEBUG);
    logger.debug("Here is some DEBUG");
    logger.info("Here is some INFO");
    logger.warn("Here is some WARN");
    logger.error("Here is some ERROR");
    logger.fatal("Here is some FATAL");
    }
    }

    你可以下? simpandfile.java?q可以查看它的输出: output1.txt.

    q里是一个非常简单的例子Q程序实C HTMLLayout和WriterAppender:

    import java.io.*;
    import org.apache.log4j.Level;
    import org.apache.log4j.Logger;
    import org.apache.log4j.HTMLLayout;
    import org.apache.log4j.WriterAppender;
    public class htmlandwrite {
    static Logger logger = Logger.getLogger(htmlandwrite.class);
    public static void main(String args[]) {
    HTMLLayout layout = new HTMLLayout();
    WriterAppender appender = null;
    try {
    FileOutputStream output = new FileOutputStream("output2.html");
    appender = new WriterAppender(layout,output);
    } catch(Exception e) {}
    logger.addAppender(appender);
    logger.setLevel((Level) Level.DEBUG);
    logger.debug("Here is some DEBUG");
    logger.info("Here is some INFO");
    logger.warn("Here is some WARN");
    logger.error("Here is some ERROR");
    logger.fatal("Here is some FATAL");
    }
    }

    你可以下? simpandfile.java. q可以查看它的输出:output1.txt.

    q里是一个非常简单的例子Q程序实CPatternLayout和ConsoleAppender:

    import org.apache.log4j.Level;
    import org.apache.log4j.Logger;
    import org.apache.log4j.PatternLayout;
    import org.apache.log4j.ConsoleAppender;
    public class consandpatt {
    static Logger logger = Logger.getLogger(consandpatt.class);
    public static void main(String args[]) {
    // Note, %n is newline
    String pattern = "Milliseconds since program start: %r %n";
    pattern += "Classname of caller: %C %n";
    pattern += "Date in ISO8601 format: %d{ISO8601} %n";
    pattern += "Location of log event: %l %n";
    pattern += "Message: %m %n %n";

    PatternLayout layout = new PatternLayout(pattern);
    ConsoleAppender appender = new ConsoleAppender(layout);
    logger.addAppender(appender);
    logger.setLevel((Level) Level.DEBUG);
    logger.debug("Here is some DEBUG");
    logger.info("Here is some INFO");
    logger.warn("Here is some WARN");
    logger.error("Here is some ERROR");
    logger.fatal("Here is some FATAL");
    }
    }

    你可以下?simpandfile.java. q可以查看它的输出: output2.txt.

    Log4jl常与外部日志文件联合用,q样很多可选项不必编码在软g中。用外部配|文件的优点是修改可选项不需要重新编译程序。唯一的缺点就是,׃用到io 指oQ速度E微有些减慢?

    有两个方法可以用来指定外部配|文Ӟ文本文g或者XML文g。既然现在所有事情都写成XML文gQ那么该教程重点讲解XML文gҎQ但是也包含相关文本文g的例子。首先,看看下面的XML配置文gCZQ?/a>

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
    <log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">

    <appender name="ConsoleAppender" class="org.apache.log4j.ConsoleAppender">
    <layout class="org.apache.log4j.SimpleLayout"/>
    </appender>
    <root>
    <priority value ="debug" />
    <appender-ref ref="ConsoleAppender"/>
    </root>
    </log4j:configuration>

    文g以标准的XML声明作ؓ开始,后面跟着指出DTDQ文档类型定义)的DOCTYPE声明Q它定义了XML文g的结构,例如Q什么元素可以嵌入在其他元素中等{。上面文件在log4j发行版的src/java/org/apache/log4j/xml目录中?接着看看装所有元素的 log4j:configuration 元素Q它在DOCTYPE声明中被指定为根元素。嵌入在根元素中有两个结构:

      <appender name="ConsoleAppender" class="org.apache.log4j.ConsoleAppender">
    <layout class="org.apache.log4j.SimpleLayout"/>
    </appender>

    q里创徏一个名?ConsoleAppender"?AppenderQ注意,你可以选择M名字Q该CZ之所以选择"ConsoleAppender"Q完全是ZCZ的设计。接着q个appendercM全名形式l出Q经常用规范Qfully qualifiedQ类名?Appender必须h一个指定的 name?span class="emphasis">class。嵌入在 Appender之内的是 layout元素Q这里它被指定ؓSimpleLayout?Layout 必须h一?class属性?

      <root>
    <priority value ="debug" />
    <appender-ref ref="ConsoleAppender"/>
    </root>

    root元素必须存在且不能被子类化。示例中的优先被设|ؓ"debug"Q设|appender饱含一?span class="emphasis">appender-ref元素。还有更多的属性或元素可以指定。查看log4j发行版中的src/java/org/apache/log4j/xml/log4j.dtd以了解关于XML配置文gl构的更多信息。可以用下面q种Ҏ把配|信息文件读入到JavaE序?

    DOMConfigurator.configure("configurationfile.xml");

    DOMConfigurator 用一DOM树来初始化log4j环境。这里是CZ中的XML配置文gQ?/a>plainlog4jconfig.xml。这里是执行该配|文件的E序: files/externalxmltest.java:

    import org.apache.log4j.Logger;
    import org.apache.log4j.xml.DOMConfigurator;
    public class externalxmltest {
    static Logger logger = Logger.getLogger(filetest.class);
    public static void main(String args[]) {
    DOMConfigurator.configure("xmllog4jconfig.xml");
    logger.debug("Here is some DEBUG");
    logger.info("Here is some INFO");
    logger.warn("Here is some WARN");
    logger.error("Here is some ERROR");
    logger.fatal("Here is some FATAL");
    }
    }

    q里是一个实现带?span class="emphasis">PatternLayout?span class="emphasis">FileAppender的日志记录器Logger的XML配置文g:

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
    <log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">

    <appender name="appender" class="org.apache.log4j.FileAppender">
    <param name="File" value="Indentify-Log.txt"/>
    <param name="Append" value="false"/>
    <layout class="org.apache.log4j.PatternLayout">
    <param name="ConversionPattern" value="%d [%t] %p - %m%n"/>
    </layout>
    </appender>
    <root>
    <priority value ="debug"/>
    <appender-ref ref="appender"/>
    </root>
    </log4j:configuration>

    你可以从q里下蝲CZ: xmllog4jconfig2.xml?惌得到更多的用XML文g配置log4j环境的例子,h看log4j发行版的目录src/java/org/apache/log4j/xml/examples/ ?

    q就是上面讨论的文本文g形式的配|文?

    # initialise root logger with level DEBUG and call it BLAH
    log4j.rootLogger=DEBUG, BLAH
    # add a ConsoleAppender to the logger BLAH
    log4j.appender.BLAH=org.apache.log4j.ConsoleAppender
    # set set that layout to be SimpleLayout
    log4j.appender.BLAH.layout=org.apache.log4j.SimpleLayout

    从这里可以下? plainlog4jconfig.txt。这是执行该配|文件的E序:

    import org.apache.log4j.Logger;
    import org.apache.log4j.PropertyConfigurator;
    public class externalplaintest {
    static Logger logger = Logger.getLogger(externalplaintest.class);
    public static void main(String args[]) {
    PropertyConfigurator.configure("plainlog4jconfig.xml");
    logger.debug("Here is some DEBUG");
    logger.info("Here is some INFO");
    logger.warn("Here is some WARN");
    logger.error("Here is some ERROR");
    logger.fatal("Here is some FATAL");
    }
    }

    你可以下载用该配置文g的示例: externalplaintest.java。想要获得更多的使用文本文g配置log4j环境的例子,h看log4j发行版中的目录examples?

    使用外部配置文g的例子就单的讨论到这里,现在应该可以肯定你已l有能力独立学习更多的log4j发行版和试版中提供的例子?/p>



    Pudgy's World 2005-08-18 16:58 发表评论
    ]]>
    E序员心?http://www.tkk7.com/Pudgy/archive/2005/08/16/10219.htmlPudgy's WorldPudgy's WorldTue, 16 Aug 2005 04:58:00 GMThttp://www.tkk7.com/Pudgy/archive/2005/08/16/10219.htmlhttp://www.tkk7.com/Pudgy/comments/10219.htmlhttp://www.tkk7.com/Pudgy/archive/2005/08/16/10219.html#Feedback2http://www.tkk7.com/Pudgy/comments/commentRss/10219.htmlhttp://www.tkk7.com/Pudgy/services/trackbacks/10219.html    q些日子我一直在写一个实时操作系l内核,已有成了,{写完我会全部公开Q希望能够ؓ国内IT的发展尽自己一份微薄的力量。最q看到很多学生朋友和我当q一h有方?Q所以把我的l历写出来与大家共勉Q希望能l刚如行的朋友们一点点帮助?一转眼我在IT行业学习工作已经七年多了Q这期间我做q网,写过MIS、数据库Q应用程序,做过通信软g、硬仉动、协议栈Q到现在做操作系l内核和IC相关开发,q中间走了很多弯路,也吃了不苦?BR>    我上的是一个三的高校Q就q同一个城市的人多数都不知道。因为学校不好也没有指望能靠学校名气找一个好工作。所有的希望都寄托在自己的努力上了,大一开学前的假期我开始了学习Q记得我买的W一本书是《计机基础DOS3.0》,大家别吓着了,其实当时已经普及了DOS6.22了,只是我在书店里看CDOS4.0Q?.0Q?.0的书Q以为像p那样是第四、五、六册,记得当时到处找DOS1.0Q现?x也幸好我没有扑ֈQ)开学前我学完了PASCALQ那时既没有计算Z没有人可以请教,我连E序是什么的概念都没有, 只好死记背代码Q然后拿U写Q我一直到大三才有了一?86Q在q之前用U写了多程序我也记不清楚了Q只知道最长的一个我拿A4大小的草E纸写了30多页Q我的C语言、C++ 、VC都是在这L条g下入门的。所以说条g是可以克服的Q希望我的经历多给条g艰苦的同学们一点信心。第一ơ上机是在我姐夫的机房,我的心情Ȁ动的无与伦比Q但是一上机我立d了眼Q他们用的是英文版的Win3.1Q我的那点DOS知识都见了鬼Q上机提心吊胆的一늞摸,一不小心把Word弄成了全屏,怎么都还不了原,当时真是心急如焚,我以为机器被我弄坏了。第一个C语言E序Q就是那个经典的HelloWorldQ我调了几个星期Q上机机会非常少Q也没有书告诉我开发环境(TC2.0Q需要设|,而且开始我都不知道有编译器Q我甚至自作聪明把写好的E序扩展名从.cҎ.exeQ结果可惌知。大一学完了C、X86的汇~、数据结构、C++。由于精力都花在自学上了Q大一下四门课挂了彩,三类学校是q点好,挂上一二十门也照样毕业。不q扯q点_我那么刻苦都及不了格Q可见我们国家的计算机教育有多死ѝ?
      大二准备学VC和BCQ当旉以取舍,后来选了VCQ不为别的,只ؓ书店里两本书QVC 那本便宜6块钱。我的努力在班上无h能及Q学的日夜不分,大三有了计算机后更是如此Q?很多ơ父亲半夜教训我说我不要命了Q我一直觉得自己基差,记忆又不行,条g也不?Q所以觉得只有多q旉才能赶上别h。居然后来有许多朋友说我有学计算机的天赋Q?让我哭笑不得。我用的?86Q?6M内存Q?G盘Q当时同学们的配|都是P166MMXQ我安装 一个Windows NT4.0需要一个通宵Q编译一个BC5.0向导生成的程序需要近两个时Q我的显C器是个二手的,辐射非常大,开机屏q冒火花Q看h很酷的:Q,有一ơ程序写的太久,觉得怎么白色的编辑器背景变成了Ԍ以ؓ昄器坏了,后来才发现眼睛不行了Q不q说来也奇怪,C天我的视力还能保?.5Q真是个奇迹。但是就是那台破机器陪伴了我两年Q让我学会了VC、Delphi、SQLServer{。后来那台机器给我阿姨打字用Q据她说一天她正打的开心,一股青烟夹着火苗从显C器d来,之后它才寿终正寝?
      大三假期找了个机会在一个计机研究所实习Q与其说实习不如说是做义工,工作了两个月一分钱没有ѝ但是这两个月对我的发展帮助很大Q让我早一步了解了C会Q刚ȝ时候我当然是一H不通,在那里我熟悉了网l,学会了Delphi和Oracle。由于工作很认真Q?得到了比较好的评P在一位长者的引荐下,我开始和他们一起做目Q这使我在大三大四就有了自己的收入,大四又找了两家MIS公司DQ虽焉不多Q但是在学生期间?000多的收入我已l非常满了Q我l于用自p的钱把计机换了。大四下开始找工作Q这时我的工作经验已l比较多Q当然现在想想非常幼E)Q开始听父母的想去那个研I所Q?实习q那个部门也希望我能去,但是不知道ؓ什么最后不了了之,q种单位是比较官僚 Q我一气之下就C我兼职的一个公司做MIS的TeamLeader。在大三到毕业一q的旉Q做q了各种MISQ从煤气、烟厂、公安、铁路、饮食到高校Q什么有钱做什么,工作也很辛苦 Q经常加班和熬通宵Q从跟客戯需求到设计、编码、测试、交付都要上。那时觉得很有成感Q觉得自p不错Q现在想想真是很肤浅?BR>  刚走上工作岗位的学生很容易被误导Q各U开发工兯人眼q݋乱,同时也觉得很受公司器重,但这样工作永q是一个低层次的开发者。不要跟我说什么系l分析有多么多么重要Q多么多么难。你以ؓ自己跟用戯需求做设计是pȝ分析和设计了吗,国内又有几个公司能够做的很到位很规范Q我是ISO9000内审员,也在Rational公司受过多次培训Q拿?个证书,q有一个公司让我去做CMM。这些我听过很多Q但是很多事情到国内变了性质Q一个公怸是通过了ISO9000或者CMMp规范了,我现在在一家有几十q历史的外企工作Q里面的理不是一般国内企业能及的。作Z个毕业不久以前没有步入过C会的学生,几乎不可能在很短的时间掌握系l分析和设计Q面向对象、UML只是一个工P关键是h本n的思想Q不是说你熟悉了C++、Rosep够做出好的设计,相反如果你具备了很高的素质,你可以用C写出比别人用C++更加模块化的E序?
      话说q一些,国内软g开发行业有一个怪圈Q很多h觉得VC > Delphi > VBQ真是很搞笑。这几个软g我都做过开发,说白了他们都是工P应该Ҏ应用的需要选择采用哪个Q而不是觉得哪个上层次。如果你因ؓ用某个开发工具很有面子而选择的话Q只能说明你很浅薄。如果说层次Q那么这些工具都不上层次Q因为它们用来用去都是一些系l的APIQ微软的朋友不会因ؓ你记住他们多个API或者多个cd会觉得你很了不vQ你永远只是他们的客P他们看重的是你口袋里的银子。我也做q系l内核,我也装q很多APIQ同h也不会看重那些用这些API做二ơ开发的客户Q除非他能够作出自己独到的设计?
      至于有h认ؓC++ > C那更是让人笑掉大牙,不妨你去打听一下,现在有几个操作系l内核是用C++写的Q又有几个实时系l用的是C++Q当然我也不是说C++不好Q但是目前的内核和实时系l中C++q无法与CҎQ至于说C++适合做应用系l的开发那是另外一回事。所以我的观Ҏ不在于你用什么工具和语言Q而在于你q什么工作。你的设计体C你的技术层ơ?BR>  q样q了一q我觉得非常苦闷Q做的大多数都是熟练工种的活Q个人技术上没有太多 的提高也看不到方向。所以决定离开q个城市MPL更好的发展,q且打算攑ּ我以前的MIS转到通信行业?
      写到q里不能不提到我x友,我们是在来上前半年认识的,她大四在我公司实习,公司z֥l我写文档,我们的感情发展的很快。她告诉我很多事情,她家原本是改革开攄W一Ҏ发户Q她母亲爱打牌,输掉了几百万Q还Ơ了很多债,Ҏh友,但是她对他没有感情,只因Zl了Ҏ亲两万多块钱Q后来还她写了四万块的借条Q她h友背叛过她ƈ且不止一ơ打她,现在逼她l婚不然p她还钱。这人居然还是一个高校的老师Q她母亲把父亲给她的学费׃Q因为拖Ơ学费她没有办法拿到毕业证。她母亲现在有病需要钱Q我拿出了自q一点积蓄ƈ且跟朋友们接了一些,替她交了学费q给Ҏ亲看 病(后来才知道看病的钱又不知所l,pҎ亲是不是有病我都不知道,但她也是没有办法Q。这个时候我家知道了一些事情,坚决反对我和她在一P她原来的h友也极力破坏。无奈之下我们决定早一定离开q个伤心的城市,q且瞒着我们家。由于时间仓促,我只准备?000块钱Q她仅有的几癑֝׃被她母亲要去了,我买了三张票Q一张是中午的,两张是晚上的Q中午我的家人把我送上船,他们一d我就下了船,我和她乘坐晚上的船离开了这个我和她生活了很多年的城市,带走的只是一w债务。没有来q上L我们两个性倔强Q都不愿意去ȝ同学和朋友。来Ch傍晚6点半Q我?都不知道该去哪里Q我们找了一?0块钱的旅馆,q个戉Kq窗户都没有Q?月䆾的天气酷热难耐,戉K里非帔R热。第二天我们开始租房子Q因n上的׃多,我们基本都是步行Q花了一个星期时_不知道在东转了多少圈后扑ֈ了一?00块的房子Q但是我们都不了解上h付三压一Q还要付半个月的中介费,C一些锅瓢盆后Q我们n上只?00块钱了,工作都还没有着落,q?00块钱要支持到我们拿到W一个月工资Qؓ了省钱我们自己做饭,每天买菜只花两块钱,奚w常喜Ƣ吃Q也可能她在大学l常挨饿的愿意)Q看到她现在q样省吃俭用我真的很不忍心。她以前的男朋友也没有放q她Q经常打电话来骚扎ͼq且来上L她,q说了不恐吓她的话Q她q于善良Q说他以前毕竟帮助过她,叫我不要与他一般见识。以后的每天在家是苦等面试通知Q原本我惌速找一家MIS公司解决眼前的困难,但是她坚持让我不要放弃自q理想Q终于功夫不负有心hQ我扑ֈ了一安信公司Q?000块的工资虽然赶不上MIS公司l我开出的价位Q但也够在上L存。她也找C工作Q第一天上班她哭了Q这是她来上L一ơ流泪,我心里很隑֏也很感动?BR>  ׃是全新的行业Q我把自己降C零点Q我学的VC、Delphi、数据库z不上用场, 摆在我面前的是嵌入式、协议、信令一些我从未接触q的知识。我知道我没有退路,于是拼命的学习,我把自己当做一个应届毕业生一P一分努力一分收P半年q去我终于熟悉了工作Qƈ且得C公司的表彎ͼ薪水也加了一U。后面的日子里我们省吃P用,把欠朋友?万多块钱q了Q日子终于上了正轨。这时女朋友告诉我她惌研I生Q我也很支持Q于是她辞职在家备考?BR>  另外Q在q里我要感谢我的ProjectManagerQ他原来是一个大通信公司的品经理, 对h非常和善Q我从他那里学到了很多知识,而且他也l了我许许多多无U的帮助。在工作上他l我充分的空间和信Q。记得公司安排我l护一个接入服务器软gQ由于代码量不算太小Q?万行Q,资料和文档都不齐全,我维护v来非常吃?Q所以想重新把它做一遍, 公司领导不太支持Q可能觉得工作量太大Q但是他极力支持我,U下里他让我放手dQ?我的l护工作他挤旉做。在他的支持下,我花了半q时间完成了接入服务器的软gQƈ且实C一个相对完整的TCP/IP协议栈。在q里我学会了嵌入式系l设计、驱动开发、TCP/IP和很多通信的知识,我花了一q时间终于自己从MIS开发{C通信行业Qƈ且站E了脚跟。我的开发大量是对硬件的直接操作Q不再受微Y的操作系l,VC、Delhpiq些开发工LU束Q我l于看到了另外一片天I?
      我做事情喜欢q根问底Q随着开发的深入QY件开发与g联系来紧密,g知识的匮乏又Ҏ的发展生了障碍Q而且芯片技术基本上掌握在国外公司的手里Q这对做pȝU设计是一个非常大的制U,一个新产品出来Q第一道利润(也往往是最丰厚的利润)常常都被IC公司如Intel、Motorola赚去了,国内的厂商只能喝Ҏ。所以我军_解决自己的硬件技术障,q打离开通信行业Q进入IC设计相关领域?
      当然我明白如果我对硬件了解的非常,没有哪家IC公司会仁慈到招我q样一个一H不通的人来培训。所以我必须努力打好基础Q学一些相关知识ؓ以后做准备。就像我开始从MIS转到通信一P我看q大量通信斚w的书Qƈ且给一个ISP做过RADIUS计费分拣収ͼ在这L背景下这安信公司才给了我q个Z。我在的通信公司是做pȝ设计的,有不PCB Layoutg人员Q^常我注意向他们学习Q由于我做的是YӞ在公司看g资料不好意思,所以开始只好在家看Q刚来上工作我q箋一q都在加班,后来不加了,因ؓ我要挤出旉学习Q通常?2点左右睡 Q第二天5点半P我上班比较早Q地铁上如果Z多我也用来看书。学习当然不会是一帆风的Q有些实在不懂的问题q累v来问g人员Q他们的帮助使我学习q度快了很多Q因为在没有人点拨的情况下自学,我的一半时间是花在解决疑难问题上,但这U问题经常是别h的一句话可以让我豁然开朗,我非常庆q我有这L学习环境。在后面的一q里Q我学会了看g原理图,学会了简单的g设计Q模拟电路方面还有不的差距Q,事情是q样的,当你安安份䆾做YӞ别h永远认ؓ你是软g开发h员,在你开始学习硬件时别h未必会认同,有位中兴通讯的朋友还Ҏ说过Q一个h不可能把所有东襉K学完。我也明白这一点,但我希望?己做的更好。但当你熟悉g后大家又会觉得你好像原本是软硬仉懂的Q同事们也都习以为常了。这个时候我可以把硬件资料堂堂正正的拿到公司看,没有人再大惊怪了?让我比较自豪的是我通过自己的努力做了一个IADQY交换的终端设备)pȝҎQ包含Yg的选型、设计等内容Q这个方案得C公司和同事们的认同,让我感到非常ƣ慰?
      技术是相辅相成的,当我的硬件有了一定的q步后,我的软g设计也有了很大的提高 Q我可以从更深层ơ理解问题,我做的接入服务器CPU是Motorola PowerPC860Q熟悉的朋友都知?60 QMC与Y件的扚w数据传输通常采用BD表的方式Q硬件h员做驱动的时候习惯采用固定BD表,每接收或发送数据都数据从BD表拷贝到用户BufferQ或从用户Buffer拯到BD表,׃理解的比较深入,我自己重新实C q个q程Q采用动态BD表的方式Q驱动从一个网口接收数据,提交l我的Y件进行三层交换,直至从另外的接口发送出去,没有q行一ơ拷贝。这L设计大大提高了性能Qɾpȝ的指标接q理论倹{Yg的结合我的设计水^上了一个台阶。我现在写的q个操作pȝQ编译后我把E序反编译成汇编Q找出其中不优化的代码,然后在CE序中进行调整。D个例子,很多CPU没有专门的乘法指令,q个大家应该都知道,在这UCPU上进行一个乘法操作常怼p大量的指令周期, 有的朋友会说q个我知道,我会量避免采用×P但是事情往往不是那么单,你知道C语言中数l的下标操作是怎么实现的吗Q仔l看看反汇编的代码你׃明白Q同h通过下标的定位操作,C~译器会有时候会产生位移指oQ但有时候会用乘法实玎ͼ两者效率往往是天壤之别,所以明白这些问题你才能系l性能提升到极致。这些问题就不多说了Q有兴趣的话以后可以共同探讨?BR>  话说q一点,我由L希望在Y件上做的比较深入的朋友们有机会学学硬件以及其它相关知识,其是做底层开发和嵌入式设计的。这对Y件技术的提高有非常大的帮助,否则很多事情你只知道该这样但不会明白Z么该q样。我q个观点在我现在的IC公司Project Manager那里也得C验证。他告诉我们公司现在?02.11芯片产品的Y件经理原本是做该芯片g设计的,某某某原本是做Y件的Q现在在做ICQ类似的例子q有很多Q只是在国内q样的风气不是非常流行?BR>  我有一些心得体会与大家分nQ只有当我干好本职工作后Q我才会学习与工作关pM大的技术,q样公司的上司才不至于反感,在入门阶D늚问题我通常不去问那些资׃h?Q而是问一些资历比较浅的朋友,比如刚毕业不久的学生Q因Z们往往会跟你详l的讲解Q而资׃h士通常觉得你的问题太简单,所以回{的也很单,我又不好意思多问。等技术上了一定的层次后我才会问他们,他们也能l你比较深入的回{。另外,有些朋友说我Z比较好,他们也希望能从事新的工作可惜没有ZQ我听了只有苦笑Q我的机会了解的人都应该知道Q我没有出生在什么IT世家Q)也没有谁一路提拔我Q所有的路都是自p出来的,我母亲去世比较早Q我的后母(我叫奚w姨)看着我努力过来的Q一ơ她看我大年30q在写程序,她说像我q样努力木头都能学出来?
      我的最l目的是IC而不是PCBQ所以我下一步的准备开始学习IC设计的知识。公司的同事没有懂IC设计的,后面的\又要靠自׃Q我C不少相关的书Q在|上也查了很多的资料Q我׃大量的时间去学习VHDLQƈ且用软gq行了一些简单的设计和仿真(没有设计ASICQ只是针对FPGAQ,随着学习的深入,我渐渐明白了IC设计的基本流E,同时也明白了q条路的艰辛。这个时候我已经做好了蟩槽的准备Q我向一家业界又一定知名度的IC设计公司投了历,q过了O长的面试Q?个多时Q。其他的一切我都比较满意,唯独薪资差强人意Q我也明白原因,因ؓ我是q个行业的新人,我没有经验,我再一ơ将自己清零了。公司老板问我6000多一个月能不能接受,我知道他也是照章办事。想x通信行业的朋友们Q基本上都是q薪10万以上,月薪q万的也比比皆是Q朋友们也帮我介l了不少待遇不错的公司,我该怎么选择Q当时我很犹豫,我热爱我的事业,我向往我的q求Q?但我也是一个普通的人,我也需要养家糊口,我也x一点买房买车。生zȝ我出了一道难题?
       爱因斯坦?3岁时说过“一个h没有?0岁以前达成科学上的最大成,那他永远都不会有。”这句话l了我很大的压力和震动,我马上就26岁了Q离30只有四年旉Q我必须抓紧q几q宝늚旉Q努力达到我技术上的最高峰。ؓ了这个理惻IZ能离自己的梦更近一些,我选择了这家IC公司Q我明白自己的薪资和公司刚进来的士研究生相差无几, 但ؓ了今后的发展只能忍受Q一切又得重新开始。换行业是一个非常痛苦的q程Q尤其从一个春风得意的位置换到一个陌生的岗位Q感觉象从温暖的被子里钻出来跌冰水中,让h难以接受。在原来那家通信公司Q我是唯一两年旉涨了五次工资的员工,公司和同事都l了我极大的认可Q工作上也常常被委以重Q。但现在q一切都成了q去Q在新的公司我只是一个新?没有人知道也没有人在意我q去的成l。我军_重新开始,我把自己看作新毕业的学生Q我要用自己的努力得到公司的认可。进入新的行业是非常痛苦的,我告诉自己必d受这一切,虽然外面有很多诱惑,但是既然作出了选择我就不允许自p易放??
      我现在已l在q家新公怸了一个多月的班,开始非常艰难,现在慢慢适应了。第一 个月l束ӞTeam Leader找我谈话Q说我是新进员工中最优秀的一个,我心里很ƣ慰Q这也算Ҏ努力的一个肯定吧。在q里q要感谢我的x友,她给了我很大的支持和鼓舞Q?每次在我动摇的时候她都在鼓励我,让我坚持自己的理惻I刚来上v是她让我不要勉强dMISQ这ơ也是她让我住了月薪过万的诱惑Q没有她我可能不会有今天的成l?现在的公司有自己的操作系l,自己的CPU、DSP和其它芯片,在这里我能学C界上最先进的技术,我们的设计开发不再完全依赖别人的g和系l,q让我很开心。我打算{工作步入正轨后Q全力学习新的知识,实现我的理想?

        在后面的两年里我l自己定下了几个目标Q?

    一.努力做好本职工作Q在工作上得到公司和同事们的认同Q?

    ?努力学习ICg设计知识Q多向同事请教,q利用一切机会多实践Q?

    ?实现我的实时操作pȝ的主要部分,完成TCP/IP协议栈模块,q免费发布源代码Q?

    ?和我x友结婚ƈC套小房子Q这是最重要的,因ؓ我明白事业是可以重来的,但是珍贵的感情很隑֤而复得?

    q里提一下我现在开发的操作pȝQ它是一个实时嵌入式pȝQ目前支持以下特性:

     a.支持旉片轮转调度和Z优先U调度,最?4个优先Q?

     b.抢占式实时内核;

     c.Z便于ULQ主体用标准C实现Q?

     d.汇编代码非常,不到100行;

     e.支持d理Q各d有独立的堆栈Q?

     f.q程同步和通信目前完成了SemaphoreQMessage Queue正在调试Q?

     g.实现了定时系l调用;

     h.可以在windows上仿真调?

        我还打算下一步实C先反{保护QEvent FlagQData PipeQ内存管理(以前实现q)、驱动接口等?在这之后我还会努力完善它Q比如加入文件系l,协议栈、调试接口等。希望朋友们提出自己的意见和Q在此不胜感ȀQ?

     后记Q?

      像有的朋友说的Q我的经历或怼l一些朋友生误|在这里我必须说明一下?我来上v以前学习q于拼命Q常常晚上只?个多时Q我w高1c?1Q那时只?08斤(我现?30多)Q家Z说我q样拼命zMq?0岁,但是当时的我太固执,我对他们说只要能实现理想z?0岁我够了。那时的拼命使我的n体受C影响Q有一ơ早上突然腰肌剧痛难忍,痛的我倒在床上站不h。虽然我现在已经比较注意Q但有时候还会隐隐作痛。后来在x友说服了我,来上以后我不再如此。我l常引用父亲的一句话“n体是革命的本钱”?BR>  而且我也发现拼命不是办法Q我可以熬一两个通宵Q最多的一ơ我q箋工作了三天三夜, 但是我半个月都没有恢复过来,q样是不是得不偿失?学习工作应该是一个长期的q程Q?像马拉松而不是百c_刺。我现在非常注意调整学习和工作的强度Q我要保证每天尽量有相对充沛的精力,一些年ȝ朋友觉得自己也应该拼命努力,q让我多有些担心,如果我的故事能让你在学习工作上多一点兴,我会感到很开心,但如果误g某些朋友Q让你做一些不值得的付出,我会感到很内疚?BR>   技术没有贵׃分,我以前换行业是因q兴趣所_而不是对哪个行业有什么偏见。我希望我的l历不要l朋友一个错误的导向Q觉得我始终向更高的技术发展。其实各行各业做到顶都是很困难的。话又说回来虽然技术没有贵贱,但是门槛是有高低的, 无论如何Q做IC的门槛要比做|页的高Q这一Ҏ可否认。国家各Uh才都是需要的Q但是作Z人奋发向上的xq是应该有的Q努力在自己喜欢的行业上做的更好Q而不应该停留在比较肤的层次上?BR>  我是一个自p得比较有自知之明的hQ或许我最大的优点是知道自己有很多缺?Q)。我的故事中很多的曲折和错误都是由我的缺炚w成的,希望大家用审慎的眼光看待我的l历Q不要被我的“花a巧语”所qh。我学习有些随心所Ԍq给我带来了无尽的麻烦,也大大阻的我的发展。记得我时候成l比较出Ԍ但是后来学习严重偏科Q导致我中学成W一再滑坡,也没有考上什么好的学校,时候的一个朋友,当时的成l和我相仿,但是没有我这个缺点,她上了清华,后来在去了美国深造,在一个著名导师手下研I理论科学,q未不是一条更好的\。另外我的学习方法也是在不断改善中的Q过ȝ学习q于讲究数量和时_那样学习既苦而已效率不高Q现在我非常注意学习的效率和技巧,q样才是学习的捷径(当然不是指投机取巧)Q比如说学一相对陌生的技术,如果有条Ӟ不妨问一问有l验的hQ不需要问很多Q往往他不l意的几句话会给你非常大的帮助,甚至过你看一个星期的书。带着q样的思想再去学习你会节省很多旉Q这样何乐不为呢Q这些年中我学了不少的东西,׃开始非常盲目,所以学的东西杂乱无章,现在回想h让我啼笑皆非Q我把大量的旉费在一些没有必要深入了解的知识上,毕竟一个h的精力是有限度的。很多朋友很我一样都背过五笔字ŞQ的它是个不错的输入法Q但是对一个研发h员它l对不值得你去背,你的旉应该花在有h值的地方。我q样的事情还做过很多Q我背过CCED、WPS的命令和快捷键,在dBase基本退出历史舞台后我还׃很多旉d习它的用。所以我的学习在前期~Z规划Q没有明的短期目的、中期目标,只有一个虚无飘渺的长期的理惟뀂这像做设计一P好的设计是从需求抽象到代码有很多过E,而不能得C需求就立刻开始开始编码?
       当然q么些年的学习和工作多多少有些收获Q下面我说说我的一些学习的心得Q这 些方法未必正,我也在不断探索和改进中。我的学习和工作有相Ҏ的目标Q我不会一时心动而去学习某一技术,在下军_之前我会考虑很多Q包括长期的发展Q个\U的规划Q需要付出的代h、可能遇到的困难及解决的办法{等Q在军_后还会制定更加明的计划Q包括短期、中期和长期的,w边可以利用到的资源Q包括好的书c、资料、Yg环境Q也包括有经验的朋友或者师长)Q以及每一个阶D|怎么q渡到高一阶段的计划,往往在一个学习阶D一旦上路后会走的相寚w利,但是跨阶D通常比较ȝQ比如从学习基础知识转到实践。另外我C也有自己的方法,现在世面上高质量的书q不如低质量书多Q对于一个陌生的技术,往往在第一ơ买书会选择错误Q即使买C本好书但是它的方向也未必适合你,所以我通常会先在网上查找一些该技术的介绍Q有了一点点概念后再M一本比较薄、相对便宜ƈ且内容相Ҏ泛而谈的书Q这是国内作者最善于写的书:Q?Q再把它览一遍后我就会基本明白这门技术的要点Q后面买书和制定计划׃明确的多。否则一开始就x本好书往往比较困难Q而且买回来后努力学习Q有时候学了一半才发现是本低质量的书或者是相对q时技术,让h非常懊恼。另外让有经验的人帮你介l,通常也是一个不错的选择?BR>  有些朋友惛_通信、嵌入式开发,但总觉得自己没有Yg环境Q我按我的了解l?大家介绍一下怎么建立q样的环境,当然我了解的只是我学习和工作的方向。通信我做的是数据|方面的工作Q包括TCP/IP、二三层交换、对接入|、H.323和Y交换也有一点认识。这些Yg环境都是可以在PC上构建的。你甚至可以在一个没有网卡的PC上徏立一个包含多个\由器、接入服务器、VoIP|关、网守、主机等的仿真网l环境,而且与实际的|络相当接近Q当然这需要你有清晰的|络概念和一定的|络知识Q我一直在努力开发一套Y件将q个q程化,目前试验已经做完Q我可能会将它融入我的操作系l外围扩展Y件中。这LҎ我无法用单的语句讲的很清楚,我可以说一下大概的思想Q就是在PC上实C真网卡,Q知道Windows怎么在没有网卡的机器实现虚拟|卡技术的朋友都应该会明白Q,然后每一个仿真网卡对应一个虚拟设备,如\由器或者主机。你也可以借助W三方工具完成部分工作,如VmWare{。我现在是利用一个仿真网卡做自己的开发的?BR>  至于嵌入式开发环境更加容易实玎ͼPC是一个非常大的硬件^収ͼ现有的嵌入式?作系l通常都支持X86Q你可以在上面做开发,通过软盘Boot或者用虚拟机装蝲Q我用VxWorks做了试验Q在一台PC上跑Windows和VxWorks两个pȝ。另外Windows上的兼容DOS?6位仿真X86环境也ؓ很多操作pȝ提供了绝佳的试验环境Q我的操作系l在Windows上就是这样实现的。Linux在嵌入式中应用也比较q泛Q它在网上有大量的资料,而且也相Ҏ较容易实c同时很多完善的嵌入式开发环境支持Y件仿真,如Tornado、WinCE{?



    Pudgy's World 2005-08-16 12:58 发表评论
    ]]>
    ImageIO 's IIOReadProgressListenerhttp://www.tkk7.com/Pudgy/archive/2005/08/16/10215.htmlPudgy's WorldPudgy's WorldTue, 16 Aug 2005 04:19:00 GMThttp://www.tkk7.com/Pudgy/archive/2005/08/16/10215.htmlhttp://www.tkk7.com/Pudgy/comments/10215.htmlhttp://www.tkk7.com/Pudgy/archive/2005/08/16/10215.html#Feedback0http://www.tkk7.com/Pudgy/comments/commentRss/10215.htmlhttp://www.tkk7.com/Pudgy/services/trackbacks/10215.htmlRecently, I am working on graphic project. This project I faced is a big challenge to me. Here is a sloution to show the progress bar when loading the image from the net.
    PS:
    If you install the JAI, it will break the progress interrupt.
    See this in Sun's Bug Database http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4842452


      1 import java.awt.BorderLayout;
      2 import java.awt.event.ActionEvent;
      3 import java.awt.event.ActionListener;
      4 import java.awt.image.BufferedImage;
      5 import java.io.IOException;
      6 import java.net.MalformedURLException;
      7 import java.net.URL;
      8 import java.util.Iterator;
      9 
     10 import javax.imageio.ImageIO;
     11 import javax.imageio.ImageReader;
     12 import javax.imageio.event.IIOReadProgressListener;
     13 import javax.imageio.stream.ImageInputStream;
     14 import javax.swing.*;
     15 
     16 public class IIOProgressTest
     17 {
     18     public static void main(String[] args)
     19     {
     20         try {
     21             UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
     22         } catch (Exception e) {
     23             e.printStackTrace();
     24         }
     25 
     26         final JLabel imageLabel = new JLabel();
     27         JScrollPane scrollPane = new JScrollPane(imageLabel);
     28         final JButton startBtn = new JButton("Load Image");
     29         final JProgressBar progressBar = new JProgressBar();
     30         progressBar.setVisible(false);
     31         JPanel p = new JPanel(new BorderLayout(55));
     32         p.add(startBtn, BorderLayout.WEST);
     33         p.add(progressBar, BorderLayout.CENTER);
     34         
     35         final IIOReadProgressListener progressListener = new IIOReadProgressListener() {
     36             public void imageStarted(ImageReader source, int imageIndex)
     37             {
     38                 SwingUtilities.invokeLater(new Runnable()
     39                 {
     40                     public void run()
     41                     {
     42                         startBtn.setEnabled(false);
     43                         progressBar.setValue(0);
     44                         progressBar.setVisible(true);
     45                         invalidate();
     46 
     47                     }
     48                 });
     49             }
     50             public void imageProgress(ImageReader source, final float percentageDone)
     51             {
     52                 SwingUtilities.invokeLater(new Runnable()
     53                 {
     54                     public void run()
     55                     {
     56                         System.out.println("percentageDone" + percentageDone);
     57                         progressBar.setValue((int) (percentageDone));
     58                     }
     59                 });
     60             }
     61             public void imageComplete(ImageReader source) 
     62             {
     63                 SwingUtilities.invokeLater(new Runnable()
     64                 {
     65                     public void run()
     66                     {
     67                         startBtn.setEnabled(true);
     68                         progressBar.setValue(100);
     69                         progressBar.setVisible(false);
     70                     }
     71                 });
     72             }
     73 
     74             public void sequenceStarted(ImageReader source, int minIndex) {}
     75             public void sequenceComplete(ImageReader source) {}
     76             public void thumbnailStarted(ImageReader source, int imageIndex, int thumbnailIndex) {}
     77             public void thumbnailProgress(ImageReader source, float percentageDone) {}
     78             public void thumbnailComplete(ImageReader source) {}
     79             public void readAborted(ImageReader source) {}
     80         };
     81 
     82         startBtn.addActionListener(new ActionListener()
     83         {
     84             public void actionPerformed(ActionEvent e)
     85             {
     86                 final String urlStr = JOptionPane.showInputDialog(
     87                         SwingUtilities.getWindowAncestor(startBtn), "Input image URL");
     88                 if (urlStr == null) {
     89                     return;
     90                 }
     91 
     92                 new Thread() {
     93                     public void run()
     94                     {
     95                         try {
     96                             URL url = new URL(urlStr);
     97                             ImageInputStream iis = ImageIO.createImageInputStream(url.openStream());
     98                             Iterator iter = ImageIO.getImageReaders(iis);
     99                             if (iter.hasNext()) {
    100                                 ImageReader reader = (ImageReader) iter.next();
    101                                 reader.setInput(iis);
    102                                 reader.addIIOReadProgressListener(progressListener);
    103                                 BufferedImage image = reader.read(reader.getMinIndex());
    104                                 final ImageIcon icon = new ImageIcon(image);
    105 
    106                                 SwingUtilities.invokeLater(new Runnable()
    107                                 {
    108                                     public void run()
    109                                     {
    110                                         imageLabel.setIcon(icon);
    111                                         imageLabel.revalidate();
    112                                     }
    113                                 });
    114                             }
    115                         } catch (MalformedURLException e) {
    116                             e.printStackTrace();
    117                         } catch (IOException e) {
    118                             e.printStackTrace();
    119                         }
    120                     }
    121                 }.start();
    122             }
    123         });
    124 
    125         JFrame f = new JFrame("IIOProgressTest");
    126         f.getContentPane().setLayout(new BorderLayout(55));
    127         f.getContentPane().add(scrollPane, BorderLayout.CENTER);
    128         f.getContentPane().add(p, BorderLayout.SOUTH);
    129         f.setSize(800600);
    130         f.setLocationRelativeTo(null);
    131         f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    132         f.setVisible(true);
    133     }
    134 }
    135 



    Pudgy's World 2005-08-16 12:19 发表评论
    ]]>
    Java Learning Path http://www.tkk7.com/Pudgy/archive/2005/08/15/10177.htmlPudgy's WorldPudgy's WorldMon, 15 Aug 2005 14:31:00 GMThttp://www.tkk7.com/Pudgy/archive/2005/08/15/10177.htmlhttp://www.tkk7.com/Pudgy/comments/10177.htmlhttp://www.tkk7.com/Pudgy/archive/2005/08/15/10177.html#Feedback0http://www.tkk7.com/Pudgy/comments/commentRss/10177.htmlhttp://www.tkk7.com/Pudgy/services/trackbacks/10177.html
    Java Learning Path Q一Q、工L 
    一?nbsp;JDK (Java Development Kit) 

    JDK是整个Java的核心,包括了Javaq行环境QJava Runtime EnvirnmentQ,一堆Java工具和Java基础的类?rt.jar)。不Z么Java应用服务器实质都是内|了某个版本的JDK。因此掌握JDK是学好Java的第一步。最L的JDK是Sun公司发布的JDKQ除了Sun之外Q还有很多公司和l织都开发了自己的JDKQ例如IBM公司开发的JDKQBEA公司的JrocketQ还有GNUl织开发的JDK{等。其中IBM的JDK包含的JVMQJava Virtual MachineQ运行效率要比Sun JDK包含的JVM高出许多。而专门运行在x86q_的Jrocket在服务端q行效率也要比Sun JDK好很多。但不管怎么_我们q是需要先把Sun JDK掌握好?nbsp;

    1?nbsp;JDK的下载和安装 
    JDK又叫做J2SEQJava2 SDK Standard EditionQ,可以从Sun的Java|站上下载到Qhttp://java.sun.com/j2se/downloads.html QJDK当前最新的版本是J2SDK1.4.2Q徏议下载该版本的JDKQ下载页面在q里Qhttp://java.sun.com/j2se/1.4.2/download.html?nbsp;

    下蝲好的JDK是一个可执行安装E序Q默认安装完毕后会在C:\Program Files\Java\目录下安装一套JREQ供览器来使用Q,在C:\j2sdk1.4.2下安装一套JDKQ也包括一套JREQ。然后我们需要在环境变量PATH的最前面增加java的\径C:\j2sdk1.4.2\bin。这样JDK安装好了?nbsp;

    2?nbsp;JDK的命令工?nbsp;
    JDK的最重要命o行工P 
    javaQ?nbsp;启动JVM执行class 
    javacQ?nbsp;Java~译?nbsp;
    jarQ?nbsp;Java打包工具 
    javadocQ?nbsp;Java文档生成?nbsp;
    q些命o行必要非常非常熟悉Q对于每个参数都要很_N才行。对于这些命令的学习QJDK Documentation上有详细的文档?nbsp;


    二?nbsp;JDK Documentation 

    Documentation在JDK的下载页面也有下载连接,同时下蝲Documentation。Documentation是最最重要的编E手册,늛了整个Java所有方面的内容的描q。可以这栯Q学习Java~程Q大部分旉都是花在看这个Documentation上面的。我是随w携带的Q写Java代码的时候,随时查看Q须臾不L?nbsp;


    三?nbsp;应用服务?App Server) 

    App Server是运行Java企业lg的^収ͼ构成了应用Y件的主要q行环境。当前主的App Server是BEA公司的Weblogic Server和IBM公司的Websphere以及免费的JbossQ选择其中一个进行学习就可以了,个h推荐WeblogicQ因为它的体pȝ构更加干净Q开发和部v更加方便Q是Java企业软g开发h员首选的开发^台。下面简要介l几U常用的App ServerQ?nbsp;

    1?nbsp;Tomcat 
    Tomcat严格意义上ƈ不是一个真正的App ServerQ它只是一个可以支持运行Serlvet/JSP的Web容器Q不qTomcat也扩展了一些App Server的功能,如JNDIQ数据库q接池,用户事务处理{等。Tomcat被非常广泛的应用在中规模的Java Web应用中,因此本文做一点下载、安装和配置Tomcat的介l: 

    Tomcat是Apachel织下Jakarta目下的一个子目Q它的主|站是:http://jakarta.apache.org/tomcat/ QTomcat最新版本是Tomcat4.1.27QY件下载的q接是:http://www.apache.org/dist/jakarta/tomcat-4/binaries/ ?nbsp;

    下蝲Tomcat既可以直接下载zip包,也可以下载exe安装包(个hzip更干净些)Q不哪U情况,下蝲完毕安装好以后(zip直接解压~就可以了)。需要设|两个环境变量: 

    JAVA_HOME=C:\j2sdk1.4.2 
    CATALINA_HOME=D:\tomcat4 (你的Tomcat安装目录) 

    q样安装好了,启动Tomcatq行CATALINA_HOME\bin\startup.batQ关闭Tomcatq行shutdown.bat脚本。Tomcat启动以后Q默认?080端口Q因此可以用览器访问http://localhost:8080来测试Tomcat是否正常启动?nbsp;

    Tomcat提供了两个Web界面的管理工PURL分别是: 
    http://localhost:8080/admin/index.jsp 
    http://localhost:8080/manager/html 
    在启用这两个理工具之前Q先需要手工配|一下管理员用户和口令。用一个文本工h开CATALINA_HOME\conf\tomcat-users.xmlq个文gQ加入如下几行: 

    <role rolename="manager"/> 
    <role rolename="admin"/> 
    <user username="robbin" password="12345678" roles="admin,manager,tomcat"/> 

    q样用户“robbin”就具备了超U管理员权限。重新启动Tomcat以后Q你可以用该用户来登陆如上的两个理工具Q通过Web方式q行Tomcat的配|和理了?nbsp;

    2?nbsp;BEA Weblogic 
    Weblogic可以到BEA的网站上免费注册之后下蝲到最新的Weblogic8.1企业版,License可以免费使用1q时_其实q已l完全够了。Weblogic的下载连接:http://commerce.bea.com/index.jspQWeblogic的在U文档:http://edocs.bea.com/ ?nbsp;

    3?nbsp;IBM Webshpere 
    Websphere同样可以下蝲到免费的试用版本Q到IBM的developerWorks|站可以看到Websphere试用产品的下载和相关的Websphere的资料,developerWorks中文|站的连接是Qhttp://www-900.ibm.com/developerWorks/cn/wsdd/ QWebsphere的下载连接:http://www7b.software.ibm.com/wsdd/downloads/WASsupport.html ?nbsp;

    4?nbsp;Jboss 
    Jboss是免费开源的App ServerQ可以免费的从Jboss|站下蝲Qhttp://www.jboss.org/index.htmlQ然而Jboss的文档是不免费,需要花p乎ͼ所以ؓ我们学习Jboss讄了一定的障碍。在Jdon上有几篇不错的Jboss配置文档Q可以用来参考:http://www.jdon.com/idea.html 


    四?nbsp;Java应用的运行环?nbsp;

    Java的应用可以简单分Z下几个方面: 

    1?nbsp;Java的桌面应?nbsp;
    桌面应用一般仅仅需要JRE的支持就_了?nbsp;

    2?nbsp;Java Web应用 
    Java的Web应用臛_需要安装JDK和一个web容器Q例如TomcatQ,以及一个多用户数据库,Web应用臛_分ؓ三层Q?nbsp;
    Browser层:览器显C用户页?nbsp;
    Web层:q行Servlet/JSP 
    DB层:后端数据库,向JavaE序提供数据讉K服务 

    3?nbsp;Java企业U应?nbsp;
    企业U应用比较复杂,可以扩展到n层,最单情况会分ؓ4层: 
    Browser层:览器显C用户页?nbsp;
    Client层:Java客户端图形程序(或者嵌入式讑֤的程序)直接和Web层或者EJB层交?nbsp;
    Web层:q行Servlet/JSP 
    EJB层:q行EJBQ完成业务逻辑q算 
    DB层:后端数据库,向JavaE序提供数据讉K服务 

    4?nbsp;Java嵌入式应?nbsp;
    Java嵌入式应用是一个方兴未艄领域Q从事嵌入式开发,需要从Sun下蝲J2ME开发包QJ2ME包含了嵌入式讑֤专用虚拟机KVMQ和普通的JDK中包含的JVM有所不同。另外还需要到特定的嵌入式厂商那里下蝲模拟器?nbsp;


    Java Learning PathQ二Q、书c篇 

    学习一门新的知识,不可能指望只看一本,或者两本书p够完全掌握。需要有一个@序渐q的阅读q程。我推荐Oreilly出版的Javapd书籍?nbsp;

    在这里我只想补充一点看法,很多人学习Java是从《Thinking in Java》这本书入手的,但是我认本书是不适合初学者的。我认ؓ正确的用这本书的方法应该是作ؓ辅助的读物。《Thinking in Java》ƈ不是在完整的介绍Java的整个体p,而是一U蟩跃式的写作方法,是一U类似tips的方法来对Java很多知识点进行了深入的分析和解释?nbsp;

    对于初学者来_最好是找一本Java入门的书c,但是比较完整的@序的介绍Java的语法,面向对象的特性,核心cd{等Q在看这本书的同Ӟ可以同步来看《Thinking in Java》,来加深对Java的理解和原理的运用,同时又可以完整的了解Java的整个体pR?nbsp;

    对于Java的入门书c,蔡学镛推荐的是Oreilly的《Exploring Java, 2nd Edition?nbsp;或者《Java in a Nutshell,2nd EditionQ针对C++背景Q》,我ƈ没有看过q两本书。其实我觉得电子工业出版C《Java 2~程详解》或者《Java 2从入门到_N》就很不错?nbsp;

    在所有的Java书籍当中Q其实最最有用的,q不是O'reilly?nbsp;Java SerialsQ真正最最有用处是JDK的DocumentationQ几乎你惌得的所有的知识在Documentation里面全部都有Q其中最主要的部分当然是Java基础cd的API文档Q是按照package来组l的Q对于每一个class都有详细的解释,它的l承关系Q是否实C某个接口Q通常用在哪些场合Q还可以查到它所有的public的属性和ҎQ每个属性的解释Q意义,每个Ҏ的用途,调用的参敎ͼ参数的意义,q回值的cdQ以及方法可能抛出的异常{等。可以这h_所有关于Java~程斚w的书c其实都不过是在用比较通俗易懂的语aQ和良好的组l方式来介绍Documentation里面的某个package里面包含的一些类的用法而已。所以万变不d宗,如果你有_的能力来直接通过Documentation来学习Java的类库,那么基本上就不需要看其他的书c了。除此之外,Documentation也是~程必备的手册,我的桌面上有三个Documentation的快h式,分别是J2SDK1.4.1的DocumentationQServlet2.3的Documentation和J2SDKEE1.3.1的Documentation。有了这个三个DocumentationQ什么其他的书籍都不需要了?nbsp;

    对于Java Web ~程来说Q最核心的是要熟悉和掌握HTTP协议Q这个就和Java无关了,在熟悉HTTP协议之后Q就需要熟悉Java的实现HTTP协议的类库,也就是Servlet APIQ所以最重要的东西就是Servlet API。当然对于初学者而言Q直接通过Servlet API来学习Web~程有很大的隑ֺQ我推荐O'reilly的《Java Server Pages 》这本书来学习Web ~程?nbsp;

    EJB的书c当中,《Enterprise JavaBeans, 2nd Edition》是一本很不错的书Q?nbsp;EJB的学习门槛是比较高,入门很难Q但是这本书完全降低了学习的隑ֺQ特别重要的一ҎQEJB的学习需要结合一UApp Server的具体实玎ͼ所以在学习EJB的同Ӟ必须同步的学习某UApp ServerQ而这本书相关的出了三本书Q分别是Weblogic6.1QWebsphere4.0和JBoss3.0上面部v书中例子的实做。真是既有理论,又有实践。在学习EJB的同Ӟ可以边看边做QEJB的学习会变得很轻松?nbsp;

    但是q本书也有一个问题,是版本比较旧,主要讲EJB1.1规范和部分EJB2.0的规范。而Ed Roman写的《Mastering EJB 2.0》这本书完全是根据EJB2.0规范写的Q深入浅出,覆盖了EJB~程的各个方面,q且q有很多~程l验tipsQ也是学习EJB非常推荐的书c之一?nbsp;

    如果是结合Weblogic来学习J2EE的话Q《J2EE应用与BEA Weblogic Server》绝Ҏ首选读物,虽然是讲q的Weblogic6.0Q仍然值得购买Q这本书是BEA官方推荐的教材,作者也是BEA公司的工E师。现在中文版已经随处可见了。这本书l合Weblogic介绍了J2EE各个斚w的技术在Weblogicq_上的开发和部vQ实跉|导意义非常强?nbsp;

    在掌握了Javaq_基础知识和J2EE斚w的知识以后,更进一步的是学习如何运用OO的方法进行Y件的设计Q那么就一定要学习“设计模式”。Sun公司出版了一本《J2EE核心模式》,是每个开发Java企业q_软g的架构师必备的书c。这本书全面的介l了J2EE体系架构的各U设计模式,是设计师的必Mc?nbsp;

    Java Learning PathQ三Q过E篇 

    每个人的学习Ҏ是不同的Q一个h的方法不见得适合另一个hQ我只能是谈自己的学习方法。因为我学习Java是完全自学的Q从来没有问q别人,所以学习的q程基本上完全是自己摸烦出来的。我也不知道q种Ҏ是否是比较好的方法,只能l大家提供一点参考了?nbsp;

    学习Java的第一步是安装好JDKQ写一个Hello WorldQ? 其实JDK的学习没有那么简单,关于JDK有两个问题是很容易一直困扰JavaE序员的地方Q一个是CLASSPATH的问题,其实从原理上来说Q是要搞清楚JRE的ClassLoader是如何加载Class的;另一个问题是package和import问题Q如何来Lcȝ路径问题。把q两个问题摸索清楚了Q就扫除了学习Java和用JDK的最大障。推荐看一下王的《Java深度历险》,对这两个问题q行了深入的探讨?nbsp;

    W二步是学习Java的语法。Java的语法是cC++的,基本上主的~程语言不是cCQ就是类C++的,没有什么新东西Q所以语法的学习Q大概就是半天的旉_了。唯一需要注意的是有几个不容易搞清楚的关键字的用法,publicQprotectedQprivateQstaticQ什么时候用Qؓ什么要用,怎么用,q可能需要有人来指点一下,我当初是完全自己琢磨出来的,׃很久的时间。不q后来我看到《Thinking in Java》这本书上面是讲了这些概늚?nbsp;

    W三步是学习Java的面向对象的~程语言的特性的地方。比如承,构造器Q抽象类Q接口,Ҏ的多态,重蝲Q覆盖,Java的异常处理机制。对于一个没有面向对象语a背景的h来说Q我觉得q个q程需要花很长很长旉Q因为学习Java之前没有C++的经验,只有C的经验,我是大概׃一个月左右吧,才彻底把q些概念都搞清楚Q把书上面的例子反复的揣摩,修改Q尝试,把那几章内容反复的看q来Q看q去Q看了不?遍,才彻底领悟了。不q我惛_果有C++l验的话Q应该一两天旉_了。那么在q个q程中,可以多看看《Thinking in Java》这本书Q对面向对象的讲解非帔R彻。可惜的是我学习的时候,q没有看到这本书Q所以自p了大量的旉Q通过自己的尝试和揣摩来学会的?nbsp;

    W四步就是开始熟悉Java的类库。Java的基cd其实是JDK安装目录下面jre\lib\rt.jarq个包。学习基cd是学习rt.jar。基cd里面的类非常非常多。据说有3000多个Q我没有l计q。但是真正对于我们来说最核心的只?个,分别?nbsp;
    java.lang.*; 
    java.io.*; 
    java.util.*; 
    java.sql.*; 

    q四个包的学习,每个包的学习都可以写成一本厚厚的教材Q而O'reilly也确实是q样做的。我觉得如果旉比较紧,是不可能通过d本书来学习。我觉得比较好的学习Ҏ是这LQ?nbsp;
    首先要通读整个package的框Ӟ了解整个package的classQinterfaceQexception的构成,最好是能够扑ֈ介绍整个包框架的文章。这些专门介l包的书c的前几章应该就是这些M的框架内容介l?nbsp;

    对包整体框架的把握ƈ不是要熟悉每个类的用法,C它有哪些属性,Ҏ。想CC住的。而是要知道包有哪些方面的cL成的Q这些类的用途是什么,最核心的几个类分别是完成什么功能的。我在给人培训的时候一般是一ơ课讲一个包Q所以不可能详细的介l每个类的用法,但是我反复强调,我给你们讲这些包的不是要告诉你们cȝҎ是怎么调用的,也不要求你们CcȝҎ调用Q而是要你们了解,Javal我们提供了哪些c,每个cL用在什么场合,当我遇到问题的时候,我知道哪个类Q或者哪几个cȝl合可以解决我的问题QThat'allQ,当我们具体写E序的时候,只要你知道该用哪个类来完成你的工作就_了。编码的时候,具体的方法调用,是边写代码,ҎDocumentationQ所有的东西都在Documentation里面Q不要求你一定记住,实际你也C?000多个cȝd近10万个Ҏ调用。所以对每个包的M框架的把握就变得极ؓ重要?nbsp;

    W五步,通过上面的学习,如果学的比较扎实的话Q就打好了Java的基了,剩下要做的工作是扫清Documentation里面除了上面4个包之外的其他一些比较有用处的类。相信进展到q一步,Java的自学能力已l被培养出来了,可以C直接学习Documentation的水q了。除了要做GUI~程之外QJDK里面其他会有用处的包是这些: 
    java.text.*; 
    java.net.*; 
    javax.naming.*; 
    q些包里面真正用的比较多的类其实很少Q只有几个,所以不需要花很多旉?nbsp;

    W六步,Java Web ~程 
    Web~程的核心是HTTP协议QHTTP协议和Java无关Q如果不熟悉HTTP协议的话Q虽然也可以学好Servlet/JSP~程Q但是达不到举一反三Q一通百通的境界。所以HTTP协议的学习是必备的。如果熟悉了HTTP协议的话Q又有了Java~程的良好的基础Q学习Servlet/JSP直易如反掌,我学习Servlet/JSPq了不C周的旉Q然后就开始用JSP来做目了?nbsp;

    在Servlet/JSP的学习中Q重头仍然是Servlet Documentation。Servlet API最常用的类很少Q花比较的旉可以掌握了。把q些c都看一遍,多写几个例子试试。Servlet/JSP~程本质是在反复调用这些类来通过HTTP协议在Web Server和Brower之间交谈。另外对JSPQ还需要熟悉几个常用JSP的标讎ͼ具体的写法记不住的话Q时查是了?nbsp;

    此外Java Web~程学习的重点要攑֜Web Application的设计模式上Q如何进行业务逻辑的分析,q且q行合理的设计,按照MVC设计模式的要求,q用Servlet和JSP分别完成不同的逻辑层,掌握如何在Servlet和JSP之间q行程的控制和数据的共享,以及Web Application应该如何配置和部|Ӏ?nbsp;

    W七步,J2EE~程 
    以上的学习过E如果是比较利的话Q进行到q一步,隑ֺ又陡然提高。因Z面的知识内容都是只涉及一个方面,而像EJBQJMSQJTA{核心的J2EE规范往往是几UJava技术的l合q用的结Ӟ所以掌握v来难度比较大?nbsp;

    首先一定要学习好JNDIQJNDI是App Server定位服务器资源(EJBlgQDatasouceQJMSQ查找方法,如果对JNDI不熟悉的话,EJBQJMSq些东西几乎学不下去。JNDI其实是javax.naming.*q个包,q用h很简单。难点在于服务器资源文g的配|。对于服务器资源文g的配|,需要看看专门的文档规范了,比如web.xml的写法,ejb-jar.xml的写法等{。针ҎU不同的App ServerQ还有自q服务资源配置文gQ也是需要熟悉的?nbsp;

    然后可以学习JTAQ主要是要理解JTA对于事务的控制的ҎQ以及该在什么场合用JTA。这里可以简单的举个例子Q我们知道一般情况可以对于一个数据库q接q行事务控制(conn.setAutoCommit(false),....,conn.commit())Q做Z个原子操作,但是假设我的业务需求是要把对两个不同数据库的操作做Z个原子操作,你能做的到吗Q这时候只能用JTA了。假设操作过E是先往A数据库插一条记录,然后删除B数据库另一个记录,我们自己写代码是控制不了把整个操作做Z个原子操作的。用JTA的话Q由App Server来完成控制?nbsp;

    在学习EJB之前要学习对象序列化和RMIQRMI是EJB的基。接着学习JMS和EJBQ对于EJB来说Q最关键是要理解EJB是如何通过RMI来实现对q端对象的调用的Q以及在什么情况下要用到EJB?nbsp;

    在学习完EJBQJMSq些东西之后Q你可能会意识到要急不可待学习两个领域的知识,一个是UMLQ另一个是Design Pattern。Java企业软g的设计非帔R视框?Framework)的设计,一个好的Y件框架是软g开发成功的必要条g。在q个时候,应该开始把学习的重Ҏ在设计模式和框架的学习上Q通过学习和实际的~程l验来掌握EJB的设计模式和J2EE的核心模式?nbsp;

    J2EE规范里面Q除了EJBQJMSQJTAQServlet/JSPQJDBC之外q有很多很多的企业技术,q里不一一q行介绍了?nbsp;

    另外q有一个最新领域Web Services。Web Services也完全没有Q何新东西Q它像是一U黏合剂Q可以把不同的服务统一h提供一个统一的调用接口,作ؓ使用者来_我只要获得服务提供者给我的WSDLQ对服务的描qͼQ就够了Q我完全不知道服务器提供者提供的服务I竟是EJBlgQ还?NetlgQ还是什么CORBAlgQ还是其他的什么实玎ͼ我也不需要知道。Web Services最伟大的地方就在于通过l一的服务提供方式和调用方式Q实C整个Internet服务的共享,是一个非o人激动的技术领域。Web Services好像目前q没有什么很好的书籍Q但是可以通过在网l上面查资料的方式来学习?nbsp;

    Java Learning PathQ四Q?nbsp;Ҏ?nbsp;

    Java作ؓ一门编E语aQ最好的学习Ҏ是写代码。当你学习一个类以后Q你可以自己写个简单的例子E序来运行一下,看看有什么结果,然后再多调用几个cȝҎQ看看运行结果,q样非常直观的把cȝ学会了,而且记忆非常深刻。然后不应该满把代码调通,你应该想想看如果我不q样写,换个方式Q再试试行不行。记得哪个高q学习编E就是个破坏的过E,把书上的例子Q自己学习Documentation~写的例子在q行通过以后Q不断的试着用不同的Ҏ实现Q不断的试破坏代码的结构,看看它会有什么结果。通过q样的方式,你会很彻底的很精通的掌握Java?nbsp;

    举个例子Q我们都~过Hello World 

    public class HelloWorld 
    public static void main(String[] args) 
    System.
    out.println("Hello World"); 
    }
     
    }

     

    很多初学者不是很理解Z么mainҎ一定要q样来定义public static void main(String[] args)Q能不能不这样写Q包括我刚学习Java的时候也有这L疑问。想知道{案吗?很简单,你把main改个名字q行一下,看看报什么错误,然后Ҏ出错信息q行分析Q把main的public取掉Q在试试看,报什么错误;staticLq能不能q行Q不知道mainҎ是否一定要传一个String[]数组的,把String[]ҎQ改成int[]Q或者String试试看;不知道是否必dargs参数名称的,也可以把argsҎ别的名字Q看看运行结果如何?nbsp;

    我当初学习Java的时候就是这样做的,把Hello WorldE序反复改了七八ơ,不断q行Q分析运行结果,最后就d明白Z么了mainҎ是这样定义的了?nbsp;

    此外Q我对于staicQpublicQprivateQExceptionQtry{ }catch {}finally{}{等{等一开始都不是很懂Q都是把参考书上面的例子运行成功,然后开始破坏它Q不断的Ҏ自己心里面的疑问来重新改写程序,看看能不能运行,q行出来是个什么样子,是否可以得到预期的结果。这栯然比较费旉Q不q一个例子程序这样反复破坏几ơ之后。我对q个相关的知识彻底学通了。有时候甚x意写一些错误的代码来运行,看看能否得到预期的运行错误。这样对于编E的掌握是及其深ȝ?nbsp;

    其中特别值得一提的是JDK有一个非常棒的调试功能,-verbose 
    java -verbose 
    javac -verbose 以及其它很多JDK工具都有q个选项 
    -verbose 可以昄在命令执行的q程中,JVM都依ơ加载哪里ClassQ通过q些宝贵的调试信息,可以帮助我们分析出JVM在执行的q程中都q了些什么?nbsp;

    另外Q自己在学习q程中,写的很多的这U破坏例E,应该有意识的分门别类的保存下来,在工作中U篏的典型例E也应该定期整理Q日U月累,自己有了一个代码库了。遇到类似的问题Q到代码库里?nbsp;Copy & Paste QSearch & ReplaceQ就好了Q极大提高了开发速度。最理想的情冉|把一些通用的例E自己再抽象一层,形成一个通用的类库,装好。那么可复用性就更强了?nbsp;

    所以我觉得其实不是特别需要例E的Q自己写的破坏例E就是最好的例子Q如果你实在对自己写的代码不攑ֿ的话Q我强烈推荐你看看JDK基础cd的Java源代码。在JDK安装目录下面会有一个src.zipQ解开来就可以完整的看到整个JDK基础cdQ也是rt.jar的Java源代码,你可以参考一下Sun是怎么写JavaE序的,规范是什么样子的。我自己在学习Java的类库的时候,当有些地方理解的不是很清楚的时候,或者想更加清晰的理解运作的l节的时候,往往会打开相应的类的源代码Q通过看源代码Q所有的问题都会一扫而空?nbsp;

    Java Learning PathQ五Q资源篇 

    1?nbsp;http://java.sun.com/ (英文) 
    Sun的Java|站Q是一个应该经常去看的地方。不用多说?nbsp;

    2?nbsp;http://www-900.ibm.com/developerWorks/cn/ 
    IBM的developerWorks|站Q英语好的直接去英文ȝ点看。这里不但是一个极好的面向对象的分析设计网站,也是Web ServicesQJavaQLinux极好的网站。强烈推荐!Q! 

    3?nbsp;http://www.java-cn.com/ (中文) 
    JAVA中文站,目前国内资料最全、会员最多的JAVA技术网站,人气极高。有《JAVA电子书库》、《JAVA视频库?国内唯一)、《JAVA技术文摘库》、《JAVA源代码库》、《JAVA工具库》、《招聘求职广场》等主要栏目Q还有一些专家栏目。目前会员有5万多QVIP会员q?000人。无论是菜鸟q是老鸟Q都能在此网站中扑ֈ自己所需要的东东Q! 最强烈推荐Q!Q!Q! 

    4?nbsp;http://www.javaworld.com/ (英文) 
    关于Java很多新技术的讨论和新闅R想多了解Java的方斚w面的应用Q这里比较好?nbsp;

    5?nbsp;http://dev2dev.bea.com.cn/index.jsp 
    BEA的开发者园圎ͼBEA作ؓ最重要的App Server厂商Q有很多独到的技术,在Weblogic上做开发的朋友不容错过?nbsp;

    6?nbsp;http://www.huihoo.com/ 
    灰狐动力|站Q一个专业的中间件网站,虽然不是专业的Java|站Q但是在J2EE企业应用技术方面有深厚的造诣?nbsp;

    7?nbsp;http://www.theserverside.com/home/ (英文) 
    TheServerSide是一个著名的专门面向Java Server端应用的|站?nbsp;

    8?nbsp;http://www.javaresearch.org/ 
    Java研究l织Q有很多优秀的Java斚w的文章和教程Q特别是在JDO斚w的文章比较丰富?nbsp;

    9?nbsp;http://www.cnjsp.org/ 
    JSP技术网站,有相当多的Java斚w的文章和资源?nbsp;

    10?nbsp;http://www.jdon.com/ 
    Jdon论坛Q是一个个人性质的中文J2EE专业技术论坛,在众多的Java的中文论坛中QJdon一个是技术含量非帔RQ帖子质量非常好的论坛?nbsp;

    11?nbsp;http://sourceforge.net/ 
    SourgeForge是一个开放源代码软g的大本营Q其中也有非帔R怸富的Java的开放源代码的著名的软g?/P>

    Pudgy's World 2005-08-15 22:31 发表评论
    ]]>
    վ֩ģ壺 ޳AVƬһ| þþƷһ糱| ŷ޾ƷƵѹۿ | վ߹ۿ| ò߹ۿƵ| Ʒ˳Ƶapp| 91ƷѹƬ| þ99׾Ʒ| ߹ۿվڵ| 59paoɹƵ| ĻȫƵ | ĻƵ| 鴤һһgifƵ| avѸ߳ˮ| ĻƷ| ²߾ƷƵѹۿ| þþùƷר| þòþüƵ7| AƬƵWWW| ѸԴվ߹ۿ| һѰ| һպĻ| ԾþþӰԺ| þþþAV| ޾Ʒþþþþ| ޾Ʒպ| ؼaaaaaaaaaëƬƵ| þþþþùaѹۿ| ձĻѸƵ| һëƬѿ| ҹӰѹۿ| ޾ƷһۺϾƷ99| av벻| һ| ɫַ| һƷһavһˬˬ| ѿhƬվ| СƵ߹ۿ| JIZZձ| ޾Ʒҹvaþ| aëƬվ|