Joinclass Inc  
软件开发 软件配置 项目管理 软件工程
公告
  • 本人联系方式: E-mail: tilanmaster@gmail.com msm: J.joy@msn.com
日历
统计
  • 随笔 - 53
  • 文章 - 52
  • 评论 - 67
  • 引用 - 0

导航

常用链接

留言簿(1)

随笔分类(53)

随笔档案(53)

文章分类(61)

相册

JAVA学习链接

搜索

  •  

积分与排名

  • 积分 - 90086
  • 排名 - 77

最新评论

阅读排行榜

评论排行榜

 

 

他创造了10年内由百亿到『兆』(新台币)的飞速成长传奇。他的传奇,不是侥幸,不是昙花一现,更不是神笔马良,而是必然,是深厚的积累,是数十年不露声色,积蓄力量之后的大干一场。
  用他自己的话说,这叫『阿里山上的神木之所以大,四千年前种子掉到土里时就决定了,绝不是四千年后才知道。
          
 
       我的成功三部曲:策略、决心加方法
      ——记台湾鸿海集团董事长郭台铭
                               
                             毕亚军/文
 
  从30万元台币的小小黑白电视机旋钮工厂到“台湾最大民营制造企业”,从“台湾最大民营制造企业”到“台湾最大民营企业”,再到“台湾营收最大企业”,郭台铭先生在全球性的景气低迷中征战四方、大者恒大,让企业称谓越来越短的同时,也让外界对他个人的称谓越来越简单——转眼间,就从“台湾科技首富”简单到“台湾首富”。
  2005年,他创办领导的鸿海集团,提前3年营收突破兆元(新台币)大关,在台湾第一个完成三大洲并购的基础上,再写年营收破“兆”的历史纪录,耸立起一座更高更强的超级竞争平台。
  这个结果连他自己都没有想到。2005年年初他还说:“等营业额超过一兆,我就要走了。”并预计自己要到2008年才能实现目标,“吃了秤铊铁了心,99.9%,2008年一定交棒出去。”
               
               孤雁独自飞
 
  常说自己是山西人的郭台铭,祖籍山西晋城,1950年生于台湾。
  郭台铭的父亲是警察,生活拮据,但给了下一代很好的身教:“教我们安贫乐道,不该我们的就不该去拿,我们家从小到大都没有自己的房子,没有公司实习,因航运和贸易关系紧密,他利用机会,沙发,最好的是藤椅,但我们不觉得自己贫穷。”
  这样的经历,让郭台铭贵为台湾首富后,依然每月花不到一万台币,生活十分简朴。最快乐的事是母亲下碗面给自己吃。“我是山西人,吃碗面、水饺、包子,就很舒服了,一点都不觉得不好,这才是真正的自我。”他说。
  警察之子的背景,也让他养成疾恶如仇,对弱者更弱,强者更强的个性,对几次“碰车事件”的处理就是例证:有次坐公务车拜访客户,那是他第一次有司机开车,车子被一辆摩托撞扁,他下车拿了1000元给摩托车司机去修车;有一次与中华邮政的车相撞,他看两方都有保险,就算了;还有一次,他的宾士300跟宾士500 撞在一起,立即下车决定好好算账。他说:“这就是我的个性。”
  这样的经历和背景,更让他只能靠自己的努力去改变命运。
  郭台铭念的是船务科,1971年到台湾复兴航运公司实习,因航运和贸易关系紧密,他利用机会,掌握到许多贸易知识,而且看到贸易背后的机遇。“可是我转念一想,没有工厂哪来的贸易?”由此萌生了如有可能,要自己开工厂的念头。
  结束实习和服役之后,机会出现在郭台铭面前。一个朋友告诉他,有个外商想找一家公司承接一批塑料零件的生产。确认消息后,郭台铭用母亲做标会的10万台币和几个朋友一道干了起来,并于第二年(1974)在台北注册了资本为30万台币的鸿海塑料企业有限公司。  工厂初创,连模具组都买不起。为完成定单,他四处到模具厂请人帮忙。最初,每月还有营业额8万,但很快遭遇石油危机的冲击,大环境一片萧条,小鸿海唇亡齿寒,转眼就陷入绝境。1975 年更负债累累,朋友股东们决定洗手上岸。
  因为深信电子业在台湾大有可为,郭台铭决定独自支撑局面。他向岳丈借了70万,将公司改名为鸿海精密工业,并由先前的电视机旋钮转向生产电视机用高压阳极帽组件。
  此时的郭台铭,就像他自己后来常常比喻的“寒冬中的孤雁”,只能在寒风凛冽中孤独展翅,依靠自己,飞出一个春天来。
  孤独的不单是股东的撤退,鸿海没有规模和技术,郭台铭没有背景,也没有让政府心动的愿景,有的只是困难,还有小混混来收保护费。“最可恶的是,早上有人来推销消防器材,如果不付钱购买,下午就会有官员来做消防检查。”融资贷款就更是谈不上,以至于多年后,他常常笑言:“20 年前我把公司设在台北土城,就是因为土城有一间看守所,是台湾专门关经济犯的地方。要有一天我因支票无法兑现被关了,我老婆还很方便来看我,报告我公司状况,让公司继续营运。”
  有一次,新加坡劳工部长向郭台铭请教,台湾当局用了什么政策让中小企业纷纷走上世界的舞台?他说:“新加坡把中小企业照顾得太好了,所以企业经不起大风大浪;而台湾当局什么都没有做,却让台湾的中小企业有了蟑螂一样的生存能力!”
  靠着蟑螂一样的生存能力,郭台铭无人助,就自助。“像一个地瓜,在田里默默地长大”。坚强的带领鸿海绝地逢生,公司也因此转入赢利,到1977年时,其资本额已增加至200万台币。
  此时,台湾经济起飞,地产和地皮价格不断上涨,他的工厂附近就有土地要出售,每坪才3800元,如果借机搞地产,肯定大赚钱。另外,制造业的蓬勃也让原料短缺,如果购买囤积,也会比代工赚得多。面对唾手可得的良机,首次拥有百万资本的郭台铭不得不仔细考虑。一贯雷厉风行的他花两个星期才定下答案,天天问自己:“我到底是以赚钱为目的,还是准备从事长久的工业?”
  最终,他决定从事长久的工业。求人要模具的无奈,让郭台铭对自主技术刻骨铭心:要长久,就必须拥有技术。他决定用这笔钱兴建自己的模具厂,告别过去常常因没有模具而喊天天不应,叫地地不灵的窘境,以掌握自主权,争取更大发展空间。
  这是一个现在人人都会佩服的决定,但当时,却被认为是傻掉顶的一根筋。不到一年,他看好的土地就涨了10多倍,原料也是水涨船高,但鸿海刚刚建立的模具厂却让人忧心。
  一方面是模具开发的压力,因为设备和员工都是新的,他和创业伙伴,现在的鸿海总工程师陈一飞,决定借机打破台湾模具界的“师徒制”传统,将模具的开发公式化,受到老模具师傅反对,甚至集体抗议。一方面因为模具本身没有直接利润,而且刚开始成本较高,工厂产量小,规模效应也发挥不出来。另外,优秀的人才都想到大公司去上班,没人愿意屈就于小小的鸿海,处处都是困难。
  家庭生活也受到牵连。当时,郭台铭的儿子刚出生不久,他每天一、二点才睡,五、六点就要出门。“为了睡好,只好跟太太分房睡。儿子整整哭一个月,最后我忍不住问太太:为什么儿子一直哭?太太才跟我说∶‘你已经三个月没有拿钱回家了!’”。郭台铭回忆,当时为了节省钱,他连长途电话都要到父母家去打。有次过年,给员工发完年终奖后,只剩2000块钱,初一给父母1000、初二给太太娘家1000,初三就身无分文,一头扎进工厂中。他说:“有时真不知道这个决定是不是太傻。”只是“每到过年,我都告诉自己,坚持下去,一天不自我累积技术,便一天要受制于人!”
  4年后(1980年),他得到了是不是太傻的答案。当炒地、囤原料的人,开始原地踏步或走下坡时。鸿海因为拥有同业竞争者没有的技术实力和平台,接到了第一笔来自美国跨国公司的大订单。
  为进一步将模具平台的核心优势转为竞争优势,郭台铭还提出“打造先进制造力”的构想,要求鸿海“搞自主研发,不断地把科技成果转换为生产力,并且在这个方向上全力以赴,长期不变。”同时,还将全部利润投入到生产,以扩大产能。
  但问题相伴而来。因为是代工,鸿海的业绩增长只能建立在委托代工企业的业绩增长之上。这样一来,为谁代工就显得十分重要。而此时,委托鸿海代工的电视、收音机制造企业却因台币快速升值纷纷倒闭。为保鸿海的生存,郭台铭首先苦练内功,控制成本,力求每个环节都以最低成本产生最大效应。其时,鸿海与美国公司的生意通过中间商完成,郭台铭希望直接与对方交易,打电话过去,说如果直接做,有“秘密武器”可把成本降到“吓死人”。客户派来代表时,他故弄玄虚似地把人带到一台刚研发成功的圆形机器面前。因为这个机器,可以利用震动来推动顶针,省掉了由人工一根一根插针的成本。
  靠着低成本和模具的领先,鸿海在逆市和微利中赢取客户,业绩持续增长,到1982年时,还买下了自己的厂房。
posted @ 2007-04-09 11:54 Joinclass Inc 阅读(512) | 评论 (0)编辑 收藏
 

一、static

  请先看下面这段程序:


public class Hello{
public static void main(String[] args){ //(1)
System.out.println("Hello,world!"); //(2)
}
}


  看过这段程序,对于大多数学过Java 的从来说,都不陌生。即使没有学过Java,而学过其它的高级语言,例如C,那你也应该能看懂这段代码的意思。它只是简单的输出“Hello,world”,一点别的用处都没有,然而,它却展示了static关键字的主要用法。


  在1处,我们定义了一个静态的方法名为main,这就意味着告诉Java编译器,我这个方法不需要创建一个此类的对象即可使用。你还得你是怎么运行这个程序吗?一般,我们都是在命令行下,打入如下的命令(加下划线为手动输入):

javac Hello.java
java Hello
Hello,world!

  这就是你运行的过程,第一行用来编译Hello.java这个文件,执行完后,如果你查看当前,会发现多了一个Hello.class文件,那就是第一行产生的Java二进制字节码。第二行就是执行一个Java程序的最普遍做法。执行结果如你所料。在2中,你可能会想,为什么要这样才能输出。好,我们来分解一下这条语句。(如果没有安装Java文档,请到Sun的官方网站浏览J2SE API)首先,System是位于java.lang包中的一个核心类,如果你查看它的定义,你会发现有这样一行:public static final PrintStream out;接着在进一步,点击PrintStream这个超链接,在METHOD页面,你会看到大量定义的方法,查找println,会有这样一行:

public void println(String x)。

  好了,现在你应该明白为什么我们要那样调用了,out是System的一个静态变量,所以可以直接使用,而out所属的类有一个println方法。

静态方法

  通常,在一个类中定义一个方法为static,那就是说,无需本类的对象即可调用此方法。如下所示:


class Simple{
static void go(){
System.out.println("Go...");
}
}
public class Cal{
public static void main(String[] args){
Simple.go();
}
}


  调用一个静态方法就是“类名.方法名”,静态方法的使用很简单如上所示。一般来说,静态方法常常为应用程序中的其它类提供一些实用工具所用,在Java的类库中大量的静态方法正是出于此目的而定义的。


静态变量

  静态变量与静态方法类似。所有此类实例共享此静态变量,也就是说在类装载时,只分配一块存储空间,所有此类的对象都可以操控此块存储空间,当然对于final则另当别论了。看下面这段代码:


class Value{
static int c=0;
static void inc(){
c++;
}
}
class Count{
public static void prt(String s){
System.out.println(s);
}
public static void main(String[] args){
Value v1,v2;
v1=new Value();
v2=new Value();
prt("v1.c="+v1.c+" v2.c="+v2.c);
v1.inc();
prt("v1.c="+v1.c+" v2.c="+v2.c);
}
}


  结果如下:


v1.c=0 v2.c=0
v1.c=1 v2.c=1

  由此可以证明它们共享一块存储区。static变量有点类似于C中的全局变量的概念。值得探讨的是静态变量的初始化问题。我们修改上面的程序:


class Value{
static int c=0;
Value(){
c=15;
}
Value(int i){
c=i;
}
static void inc(){
c++;
}
}
class Count{
public static void prt(String s){
System.out.println(s);
}
Value v=new Value(10);
static Value v1,v2;
static{
prt("v1.c="+v1.c+" v2.c="+v2.c);
v1=new Value(27);
prt("v1.c="+v1.c+" v2.c="+v2.c);
v2=new Value(15);
prt("v1.c="+v1.c+" v2.c="+v2.c);
}
public static void main(String[] args){
Count ct=new Count();
prt("ct.c="+ct.v.c);
prt("v1.c="+v1.c+" v2.c="+v2.c);
v1.inc();
prt("v1.c="+v1.c+" v2.c="+v2.c);
prt("ct.c="+ct.v.c);
}
}


运行结果如下:


v1.c=0 v2.c=0
v1.c=27 v2.c=27
v1.c=15 v2.c=15
ct.c=10
v1.c=10 v2.c=10
v1.c=11 v2.c=11
ct.c=11

  这个程序展示了静态初始化的各种特性。如果你初次接触Java,结果可能令你吃惊。可能会对static后加大括号感到困惑。首先要告诉你的是,static定义的变量会优先于任何其它非static变量,不论其出现的顺序如何。正如在程序中所表现的,虽然v出现在v1和v2的前面,但是结果却是v1和v2的初始化在v的前面。在static{后面跟着一段代码,这是用来进行显式的静态变量初始化,这段代码只会初始化一次,且在类被第一次装载时。如果你能读懂并理解这段代码,会帮助你对static关键字的认识。在涉及到继承的时候,会先初始化父类的static变量,然后是子类的,依次类推。非静态变量不是本文的主题,在此不做详细讨论,请参考Think in Java中的讲解。

静态类

  通常一个普通类不允许声明为静态的,只有一个内部类才可以。这时这个声明为静态的内部类可以直接作为一个普通类来使用,而不需实例一个外部类。如下代码所示:


public class StaticCls{
public static void main(String[] args){
OuterCls.InnerCls oi=new OuterCls.InnerCls();
}
}
class OuterCls{
public static class InnerCls{
InnerCls(){
System.out.println("InnerCls");
}
}
}


  输出结果会如你所料:


InnerCls

  和普通类一样。内部类的其它用法请参阅Think in Java中的相关章节,此处不作详解。

二、this & super

  在上一篇拙作中,我们讨论了static的种种用法,通过用static来定义方法或成员,为我们编程提供了某种便利,从某种程度上可以说它类似于C语言中的全局函数和全局变量。但是,并不是说有了这种便利,你便可以随处使用,如果那样的话,你便需要认真考虑一下自己是否在用面向对象的思想编程,自己的程序是否是面向对象的。好了,现在开始讨论this&super这两个关键字的意义和用法。

  在Java中,this通常指当前对象,super则指父类的。当你想要引用当前对象的某种东西,比如当前对象的某个方法,或当前对象的某个成员,你便可以利用this来实现这个目的,当然,this的另一个用途是调用当前对象的另一个构造函数,这些马上就要讨论。如果你想引用父类的某种东西,则非super莫属。由于this与super有如此相似的一些特性和与生俱来的某种关系,所以我们在这一块儿来讨论,希望能帮助你区分和掌握它们两个。

在一般方法中

  最普遍的情况就是,在你的方法中的某个形参名与当前对象的某个成员有相同的名字,这时为了不至于混淆,你便需要明确使用this关键字来指明你要使用某个成员,使用方法是“this.成员名”,而不带this的那个便是形参。另外,还可以用“this.方法名”来引用当前对象的某个方法,但这时this就不是必须的了,你可以直接用方法名来访问那个方法,编译器会知道你要调用的是那一个。下面的代码演示了上面的用法:


public class DemoThis{
private String name;
private int age;
DemoThis(String name,int age){
setName(name); //你可以加上this来调用方法,像这样:this.setName(name);但这并不是必须的
setAge(age);
this.print();
}
public void setName(String name){
this.name=name;//此处必须指明你要引用成员变量
}
public void setAge(int age){
this.age=age;
}
public void print(){
System.out.println("Name="+name+" Age="+age);//在此行中并不需要用this,因为没有会导致混淆的东西
}
public static void main(String[] args){
DemoThis dt=new DemoThis("Kevin","22");
}
}


  这段代码很简单,不用解释你也应该能看明白。在构造函数中你看到用this.print(),你完全可以用print()来代替它,两者效果一样。下面我们修改这个程序,来演示super的用法。

class Person{
public int c;
private String name;
private int age;
protected void setName(String name){
this.name=name;
}
protected void setAge(int age){
this.age=age;
}
protected void print(){
System.out.println("Name="+name+" Age="+age);
}
}
public class DemoSuper extends Person{
public void print(){
System.out.println("DemoSuper:");
super.print();
}
public static void main(String[] args){
DemoSuper ds=new DemoSuper();
ds.setName("kevin");
ds.setAge(22);
ds.print();
}
}


  在DemoSuper中,重新定义的print方法覆写了父类的print方法,它首先做一些自己的事情,然后调用父类的那个被覆写了的方法。输出结果说明了这一点:


DemoSuper:
Name=kevin Age=22

  这样的使用方法是比较常用的。另外如果父类的成员可以被子类访问,那你可以像使用this一样使用它,用“super.父类中的成员名”的方式,但常常你并不是这样来访问父类中的成员名的。

在构造函数中

  构造函数是一种特殊的方法,在对象初始化的时候自动调用。在构造函数中,this和super也有上面说的种种使用方式,并且它还有特殊的地方,请看下面的例子:


class Person{
public static void prt(String s){
System.out.println(s);
}
Person(){
prt("A Person.");
}
Person(String name){
prt("A person name is:"+name);
}
}
public class Chinese extends Person{
Chinese(){
super(); //调用父类构造函数(1)
prt("A chinese.");//(4)
}
Chinese(String name){
super(name);//调用父类具有相同形参的构造函数(2)
prt("his name is:"+name);
}
Chinese(String name,int age){
this(name);//调用当前具有相同形参的构造函数(3)
prt("his age is:"+age);
}
public static void main(String[] args){
Chinese cn=new Chinese();
cn=new Chinese("kevin");
cn=new Chinese("kevin",22);
}
}


  在这段程序中,this和super不再是像以前那样用“.”连接一个方法或成员,而是直接在其后跟上适当的参数,因此它的意义也就有了变化。super后加参数的是用来调用父类中具有相同形式的构造函数,如1和2处。this后加参数则调用的是当前具有相同参数的构造函数,如3处。当然,在Chinese的各个重载构造函数中,this和super在一般方法中的各种用法也仍可使用,比如4处,你可以将它替换为“this.prt”(因为它继承了父类中的那个方法)或者是“super.prt”(因为它是父类中的方法且可被子类访问),它照样可以正确运行。但这样似乎就有点画蛇添足的味道了。


  最后,写了这么多,如果你能对“this通常指代当前对象,super通常指代父类”这句话牢记在心,那么本篇便达到了目的,其它的你自会在以后的编程实践当中慢慢体会、掌握。另外关于本篇中提到的继承,请参阅相关Java教程。

三、final

  final在Java中并不常用,然而它却为我们提供了诸如在C语言中定义常量的功能,不仅如此,final还可以让你控制你的成员、方法或者是一个类是否可被覆写或继承等功能,这些特点使final在Java中拥有了一个不可或缺的地位,也是学习Java时必须要知道和掌握的关键字之一。

final成员

  当你在类中定义变量时,在其前面加上final关键字,那便是说,这个变量一旦被初始化便不可改变,这里不可改变的意思对基本类型来说是其值不可变,而对于对象变量来说其引用不可再变。其初始化可以在两个地方,一是其定义处,也就是说在final变量定义时直接给其赋值,二是在构造函数中。这两个地方只能选其一,要么在定义时给值,要么在构造函数中给值,不能同时既在定义时给了值,又在构造函数中给另外的值。下面这段代码演示了这一点:


import java.util.List;
import java.util.ArrayList;
import java.util.LinkedList;
public class Bat{
final PI=3.14; //在定义时便给址值
final int i; //因为要在构造函数中进行初始化,所以此处便不可再给值
final List list; //此变量也与上面的一样
Bat(){
i=100;
list=new LinkedList();
}
Bat(int ii,List l){
i=ii;
list=l;
}
public static void main(String[] args){
Bat b=new Bat();
b.list.add(new Bat());
//b.i=25;
//b.list=new ArrayList();
System.out.println("I="+b.i+" List Type:"+b.list.getClass());
b=new Bat(23,new ArrayList());
b.list.add(new Bat());
System.out.println("I="+b.i+" List Type:"+b.list.getClass());
}
}


  此程序很简单的演示了final的常规用法。在这里使用在构造函数中进行初始化的方法,这使你有了一点灵活性。如Bat的两个重载构造函数所示,第一个缺省构造函数会为你提供默认的值,重载的那个构造函数会根据你所提供的值或类型为final变量初始化。然而有时你并不需要这种灵活性,你只需要在定义时便给定其值并永不变化,这时就不要再用这种方法。在main方法中有两行语句注释掉了,如果你去掉注释,程序便无法通过编译,这便是说,不论是i的值或是list的类型,一旦初始化,确实无法再更改。然而b可以通过重新初始化来指定i的值或list的类型,输出结果中显示了这一点:


I=100 List Type:class java.util.LinkedList
I=23 List Type:class java.util.ArrayList

  还有一种用法是定义方法中的参数为final,对于基本类型的变量,这样做并没有什么实际意义,因为基本类型的变量在调用方法时是传值的,也就是说你可以在方法中更改这个参数变量而不会影响到调用语句,然而对于对象变量,却显得很实用,因为对象变量在传递时是传递其引用,这样你在方法中对对象变量的修改也会影响到调用语句中的对象变量,当你在方法中不需要改变作为参数的对象变量时,明确使用final进行声明,会防止你无意的修改而影响到调用方法。
另外方法中的内部类在用到方法中的参变量时,此参变也必须声明为final才可使用,如下代码所示:


public class INClass{
void innerClass(final String str){
class IClass{
IClass(){
System.out.println(str);
}
}
IClass ic=new IClass();
}
public static void main(String[] args){
INClass inc=new INClass();
inc.innerClass("Hello");
}
}


final方法


  将方法声明为final,那就说明你已经知道这个方法提供的功能已经满足你要求,不需要进行扩展,并且也不允许任何从此类继承的类来覆写这个方法,但是继承仍然可以继承这个方法,也就是说可以直接使用。另外有一种被称为inline的机制,它会使你在调用final方法时,直接将方法主体插入到调用处,而不是进行例行的方法调用,例如保存断点,压栈等,这样可能会使你的程序效率有所提高,然而当你的方法主体非常庞大时,或你在多处调用此方法,那么你的调用主体代码便会迅速膨胀,可能反而会影响效率,所以你要慎用final进行方法定义。

final类

  当你将final用于类身上时,你就需要仔细考虑,因为一个final类是无法被任何人继承的,那也就意味着此类在一个继承树中是一个叶子类,并且此类的设计已被认为很完美而不需要进行修改或扩展。对于final类中的成员,你可以定义其为final,也可以不是final。而对于方法,由于所属类为final的关系,自然也就成了final型的。你也可以明确的给final类中的方法加上一个final,但这显然没有意义。

  下面的程序演示了final方法和final类的用法:


final class final{
final String str="final Data";
public String str1="non final data";
final public void print(){
System.out.println("final method.");
}
public void what(){
System.out.println(str+"
"+str1);
}
}
public class FinalDemo { //extends final 无法继承
public static void main(String[] args){
final f=new final();
f.what();
f.print();
}
}


  从程序中可以看出,final类与普通类的使用几乎没有差别,只是它失去了被继承的特性。final方法与非final方法的区别也很难从程序行看出,只是记住慎用。


final在设计模式中的应用

  在设计模式中有一种模式叫做不变模式,在Java中通过final关键字可以很容易的实现这个模式,在讲解final成员时用到的程序Bat.java就是一个不变模式的例子。如果你对此感兴趣,可以参考阎宏博士编写的《Java与模式》一书中的讲解。

  到此为止,this,static,supert和final的使用已经说完了,如果你对这四个关键字已经能够大致说出它们的区别与用法,那便说明你基本已经掌握。然而,世界上的任何东西都不是完美无缺的,Java提供这四个关键字,给程序员的编程带来了很大的便利,但并不是说要让你到处使用,一旦达到滥用的程序,便适得其反,所以在使用时请一定要认真考虑。


  请先看下面这段程序:


public class Hello{
public static void main(String[] args){ //(1)
System.out.println("Hello,world!"); //(2)
}
}


  看过这段程序,对于大多数学过Java 的从来说,都不陌生。即使没有学过Java,而学过其它的高级语言,例如C,那你也应该能看懂这段代码的意思。它只是简单的输出“Hello,world”,一点别的用处都没有,然而,它却展示了static关键字的主要用法。


  在1处,我们定义了一个静态的方法名为main,这就意味着告诉Java编译器,我这个方法不需要创建一个此类的对象即可使用。你还得你是怎么运行这个程序吗?一般,我们都是在命令行下,打入如下的命令(加下划线为手动输入):

javac Hello.java
java Hello
Hello,world!

  这就是你运行的过程,第一行用来编译Hello.java这个文件,执行完后,如果你查看当前,会发现多了一个Hello.class文件,那就是第一行产生的Java二进制字节码。第二行就是执行一个Java程序的最普遍做法。执行结果如你所料。在2中,你可能会想,为什么要这样才能输出。好,我们来分解一下这条语句。(如果没有安装Java文档,请到Sun的官方网站浏览J2SE API)首先,System是位于java.lang包中的一个核心类,如果你查看它的定义,你会发现有这样一行:public static final PrintStream out;接着在进一步,点击PrintStream这个超链接,在METHOD页面,你会看到大量定义的方法,查找println,会有这样一行:

public void println(String x)。

  好了,现在你应该明白为什么我们要那样调用了,out是System的一个静态变量,所以可以直接使用,而out所属的类有一个println方法。

静态方法

  通常,在一个类中定义一个方法为static,那就是说,无需本类的对象即可调用此方法。如下所示:


class Simple{
static void go(){
System.out.println("Go...");
}
}
public class Cal{
public static void main(String[] args){
Simple.go();
}
}


  调用一个静态方法就是“类名.方法名”,静态方法的使用很简单如上所示。一般来说,静态方法常常为应用程序中的其它类提供一些实用工具所用,在Java的类库中大量的静态方法正是出于此目的而定义的。


静态变量

  静态变量与静态方法类似。所有此类实例共享此静态变量,也就是说在类装载时,只分配一块存储空间,所有此类的对象都可以操控此块存储空间,当然对于final则另当别论了。看下面这段代码:


class Value{
static int c=0;
static void inc(){
c++;
}
}
class Count{
public static void prt(String s){
System.out.println(s);
}
public static void main(String[] args){
Value v1,v2;
v1=new Value();
v2=new Value();
prt("v1.c="+v1.c+" v2.c="+v2.c);
v1.inc();
prt("v1.c="+v1.c+" v2.c="+v2.c);
}
}


  结果如下:


v1.c=0 v2.c=0
v1.c=1 v2.c=1

  由此可以证明它们共享一块存储区。static变量有点类似于C中的全局变量的概念。值得探讨的是静态变量的初始化问题。我们修改上面的程序:


class Value{
static int c=0;
Value(){
c=15;
}
Value(int i){
c=i;
}
static void inc(){
c++;
}
}
class Count{
public static void prt(String s){
System.out.println(s);
}
Value v=new Value(10);
static Value v1,v2;
static{
prt("v1.c="+v1.c+" v2.c="+v2.c);
v1=new Value(27);
prt("v1.c="+v1.c+" v2.c="+v2.c);
v2=new Value(15);
prt("v1.c="+v1.c+" v2.c="+v2.c);
}
public static void main(String[] args){
Count ct=new Count();
prt("ct.c="+ct.v.c);
prt("v1.c="+v1.c+" v2.c="+v2.c);
v1.inc();
prt("v1.c="+v1.c+" v2.c="+v2.c);
prt("ct.c="+ct.v.c);
}
}


运行结果如下:


v1.c=0 v2.c=0
v1.c=27 v2.c=27
v1.c=15 v2.c=15
ct.c=10
v1.c=10 v2.c=10
v1.c=11 v2.c=11
ct.c=11

  这个程序展示了静态初始化的各种特性。如果你初次接触Java,结果可能令你吃惊。可能会对static后加大括号感到困惑。首先要告诉你的是,static定义的变量会优先于任何其它非static变量,不论其出现的顺序如何。正如在程序中所表现的,虽然v出现在v1和v2的前面,但是结果却是v1和v2的初始化在v的前面。在static{后面跟着一段代码,这是用来进行显式的静态变量初始化,这段代码只会初始化一次,且在类被第一次装载时。如果你能读懂并理解这段代码,会帮助你对static关键字的认识。在涉及到继承的时候,会先初始化父类的static变量,然后是子类的,依次类推。非静态变量不是本文的主题,在此不做详细讨论,请参考Think in Java中的讲解。

静态类

  通常一个普通类不允许声明为静态的,只有一个内部类才可以。这时这个声明为静态的内部类可以直接作为一个普通类来使用,而不需实例一个外部类。如下代码所示:


public class StaticCls{
public static void main(String[] args){
OuterCls.InnerCls oi=new OuterCls.InnerCls();
}
}
class OuterCls{
public static class InnerCls{
InnerCls(){
System.out.println("InnerCls");
}
}
}


  输出结果会如你所料:


InnerCls

  和普通类一样。内部类的其它用法请参阅Think in Java中的相关章节,此处不作详解。

二、this & super

  在上一篇拙作中,我们讨论了static的种种用法,通过用static来定义方法或成员,为我们编程提供了某种便利,从某种程度上可以说它类似于C语言中的全局函数和全局变量。但是,并不是说有了这种便利,你便可以随处使用,如果那样的话,你便需要认真考虑一下自己是否在用面向对象的思想编程,自己的程序是否是面向对象的。好了,现在开始讨论this&super这两个关键字的意义和用法。

  在Java中,this通常指当前对象,super则指父类的。当你想要引用当前对象的某种东西,比如当前对象的某个方法,或当前对象的某个成员,你便可以利用this来实现这个目的,当然,this的另一个用途是调用当前对象的另一个构造函数,这些马上就要讨论。如果你想引用父类的某种东西,则非super莫属。由于this与super有如此相似的一些特性和与生俱来的某种关系,所以我们在这一块儿来讨论,希望能帮助你区分和掌握它们两个。

在一般方法中

  最普遍的情况就是,在你的方法中的某个形参名与当前对象的某个成员有相同的名字,这时为了不至于混淆,你便需要明确使用this关键字来指明你要使用某个成员,使用方法是“this.成员名”,而不带this的那个便是形参。另外,还可以用“this.方法名”来引用当前对象的某个方法,但这时this就不是必须的了,你可以直接用方法名来访问那个方法,编译器会知道你要调用的是那一个。下面的代码演示了上面的用法:


public class DemoThis{
private String name;
private int age;
DemoThis(String name,int age){
setName(name); //你可以加上this来调用方法,像这样:this.setName(name);但这并不是必须的
setAge(age);
this.print();
}
public void setName(String name){
this.name=name;//此处必须指明你要引用成员变量
}
public void setAge(int age){
this.age=age;
}
public void print(){
System.out.println("Name="+name+" Age="+age);//在此行中并不需要用this,因为没有会导致混淆的东西
}
public static void main(String[] args){
DemoThis dt=new DemoThis("Kevin","22");
}
}


  这段代码很简单,不用解释你也应该能看明白。在构造函数中你看到用this.print(),你完全可以用print()来代替它,两者效果一样。下面我们修改这个程序,来演示super的用法。

class Person{
public int c;
private String name;
private int age;
protected void setName(String name){
this.name=name;
}
protected void setAge(int age){
this.age=age;
}
protected void print(){
System.out.println("Name="+name+" Age="+age);
}
}
public class DemoSuper extends Person{
public void print(){
System.out.println("DemoSuper:");
super.print();
}
public static void main(String[] args){
DemoSuper ds=new DemoSuper();
ds.setName("kevin");
ds.setAge(22);
ds.print();
}
}


  在DemoSuper中,重新定义的print方法覆写了父类的print方法,它首先做一些自己的事情,然后调用父类的那个被覆写了的方法。输出结果说明了这一点:


DemoSuper:
Name=kevin Age=22

  这样的使用方法是比较常用的。另外如果父类的成员可以被子类访问,那你可以像使用this一样使用它,用“super.父类中的成员名”的方式,但常常你并不是这样来访问父类中的成员名的。

在构造函数中

  构造函数是一种特殊的方法,在对象初始化的时候自动调用。在构造函数中,this和super也有上面说的种种使用方式,并且它还有特殊的地方,请看下面的例子:


class Person{
public static void prt(String s){
System.out.println(s);
}
Person(){
prt("A Person.");
}
Person(String name){
prt("A person name is:"+name);
}
}
public class Chinese extends Person{
Chinese(){
super(); //调用父类构造函数(1)
prt("A chinese.");//(4)
}
Chinese(String name){
super(name);//调用父类具有相同形参的构造函数(2)
prt("his name is:"+name);
}
Chinese(String name,int age){
this(name);//调用当前具有相同形参的构造函数(3)
prt("his age is:"+age);
}
public static void main(String[] args){
Chinese cn=new Chinese();
cn=new Chinese("kevin");
cn=new Chinese("kevin",22);
}
}


  在这段程序中,this和super不再是像以前那样用“.”连接一个方法或成员,而是直接在其后跟上适当的参数,因此它的意义也就有了变化。super后加参数的是用来调用父类中具有相同形式的构造函数,如1和2处。this后加参数则调用的是当前具有相同参数的构造函数,如3处。当然,在Chinese的各个重载构造函数中,this和super在一般方法中的各种用法也仍可使用,比如4处,你可以将它替换为“this.prt”(因为它继承了父类中的那个方法)或者是“super.prt”(因为它是父类中的方法且可被子类访问),它照样可以正确运行。但这样似乎就有点画蛇添足的味道了。


  最后,写了这么多,如果你能对“this通常指代当前对象,super通常指代父类”这句话牢记在心,那么本篇便达到了目的,其它的你自会在以后的编程实践当中慢慢体会、掌握。另外关于本篇中提到的继承,请参阅相关Java教程。

三、final

  final在Java中并不常用,然而它却为我们提供了诸如在C语言中定义常量的功能,不仅如此,final还可以让你控制你的成员、方法或者是一个类是否可被覆写或继承等功能,这些特点使final在Java中拥有了一个不可或缺的地位,也是学习Java时必须要知道和掌握的关键字之一。

final成员

  当你在类中定义变量时,在其前面加上final关键字,那便是说,这个变量一旦被初始化便不可改变,这里不可改变的意思对基本类型来说是其值不可变,而对于对象变量来说其引用不可再变。其初始化可以在两个地方,一是其定义处,也就是说在final变量定义时直接给其赋值,二是在构造函数中。这两个地方只能选其一,要么在定义时给值,要么在构造函数中给值,不能同时既在定义时给了值,又在构造函数中给另外的值。下面这段代码演示了这一点:


import java.util.List;
import java.util.ArrayList;
import java.util.LinkedList;
public class Bat{
final PI=3.14; //在定义时便给址值
final int i; //因为要在构造函数中进行初始化,所以此处便不可再给值
final List list; //此变量也与上面的一样
Bat(){
i=100;
list=new LinkedList();
}
Bat(int ii,List l){
i=ii;
list=l;
}
public static void main(String[] args){
Bat b=new Bat();
b.list.add(new Bat());
//b.i=25;
//b.list=new ArrayList();
System.out.println("I="+b.i+" List Type:"+b.list.getClass());
b=new Bat(23,new ArrayList());
b.list.add(new Bat());
System.out.println("I="+b.i+" List Type:"+b.list.getClass());
}
}


  此程序很简单的演示了final的常规用法。在这里使用在构造函数中进行初始化的方法,这使你有了一点灵活性。如Bat的两个重载构造函数所示,第一个缺省构造函数会为你提供默认的值,重载的那个构造函数会根据你所提供的值或类型为final变量初始化。然而有时你并不需要这种灵活性,你只需要在定义时便给定其值并永不变化,这时就不要再用这种方法。在main方法中有两行语句注释掉了,如果你去掉注释,程序便无法通过编译,这便是说,不论是i的值或是list的类型,一旦初始化,确实无法再更改。然而b可以通过重新初始化来指定i的值或list的类型,输出结果中显示了这一点:


I=100 List Type:class java.util.LinkedList
I=23 List Type:class java.util.ArrayList

  还有一种用法是定义方法中的参数为final,对于基本类型的变量,这样做并没有什么实际意义,因为基本类型的变量在调用方法时是传值的,也就是说你可以在方法中更改这个参数变量而不会影响到调用语句,然而对于对象变量,却显得很实用,因为对象变量在传递时是传递其引用,这样你在方法中对对象变量的修改也会影响到调用语句中的对象变量,当你在方法中不需要改变作为参数的对象变量时,明确使用final进行声明,会防止你无意的修改而影响到调用方法。
另外方法中的内部类在用到方法中的参变量时,此参变也必须声明为final才可使用,如下代码所示:


public class INClass{
void innerClass(final String str){
class IClass{
IClass(){
System.out.println(str);
}
}
IClass ic=new IClass();
}
public static void main(String[] args){
INClass inc=new INClass();
inc.innerClass("Hello");
}
}


final方法


  将方法声明为final,那就说明你已经知道这个方法提供的功能已经满足你要求,不需要进行扩展,并且也不允许任何从此类继承的类来覆写这个方法,但是继承仍然可以继承这个方法,也就是说可以直接使用。另外有一种被称为inline的机制,它会使你在调用final方法时,直接将方法主体插入到调用处,而不是进行例行的方法调用,例如保存断点,压栈等,这样可能会使你的程序效率有所提高,然而当你的方法主体非常庞大时,或你在多处调用此方法,那么你的调用主体代码便会迅速膨胀,可能反而会影响效率,所以你要慎用final进行方法定义。

final类

  当你将final用于类身上时,你就需要仔细考虑,因为一个final类是无法被任何人继承的,那也就意味着此类在一个继承树中是一个叶子类,并且此类的设计已被认为很完美而不需要进行修改或扩展。对于final类中的成员,你可以定义其为final,也可以不是final。而对于方法,由于所属类为final的关系,自然也就成了final型的。你也可以明确的给final类中的方法加上一个final,但这显然没有意义。

  下面的程序演示了final方法和final类的用法:


final class final{
final String str="final Data";
public String str1="non final data";
final public void print(){
System.out.println("final method.");
}
public void what(){
System.out.println(str+"
"+str1);
}
}
public class FinalDemo { //extends final 无法继承
public static void main(String[] args){
final f=new final();
f.what();
f.print();
}
}


  从程序中可以看出,final类与普通类的使用几乎没有差别,只是它失去了被继承的特性。final方法与非final方法的区别也很难从程序行看出,只是记住慎用。


final在设计模式中的应用

  在设计模式中有一种模式叫做不变模式,在Java中通过final关键字可以很容易的实现这个模式,在讲解final成员时用到的程序Bat.java就是一个不变模式的例子。如果你对此感兴趣,可以参考阎宏博士编写的《Java与模式》一书中的讲解。

  到此为止,this,static,supert和final的使用已经说完了,如果你对这四个关键字已经能够大致说出它们的区别与用法,那便说明你基本已经掌握。然而,世界上的任何东西都不是完美无缺的,Java提供这四个关键字,给程序员的编程带来了很大的便利,但并不是说要让你到处使用,一旦达到滥用的程序,便适得其反,所以在使用时请一定要认真考虑。

 

posted @ 2007-03-31 23:13 Joinclass Inc 阅读(474) | 评论 (0)编辑 收藏
 
本文将告诉你学习Java需要达到的30个目标,希望能够对你的学习有所帮助。对比一下自己,你已经掌握了这30条中的多少条了呢?
  1.你需要精通面向对象分析与设计(OOA/OOD)、涉及模式(GOF,J2EEDP)以及综合模式。你应该十分了解UML,尤其是class,object,interaction以及statediagrams。
  2.你需要学习JAVA语言的基础知识以及它的核心类库(collections,serialization,streams,networking, multithreading,reflection,event,handling,NIO,localization,以及其他)。
  3.你应该了解JVM,classloaders,classreflect,以及垃圾回收的基本工作机制等。你应该有能力反编译一个类文件并且明白一些基本的汇编指令。
  4.如果你将要写客户端程序,你需要学习WEB的小应用程序(applet),必需掌握GUI设计的思想和方法,以及桌面程序的SWING,AWT, SWT。你还应该对UI部件的JAVABEAN组件模式有所了解。JAVABEANS也被应用在JSP中以把业务逻辑从表现层中分离出来。
  5.你需要学习java数据库技术,如JDBCAPI并且会使用至少一种persistence/ORM构架,例如Hibernate,JDO, CocoBase,TopLink,InsideLiberator(国产JDO红工厂软件)或者iBatis。
  6.你还应该了解对象关系的阻抗失配的含义,以及它是如何影响业务对象的与关系型数据库的交互,和它的运行结果,还需要掌握不同的数据库产品运用,比如:oracle,mysql,mssqlserver。
  7.你需要学习JAVA的沙盒安全模式(classloaders,bytecodeverification,managers,policyandpermissions,
codesigning, digitalsignatures,cryptography,certification,Kerberos,以及其他)还有不同的安全/认证 API,例如JAAS(JavaAuthenticationandAuthorizationService),JCE (JavaCryptographyExtension),JSSE(JavaSecureSocketExtension),以及JGSS (JavaGeneralSecurityService)。
  8.你需要学习Servlets,JSP,以及JSTL(StandardTagLibraries)和可以选择的第三方TagLibraries。
  9.你需要熟悉主流的网页框架,例如JSF,Struts,Tapestry,Cocoon,WebWork,以及他们下面的涉及模式,如MVC/MODEL2。
  10.你需要学习如何使用及管理WEB服务器,例如tomcat,resin,Jrun,并且知道如何在其基础上扩展和维护WEB程序。
11.你需要学习分布式对象以及远程API,例如RMI和RMI/IIOP。
  12.你需要掌握各种流行中间件技术标准和与java结合实现,比如Tuxedo、CROBA,当然也包括javaEE本身。
  13.你需要学习最少一种的XMLAPI,例如JAXP(JavaAPIforXMLProcessing),JDOM(JavaforXMLDocumentObjectModel),DOM4J,或JAXR(JavaAPIforXMLRegistries)。
  14.你应该学习如何利用JAVAAPI和工具来构建WebService。例如JAX-RPC(JavaAPIforXML/RPC),SAAJ (SOAPwithAttachmentsAPIforJava),JAXB(JavaArchitectureforXMLBinding),JAXM(JavaAPIforXMLMessaging), JAXR(JavaAPIforXMLRegistries),或者JWSDP(JavaWebServicesDeveloperPack)。
  15.你需要学习一门轻量级应用程序框架,例如Spring,PicoContainer,Avalon,以及它们的IoC/DI风格(setter,constructor,interfaceinjection)。
  16.你需要熟悉不同的J2EE技术,例如JNDI(JavaNamingandDirectoryInterface),JMS (JavaMessageService),JTA/JTS(JavaTransactionAPI/JavaTransactionService),JMX (JavaManagementeXtensions),以及JavaMail。
  17.你需要学习企业级JavaBeans(EJB)以及它们的不同组件模式:Stateless/StatefulSessionBeans,EntityBeans(包含Bean- ManagedPersistence[BMP]或者Container-ManagedPersistence[CMP]和它的EJB-QL),或者 Message-DrivenBeans(MDB)。
  18.你需要学习如何管理与配置一个J2EE应用程序服务器,如WebLogic,JBoss等,并且利用它的附加服务,例如簇类,连接池以及分布式处理支援。你还需要了解如何在它上面封装和配置应用程序并且能够监控、调整它的性能。
  19.你需要熟悉面向方面的程序设计以及面向属性的程序设计(这两个都被很容易混淆的缩写为AOP),以及他们的主流JAVA规格和执行。例如AspectJ和AspectWerkz。
  20.你需要熟悉对不同有用的API和frame work等来为你服务。例如Log4J(logging/tracing),Quartz (scheduling),JGroups(networkgroupcommunication),JCache(distributedcaching), Lucene(full-textsearch),JakartaCommons等等。
21.如果你将要对接或者正和旧的系统或者本地平台,你需要学习JNI (JavaNativeInterface) and JCA (JavaConnectorArchitecture)。
  22.你需要熟悉JINI技术以及与它相关的分布式系统,比如掌握CROBA。
  23.你需要JavaCommunityProcess(JCP)以及他的不同JavaSpecificationRequests(JSRs),例如Portlets(168),JOLAP(69),DataMiningAPI(73),等等。
  24.你应该熟练掌握一种JAVAIDE例如sunOne,netBeans,IntelliJIDEA或者Eclipse。(有些人更喜欢VI或EMACS来编写文件。随便你用什么了:)
  25.JAVA(精确的说是有些配置)是冗长的,它需要很多的人工代码(例如EJB),所以你需要熟悉代码生成工具,例如XDoclet。
  26.你需要熟悉一种单元测试体系(JNunit),并且学习不同的生成、部署工具(Ant,Maven)。
  27.你需要熟悉一些在JAVA开发中经常用到的软件工程过程。例如RUP(RationalUnifiedProcess)andAgilemethodologies。
  28.你需要能够深入了解加熟练操作和配置不同的操作系统,比如GNU/linux,sunsolaris,macOS等,做为跨平台软件的开发者。
  29.你还需要紧跟java发展的步伐,比如现在可以深入的学习javaME,以及各种java新规范,技术的运用,如新起的web富客户端技术。
  30.你必需要对opensource有所了解,因为至少java的很多技术直接是靠开源来驱动发展的,如java3D技术。
posted @ 2007-03-31 23:08 Joinclass Inc 阅读(405) | 评论 (0)编辑 收藏
 
35岁是青春的后期,35岁以后是收获的季节,如果你没有资格说这句话,你将会憎恨自己。所以在35岁以前,在烂漫蓬勃的青春年华里,你最好把下面十件事做好:
  
  第一,学会本行业所需要的一切知识并有所发展。已故零件大王布鲁丹在他35岁时,已经成为零件行业的领袖,并且组建了年收入达千万美元的海湾与西部工业公司。每个人在年轻时都可能有过彻夜不眠、刻苦攻读,这在20岁甚或30岁都没有问题,但到了35岁,就不应该再为学习基本技能而大伤脑筋了。35岁之前是一个人从事原始积累的阶段,35岁之后就应该勃发了。
  
  第二,养成个人风格。在35岁以前,找出你所喜欢的,不论是衣着或是爱好,哪怕是与众不同的小习惯也好。20岁、30岁时你可以不断尝试、不断改变,但是到了35岁,你便要明确地建立个人风格。一位男士或女士在事业中途改变自己的形象,就会让人觉得很不可靠。你喜欢穿西装吗?好!就把西装当作你的商标吧!办公桌上摆些鲜花会令你工作更有效率吗?那就每天都摆些鲜花吧!
  
  第三,在感情生活方面平和安定。在攀登事业的高峰时,如果私人生活不愉快,陷入感情危机,对你会产生很大的干扰,甚至会逐渐令你对别的事物失去兴趣。那些在35岁之前私人生活已经平和安定的人,一般都比生活动荡不安的人有更大的机会获得成功。因此,如果你想结束一段没有结果的恋情,或者你想和女友结婚,那就赶快行动吧,免得把问题拖到生命的第35个春秋。在35岁以后,你应该专注地看着你对事业的投资开始获利。
  
  第四,明白自己的短处。承认有些事情你的确做不好,或者不愿做。如果你讨厌数字而喜欢创作,那就不要因为待遇高或顺从别人的期望而强迫自己做数字工作。在35岁之前,一定要投入你所喜爱、所擅长的那种工作。否则,35岁之后必然会有一段郁郁不乐的日子。而且,真正的成功可能因为活力的消退而丧失。
  
  第五,知道自己的长处。你应该知道自己擅长什么,并且清楚你所喜欢做而又做得比别人好的事情。不管你目前担任什么样的角色,知道自己的长处对成功都很重要。
  
  第六,储备辞职另谋生路的钱。在这个多变的职业世界里,你也许不会永远在一个地方工作,或者永远在一个位置上淋漓尽致地发挥自己,当你感到无法施展时,你很可能会想到辞职,或者开辟第二职业,如果你事先储蓄了足够的钱,你便有了一个安全的后盾。
  
  第七,建立人际关系网。如果到了35岁你仍未建立起牢固的人际关系网,那你就有麻烦了。这个人际关系网包括你的朋友、亲人,最低限度包括所有可以互相帮助的人。这些人有的是你的同事,有的受过你的恩惠,有的你倾听过他们的问题,有的你和他有着相同的爱好。人际关系网不是一朝一夕就能建立起来的,它需要几年甚至十几年的培养。一个人在事业上、生活上的成功其实如同一个政党的成功,你要有许多人散布在适当的地方,你可以依赖他们,他们也可以依赖你。
  
  第八,学会授权他人。许多人不肯或不能这样做,因此始终被钉在从属的职位上。授权他人是成功的一半,一个事无巨细,不能将工作授权别人的人,注定会遇到极大的障碍。到了35岁,你最好已成为这方面的专家。换言之,你懂得挑选合适的人并信任他们。
  
  第九,学会在什么时候三缄其口。因说话不小心而自毁前程的人,比因为任何其他原因丧失成功的人都多。要学会保持沉默而且看起来机智--别人自然以为你知道的比实际还多。别讲别人的闲话,别谈论你自己的大计,守口如瓶所赢得的声誉,远比讲人闲话所带来的东西更加珍贵。你在事业上越成功,这一点就越重要。
  
  第十,对人要忠诚。如果你到了35岁仍未能建立起坚如磐石的忠诚信誉,这一缺点将会困扰你一生。不忠诚的恶名必然会使你在事业上到处不受欢迎。你不能靠暗箭伤人爬到事业的顶峰,而要靠在早期树立起来的真诚刚直和不可动摇的声誉。35岁以前,忠诚只是投资;35岁以后,你会作为一个可以信赖的人收到忠诚的回报。
posted @ 2007-03-30 13:25 Joinclass Inc 阅读(280) | 评论 (1)编辑 收藏
 
昨天, Eclipse官方发布了Eclipse 3.3 M6版本.新版本基于Windows Presentation Foundation平台, 同时增加了Vista的本地化特性, 支持JavaXPCOM, 更好支持OLE等等.+WPF (Windows Presentation Foundation)+Native features on Vista (win32)+JavaXPCOM support.

昨天, Eclipse官方发布了Eclipse 3.3 M6版本.

新版本基于Windows Presentation Foundation平台, 同时增加了Vista的本地化特性, 支持JavaXPCOM, 更好支持OLE等等.

新版本的特性包括:

+WPF (Windows Presentation Foundation)
+Native features on Vista (win32)
+JavaXPCOM support


+OLEExample and OLE improvements


+Reparenting support on Mac OSX
+Display.post() supports more mouse events
+Advanced graphics supports mirroring
......
等等

更多特性参考官方站点

Eclipse 3.3 M6官方下载:
http://download.eclipse.org/eclipse/downloads/drops/S-3.3M6-200703231616/index.php

原文链接:http://www.matrix.org.cn/resource/news/Eclipse3.3+M6_abe8355e-db2b-11db-9bed-29012b8c745e.html

posted @ 2007-03-27 09:28 Joinclass Inc 阅读(1103) | 评论 (5)编辑 收藏
 
从前,有一个脾气很坏的男孩.他的爸爸给了他一袋钉子,告诉他,每次发脾气或者跟人吵架的时候,就在院子的篱笆上钉一根。第一天,男孩钉了37根钉子。后面的几天他学会了控制自己的脾气,每天钉的钉子也逐渐减少了。他发现,控制自己的脾气,实际上比钉钉子要容易的多。终于有一天,他一根钉子都没有钉,他高兴的把这件事告诉了爸爸。
  爸爸说:"从今以后,如果你一天都没有发脾气,就可以在这天拔掉一根钉子." 日子一天一天过去,最后,钉子全被拔光了。爸爸带他来到篱笆边上,对他说:"儿子,你做得很好,可是看看篱笆上的钉子洞,这些洞永远也不可能恢复了。就象你和一个人吵架,说了些难听的话,你就在他心里留下了一个伤口,像这个钉子洞一样。"插一把刀子在一个人的身体里,再拔出来,伤口就难以愈合了。无论你怎么道歉,伤口总是在那儿。要知道,身体上的伤口和心灵上的伤口一样都难以恢复。你的朋友是你宝贵的财产,他们让你开怀,让你更勇敢。他们总是随时倾听你的忧伤。你需要他们的时候,他们会支持你,向你敞开心扉。"告诉你的朋友你多么爱他们,告诉所有你认为是朋友的人,你的行动可以从邮寄这个小小的故事开始。有一天,当这封信回到你的信箱里时。你会发现你有一个很大的朋友圈.
  
  最后,我要说:"友谊的幸福之一,是知道了可以向谁倾吐秘密。"如果你收到了这封信,是因为有人在默默的祝福你,因为你也爱你身边的一些人。如果你总说太忙,不能将这封信转寄出去,老是说:"改天再寄。"你将永远都不会去做这件事的。所以,不要找借口,静心的看看这篇古老印度来的故事,然后决定为你的朋友们作一些事,从传寄这封信开始。当你说:"你是我的好朋友"时,请认真的说出来。当你道歉时请看着对方的眼睛。
  永远不要嘲笑别人的梦想。不要随便给一个人定性。说话时要慢,思想时要快。
  打电话的时候请你微笑,对方一定感觉得到。
  这是一个朋友转发给我的信。常常收到类似的让我继续转发的邮件,号称如果这样做了就会发财之类,通常我会把自己作为终点,但是这封信打动了我,因为它说:"收到了这封信,是因为有人在默默的祝福你,因为你也爱你身边的一些人"。带着爱的,一切将如愿以偿。
  这是一封给你送上好运的信,它始于新英格兰。此信的复制由南非教区主教索尔安东尼起草并由维尼乌拉发出,已经绕地球转了十次。现在好运已降临到你身上,只要你照办,将此信网址复制2O份分别寄给亲朋好友或QQ上的朋友,使它在世界各地周转,你将在四天内交到好运,这不是在开玩笑,不需要寄钱,因为幸运是无代价的。
  朋友本不该有那么重要,朋友又的确那么重要。生命里或许可以没有感动、没有胜利...没有其他的东西,但不能没有的是朋友。
朋友是可以一起打着伞在雨中漫步;是可以一起在海边沙滩上打个滚儿;是可以一起沉溺于某种音乐遐思;是可以一起徘徊于书海畅游;朋友是有悲伤我陪你一起掉眼泪,有欢乐我和你一起傻傻的笑……
朋友不一定常常联系,但也不会忘记,每次偶尔念起,还是感觉那么温暖、那么亲切、那么柔情;朋友是把关怀放在心里,把关注藏在眼底;朋友是相伴走过一段又一段的人生,携手共度一个又一个黄昏;朋友是想起时平添喜悦,忆及时更多温柔。 朋友如醇酒,味浓而易醉;朋友如花香,淡雅且芬芳;朋友是秋天的雨,细腻又满怀诗意;
朋友是十二月的梅,纯洁又傲然挺立。朋友不是画,它比画更绚丽;朋友不是歌,它比歌更动听;朋友应是那意味深长的散文,写过昨天又期待未来。
朋友的美不在来日方长;朋友最真是瞬间永恒、相知刹那;朋友的可贵不是因为曾一同走过的岁月,朋友最难得是分别以后依然会时时想起,依然能记得:你,是我的朋友。
有朋友的日子里总是阳光灿烂,花朵鲜艳;有朋友的时候才发现自己已经拥有了一切。我们可以失去很多,但不能失去的是朋友。朋友也许并不能成为一段永恒,朋友也许只是你生命中某段时间的一个过客,但因为这份缘起缘灭,更使生命变得美丽起来,朋友的情感更加生动和珍贵。即使没有将来又有何妨?至少,曾经我与你一起走过朋友的路。
你看到了吗?我在默默的祝福你。*^_^*  *^_^*  *^_^*

posted @ 2007-03-26 14:09 Joinclass Inc 阅读(1090) | 评论 (2)编辑 收藏
 
posted @ 2007-03-19 21:22 Joinclass Inc 阅读(311) | 评论 (0)编辑 收藏
 
posted @ 2007-03-19 20:55 Joinclass Inc 阅读(314) | 评论 (0)编辑 收藏
 

2007 年 2 月 28 日

SVK 是一个基于 Subversion 构造的分布式的版本控制系统。通常的集中式管理系统,如 CVS,Subversion 已经得到广泛应用,但是集中式的管理存在相应的缺陷,例如对唯一的版本库过分依赖:一旦不能正常连接到集中式的版本库,整个系统陷入瘫痪。SVK 最大的能力就在于可以维护分布式的版本库,分散的开发人员可以通过 SVK 建立远程的 CVS,Subversion,P4 协议的版本库镜像,选择工作在自己合适的镜像版本库,这个镜像甚至可以是本地的,整个工作可以离线进行,然后在需要的时候同步镜像版本库到主版本库。

前言

SVK 在大部分的操作与设计思想上都与 Subversion 相似,本文假定读者对 Subversion 有一定的了解,将着重介绍 SVK 新增特性与功能,与 Subversion 重叠的部分就不再赘述。读者可以参考作者的另外一篇 关于 Subversion 的文章

历史

版本管理工具的历史由来已久,CVS 作为标准的版本管理控制工具已经得到了广泛应用。为改善 CVS 天生的缺陷,CollabNet 开发了 Subversion。Subversion 在目录版本化、原子提交、元数据、分支和标签等方面有了极大的改进,但遗憾的是它仍然是集中式的版本管理工具。不过幸运的是,由于 Subversion 灵活的设计,重用 Subversion 已有组件并扩展其功能成为了现实,SVK 就是这样一个基于 Subversion 的扩展实现。高嘉良先生一年时间的全职工作使 SVK 顺利诞生了。目前 SVK 项目已经被 Bestpractical 收录,读者可以访问其官方主页(请参阅 参考资源)。

License

SVK 是基于 Artistic License 发布的。Artistic License 目前基本被用于标准 Perl,CPAN 组件以及 Parrot 软件上。详细信息请参阅 参考资源

安装

SVK 由一组基于 SVN 的 Perl 绑定的 Perl5 的模块构成。Subversion 本身是构建于 Apache APR 之上,因此 SVK 可以在任何支持 Apache Http Server 的操作系统上运行,包括 Windows、Linux、Mac OS、Free BSD 以及 Netware。

最简单的安装方式是直接下载对应操作系统的的二进制版本。Windows 版本可以在 这里 找到,Linux 系统上也可以使用 deb 或者 rpm 的安装方式。目前 Cpan 已经提供有 2.0 版本的安装,通过 cpan 的安装方式如下:

首先需要安装 Subversion 的 Perl 绑定,cpan 没有提供这一模块,如果安装 Subversion 的时候没有选择安装 Perl 绑定则需要重新配置及安装 Subversion。

安装 Subversion 的 Perl 绑定需要 swig 的支持,swig 是 C/C++ 软件与其他高级语言的连接器,关于 swig 请参考http://www.swig.org/

安装 swig

下载 swig1.3.24 以上版本(需要 Perl 5.8.0 以上版本支持),解压后在 SWIG-1.3.xx 目录下运行如下命令,其中 /path/to/correct/perl/binary 应当指向 Perl 的可执行文件:

验证安装
可以用 swig --version 来验证安装是否成功。
./configure --with-perl5=/path/to/correct/perl/binary
make
make install

配置 Subversion

成功安装了 swig 后便可以安装 subverion 的 perl 绑定了,在 Subversion 源代码目录下运行如下命令:

验证安装
如果 Subversion 的 configure 找到了合适的 swig,将会生成名为 libsvn_swig_perl.so 的库文件。
./configure PERL=/path/to/correct/perl/binary

安装 Subversion 的 perl 绑定

make
make swig-pl
make check-swig-pl
make install
make install-swig-pl

通过 cpan 安装 SVK

通过如下命令,cpan 会自动寻找并提示安装所有相关模块。

>cpan
cpan> install SVK

如果全部安装成功。在命令行敲入 svk 便会得到如下的 SVK 帮助信息:

获取帮助

svk help commands 将会列出所有 SVK 支持的子命令。

对于某个特定的命令如 update,svk help update 将会得到关于 update 的说明。

svk help environment 将会列出所有与 SVK 相关的环境变量。

SVK Documentation - Main index:

If this is your first time using SVK, you should start by reading a
brief tutorial. When you're ready, type:

    svk help intro

Once you've done that, more in-depth help is available:

    svk help environment    Environment variables that alter svk's behavior
    svk help commands       A list of all available commands
    svk help view           svk view support
    svk help <command-name> Help for a specific command

For commercial support, contact sales@bestpractical.com. For up to date
information about SVK, visit http://svk.bestpractical.com/.

如果想要体验最新的版本,可以直接从 SVK 的版本库取出最新的源代码进行编译安装:

Perl 绑定安装部分同前述。

svn co http://code.bestpractical.com/svk/trunk/
cd trunk/
perl Makefile.PL
make
make test
make install
svk







新功能

相较于 Subversion 而言,SVK 增加了许多强劲的功能。

Depot

首先介绍一个新概念—— Depot,它是 SVK 进行版本管理的核心。SVK 使用 Subversion 的版本库实现 Depot。对本地 Depot 的引用是使用"//",由于它完全是 Subversion 兼容的,因此用户也可以很方便的将 Depot 通过 svnserve 或者 http 方式发布到网络上。

Patch

在 Subversion 中,用户可以使用重定向 svn diff 的输出来生成 patch 文件:

svn diff foo > patch.diff

在 SVK 中补丁的功能得到了加强。用户可以通过 commit 以及 smerge 中的 -P(--patch) 选项来创建补丁:

svk commit -m "this is log" --patch patch_name
svk smerge //foo //bar --patch patch_name

创建的补丁将存储在 Depot 同一目录下的 patch 子目录中,用户可以将这一补丁传递给其他用户使用。

同时 SVK 的补丁功能支持对二进制文件的补丁操作,例如:

touch foo
zip foo.zip foo
svk add foo.zip
svk commit -m "this is log" foo.zip --patch patch_name

生成补丁内容如下

==== Patch <patch_name> level 1
Source: [No source]
Target: 9bbf3572-454d-844a-a388-5e5c8078394f:/tony:1
        (http://localhost/repos)
Log:
this is log
=== foo.zip
==================================================================
Cannot display: file marked as a binary type.

Property changes on: foo.zip
___________________________________________________________________
Name: svn:mime-type
 +application/octet-stream


==== BEGIN SVK PATCH BLOCK ====
Version: svk v2.0.0 (MSWin32)

eJxNks1qE1EUx6c1qWIptMFqcaFFpoKLsXM/5iMphqhJKgY10EQUF5ObmZtkZDIzTm6DLVfIaKjF
J9AHENworly57EJbcO8LuPcFxHunFoRh4HDO/3fOPedfT1obFcDLZZ2rQOdbDxulUpMwd7AmItXk
1PNZlKgGD+iYBiriQdRXMQ/JkIosI0mfsnIZCLF9LK5lghMIlowuYVE4UosZzGEJpSrgsIJ4BXLx
FwEQySimoZNEEVMhN6FIOXIgN4hG1JFCWWzKYqjanHie0/MDqlq8F0XXd/1YUhwh1YBACqnxT+r5
CXXFRDuyQPY0ZNbk7oCEfZpBnDiJ4gwMEB+Nw9LQH1KN7cRUhZiTOA58lzA/Ctcjl1GmjcQTyPAY
ZGT5HYfR58yjASOSI+bQkVjHfUVR0uhqenGvmp/W8puFN9XCxL+TLuw9yqWbhWm1MK1deVVP56f1
869rhWbjVO6scvTitjmj7Cpgq0qVr2eU3Iex43odf5F0Onpnolxe7Xl59LiWHoSfnrxs36vfPfz9
/aez8uwIQKDr4Jz+efJ+beUPOkSTg8rT5cl09q02u9Sf7s+n15b3Vy5t3Pz10Vu8BR4sfZtT2q0F
5fSPGwe1ZmNm9sL80qryJRWdc+1WvtnIz80oFfGGdxX8/zWyxct1IciBbVrIw2bPI8TCwKIGMC2I
u7gIDewhOzsuAJwN/NGq+KR9BCiW7nCki8plyFUIj83TyvxUKrVDf0yTEQnWxMWxrB4I6yV0LILt
bd8TflwXnspuqiKTF7vdHjIsqGHRVLMxJhpBtq0Z1HBt3bJREff+AuTM7ls=
==== END SVK PATCH BLOCK ====

因而通常的patch工具不能支持SVK生成的补丁。SVK 提供了一个 patch 命令来应用补丁,patch 命令包含如下一些常用选项:

svk patch --list|--ls
查看当前所有的补丁
svk patch --cat|--view PATCHNAME
查看某一补丁的内容
svk patch --regenerate|--regen PATCHNAME
重新生成补丁
svk patch --apply PATCHNAME [TARGET] [-- MERGEOPTIONS]
应用补丁
svk patch --delete|--rm PATCHNAME
删除补丁

Mirror

SVK 的镜像功能支持如下流行的版本控制工具:

svk mirror [http|svn]://host/path DEPOTPATH
svk mirror cvs::pserver:user@host:/cvsroot:module/... DEPOTPATH
svk mirror p4:user@host:1666://path/... DEPOTPATH

常用的 mirror 选项包括:

--list (-l)
察看本机上的所有 mirror
--detach (-d)
取消一个 mirror
--relocate
将 mirror 的源路经重定向
--unlock
非正常操作导致 mirror 被锁住可以用这个选项解锁

star-merge(smart-merge)

smerge 是 SVK 的亮点之一,SVK 的核心功能都是围绕其展开的。主要操作选项列举如下:

 -I [--incremental]
 渐进式的合并。它可以忠实地记录源版本库的每一次 commit 操作。
 -B [--baseless]
 用最早的版本作为合并的初始点。一般用户新版本库同步的首次合并。
 -b [--base] BASE 
从指定版本开始合并。一般用于合并已有的版本库分支。
 -s [--sync]
 合并前同步 Depot 与源版本库。
 -P [--patch] NAME
 不进行真实的合并,而是将合并内容生成一个补丁。
 -C [--check-only]
 列举合并的内容而不进行真实的操作。

合并过程中难免会遇到冲突的代码,SVK 提供了一些解决冲突的支持。用 perldoc SVK::Resolve 可以列出合并相关的帮助信息:

NAME

    SVK::Resolve - Interactively resolve conflicts

DESCRIPTION

      Accept:
         a   : Accept the merged/edited file.
         y   : Keep only changes to your file.
         t   : Keep only changes to their file.
      Diff:
         d   : Diff your file against merged file.
         dm  : See merged changes.
         dy  : See your changes alone.
         dt  : See their changes alone.
      Edit:
         e   : Edit merged file with an editor.
         m   : Run an external merge tool to edit merged file.
      Misc:
         s   : Skip this file.
         h   : Print this help message.

      Environment variables:
        EDITOR     : Editor to use for 'e'.
        SVKMERGE   : External merge tool to always use for 'm'.
        SVKRESOLVE : The resolve action to take, instead of asking.


在合并的过程中遇到冲突 SVK 会中断操作并提示用户输入:

e)dit, d)iff, m)erge, s)kip, t)heirs, y)ours, h)elp? [e]

可以选择的操作有编辑当前文件,打印出差异,合并,跳过,保留源端文件以及保留目标端的文件。

选择了 merge 以后 SVK 会自动搜寻可以使用的合并工具:

Multiple merge tools found, choose one:
(to skip this question, set the SVKMERGE environment variable to one of them)
1)GVim, 2)TortoiseMerge, 3)Vim, q)uit?

用户可以使用任何一种合并工具来手动解决冲突。此外 SVK 提供了设定环境变量来定义默认解决冲突的方式,用户可以设定环境变量 SVKRESOLVE 为上述提到的任何一种操作,例如 s(kip),t(heirs),y(ours)。







性能

SVK 在大部分方面具有与 Subversion 相当的性能,而在某些可以离线的操作具有更出色的表现。例如 svk status, svk update 以及 svk switch。

CVS,SVK 以及 Subversion 详细的比较数据见 http://svk.bestpractical.com/view/SVKvsSVNvsCVS







完整的例子

这一部分介绍 SVK 的实际使用。

单独使用

假设有一个远程的版本库 http://remote/repos,用户经常需要离线的工作,则可以使用 SVK 在本地计算机上建立一个远程版本库的镜像 Depot:

svk mirror http://remote/repos //mirror/local

为此镜像做一个拷贝,所有本地工作都在这一拷贝上完成

svk cp //mirror/local //local

从本地 Depot 取出 working copy

svk co //local

在能连接到远程版本库的时候,同步远程的版本库到本地

svk sy //mirror/local
svk pull //local

当然,将 Depot 作为 Subversion 版本库发布出来以后用户便可以脱离 SVK,使用 Subversion 的客户端即可访问。这样一来,所有对版本库的工作都可以在没有网络环境的情况下进行,在将来能够连上网络的时候使用如下命令便将所有在本地的更动反映到远程版本库中去:

svk push //local

版本库同步

现今流行的 Open source 开发模式限制了 committer 的数量,并非所有用户都具有 commit 的权限。假设现有一个远程的版本库 http://remote/repos,数个用户希望能够有权限自由的 commmit,自然的,我们可以利用上述的镜像方法获得一个属于自己的版本库,但是这一版本库必须位于某台服务器上而不是某人的个人电脑上,以使得所有用户都能访问到。如果这个版本库是在一台标准的 Subversion 版本服务器上(假设 URL 是 http://myremote/repos),通常用户对此服务器只有访问 Subversion 版本库的权限,也就是说,用户无法直接在这一台服务器上安装 SVK 而做镜像。SVK 很好的解决了这一问题。我们可以使用任何一台和可以很好的连接上这两台服务器的某一台机器作为中间服务器,定时进行同步,下面是主要操作步骤。

在安装有SVK的中间服务器上进行如下操作:

svk mirror http://remote/repos //remote
svk mirror http://myremote/repos //myremote

分别同步两个 depot 的内容

svk sy //remote
svk sy //myremote

定时从 //remote 同步到 //myremote

svk smerge //remote //myremote

同时本文也提供了一个 Perl 脚本 作为示例,读者可以配置它自动运行并生成 Html 格式的 Report。


图 1: 生成的报告
生成的报告






结束语

SVK 是目前唯一的分布式版本库系统,它成功的对分布式版本库领域进行了有效的探索并获得了成功,它的出现使得以往一些实现起来非常复杂的功能变的十分简单,给一些以往无法完成的操作带来了可能。如 P4,CVS 与 Subversion 版本库的同步与移植,版本库的离线访问,以及远程版本库的镜像和同步等等。期待本文能使更多的读者认识 SVK,并从中获得分布式版本管理的种种便利,使得日常工作更加完美与高效。同时也期待更多的读者与本人交流经验。








下载

描述 名字 大小 下载方法
示例 Perl 脚本 svksync.zip 3KB HTTP
关于下载方法的信息


参考资料



关于作者

吴玥颢的照片

吴玥颢,目前就职于 IBM 中国开发中心 Harmony 开发团队。 除了对 Java 和脚本语言的热爱之外,他的兴趣还包括哲学、神话、历史与篮球。此外他还是个电脑游戏高手。您可以通过wuyuehao

posted @ 2007-03-16 23:05 Joinclass Inc 阅读(539) | 评论 (0)编辑 收藏
 
 http://www.korezu.com 
posted @ 2007-03-13 17:25 Joinclass Inc 阅读(477) | 评论 (0)编辑 收藏
仅列出标题
共6页: 1 2 3 4 5 6 
 
Copyright © Joinclass Inc Powered by: 博客园 模板提供:沪江博客