2005年02月17日

翻译:Cherami

email:cherami@163.net

原文: http://java.sun.com/jdc/TechTips/2000/tt1205.html

 

想像一下你正在用java写程序,并且用下面的代码初始化类 A B 的对象:

    class A {

        int a = f();

        int f() {

            return 1;

        }

    }  

    class B extends A {

        int b = a;

        int f() {

            return 2;

        }

    }   

    public class CtorDemo1 {

        public static void main(String args[]) {

            B bobj = new B();

            System.out.println(bobj.b);

        }

    }

 

现在,好像很明显的当初始化完成后,bobj.b的值将是1。毕竟,类B中的b 的值是用类A中的a的值初始化的,而a 是用f 的值初始化的,而它的值为1,对吗?

实际上, bobj.b 的值是2,要知道为什么需要知道对象初始化的问题。

当一个对象被创建时,初始化是以下面的顺序完成的:

1.         设置成员的值为缺省的初始值 (0, false, null)

2.         调用对象的构造方法 (但是还没有执行构造方法体)

3.         调用父类的构造方法

4.         使用初始化程序和初始块初始化成员

5.         执行构造方法体

 

看看在实际中是如何一步一步完成的,看看下面的例子:

    class A {

        A() {

            System.out.println(“A.A called”);

        }

    }

   

    class B extends A {

        int i = f();

        int j;

   

        {

            j = 37;

            System.out.println(“initialization block executed”);

        }

   

        B() {

            System.out.println(“B.B called”);

        }

   

        int f() {

            System.out.println(“B.f called”);

            return 47;

        }

    }

   

    public class CtorDemo2 {

        public static void main(String args[]) {

            B bobj = new B();

        }

    }

 

程序的输出是:

 

    A.A called

    B.f called

    initialization block executed

    B.B called

 

B 的构造方法被调用,但是最先做的事情是隐含的调用父类的构造方法。父类必须自己负责初始化它自己的状态而不是让子类来做。

然后B对象的成员被初始化,这包含一个对B.f 的调用和包围在{}中的初始块的执行。最后B的构造方法体被执行。

你可能会问“什么是对父类的构造方法的隐含调用”。这意味着如果你的构造方法的第一行不是下面内容之一:

 

   super();

 

   super(args);

 

   this();

 

   this(args);

 

则有下面的调用:

 

   super();

 

提供给构造方法的第一行。

 

如果类没有构造方法呢?在这种情况下,一个缺省的构造方法(也叫无参构造方法“)java编译器自动生成。缺省构造方法只有在类没有任何其它的构造方法时才产生。

更深入的明白这个,假设在文件A.java中有这样的代码:

 

    public class A {

        public static void main(String args[]) {

            A aref = new A();

        }

    }

 

如果你想编译然后列出A.class 中的字节码,输入下面的内容:

 

    $ javac A.java

    $ javap -c -classpath . A

 

输出:

 

    Compiled from A.java

    public class A extends java.lang.Object {

        public A();

        public static void main(java.lang.String[]);

    }

   

    Method A()

       0 aload_0

       1 invokespecial #1 <Method java.lang.Object()>

       4 return

   

    Method void main(java.lang.String[])

       0 new #2 <Class A>

       3 dup

       4 invokespecial #3 <Method A()>

       7 astore_1

       8 return

 

main 中,注意对 A 的构造方法的调用(就是invokespecial ),以及A的构造方法中产生的类似的对Object 构造方法的调用。

如果父类没有缺省构造方法,你必须明确使用“super(args)”调用父类的某个构造方法,例如,下面是一个错误的用法:

 

    class A {

        A(int i) {}

    }

 

    class B extends A {}

 

在上面的情况下, A 没有缺省的构造方法,但是B的构造方法必须调用A的某个构造方法。

让我们来看看初始化的另一个例子:

 

    class A {

        A() {

            System.out.println(“A.A called”);

        }

        A(int i) {

            this();

            System.out.println(“A.A(int) called”);

        }

    }

   

    class B extends A {

        int i = f();

        int j;

   

        {

            j = 37;

            System.out.println(“initialization block executed”);

        }

   

        B() {

            this(10);

            System.out.println(“B.B() called”);

        }

   

        B(int i) {

            super(i);

            System.out.println(“B.B(int) called”);

        }

   

        int f() {

            System.out.println(“B.f called”);

            return 47;

        }

    }

   

    public class CtorDemo3 {

        public static void main(String args[]) {

            B bobj = new B();

        }

    }

 

程序的输出是:

 

    A.A called

    A.A(int) called

    B.f called

    initialization block executed

    B.B(int) called

    B.B() called

 

这个例子明确使用super() this() 调用。this()调用是调用同一个类中的另一个构造方法;这个方法被称为“显式构造方法调用”。当那样的构造方法被调用,它将执行通常的super() 过程以及后续的操作。这意味着A.A 的方法体在A.A(int)之前执行,而这两个都在B.B(int) B.B 前执行。

如果返回第一个例子,你就可以回答为什么打印的是2而不是1B 没有构造方法,因此生成一个缺省构造方法,然后它调用super(),然后调用A 产生的缺省构造方法。

然后A中的成员被初始化,成员a 被设置为方法f()的值,但是因为B 对象正被初始化,f() 返回值2。换句话说,调用的是B中的f()方法。

A产生的构造方法体被执行,然后B的成员被初始化,而b 被赋予值a,也就是2。最后,B的构造方法被执行。

最后一个例子说明了第一个例子的一个小小的变异版本:

 

    class A {

        int a = f();

        int f() {

            return 1;

        }

    }

   

    class B extends A {

        int b = 37;

        int f() {

            return b;

        }

    }

   

    public class CtorDemo4 {

        public static void main(String args[]) {

            B bobj = new B();

            System.out.println(bobj.a);

            System.out.println(bobj.f());

        }

    }

 

程序的输出是:

 

    0

    37

 

你可能会期望输出的两个值bobj.a bobj.f()是一样的,但是正如你看到的他们不一样。这是正确的,即使是在a是从Bf方法中初始化的并且打印的是a B f 方法的值。

这儿的问题是当a通过对Bf方法调用而初始化,而该方法返回成员b的值,而该成员还没有被初始化。因为这个,b的值就是刚开始的初始值0

这些例子解释了编程中重要的一点?D?D在对象的构造阶段调用可重载的方法是不明智的。

2005年02月14日

仙人掌工作室   http://www.ccw.com.cn/htm/app/aprog/01_7_31_4.asp

如果你曾经用过Perl或任何其他内建正则表达式支持的语言,你一定知道用正则表达式处理文本和匹配模式是多么简单。如果你不熟悉这个术语,那么“正则表达式”(Regular Expression)就是一个字符构成的串,它定义了一个用来搜索匹配字符串的模式。

许多语言,包括Perl、PHP、Python、JavaScript和JScript,都支持用正则表达式处理文本,一些文本编辑器用正则表达式实现高级“搜索-替换”功能。那么Java又怎样呢?本文写作时,一个包含了用正则表达式进行文本处理的Java规范需求(Specification Request)已经得到认可,你可以期待在JDK的下一版本中看到它。
然而,如果现在就需要使用正则表达式,又该怎么办呢?你可以从Apache.org下载源代码开放的Jakarta-ORO库。本文接下来的内容先简要地介绍正则表达式的入门知识,然后以Jakarta-ORO API为例介绍如何使用正则表达式。
一、正则表达式基础知识
我们先从简单的开始。假设你要搜索一个包含字符“cat”的字符串,搜索用的正则表达式就是“cat”。如果搜索对大小写不敏感,单词“catalog”、“Catherine”、“sophisticated”都可以匹配。也就是说:
1.1 句点符号
假设你在玩英文拼字游戏,想要找出三个字母的单词,而且这些单词必须以“t”字母开头,以“n”字母结束。另外,假设有一本英文字典,你可以用正则表达式搜索它的全部内容。要构造出这个正则表达式,你可以使用一个通配符——句点符号“.”。这样,完整的表达式就是“t.n”,它匹配“tan”、“ten”、“tin”和“ton”,还匹配“t#n”、“tpn”甚至“t n”,还有其他许多无意义的组合。这是因为句点符号匹配所有字符,包括空格、Tab字符甚至换行符:
1.2 方括号符号
为了解决句点符号匹配范围过于广泛这一问题,你可以在方括号(“[]”)里面指定看来有意义的字符。此时,只有方括号里面指定的字符才参与匹配。也就是说,正则表达式“t[aeio]n”只匹配“tan”、“Ten”、“tin”和“ton”。但“Toon”不匹配,因为在方括号之内你只能匹配单个字符:
1.3 “或”符号
如果除了上面匹配的所有单词之外,你还想要匹配“toon”,那么,你可以使用“|”操作符。“|”操作符的基本意义就是“或”运算。要匹配“toon”,使用“t(a|e|i|o|oo)n”正则表达式。这里不能使用方扩号,因为方括号只允许匹配单个字符;这里必须使用圆括号“()”。圆括号还可以用来分组,具体请参见后面介绍。
1.4 表示匹配次数的符号
表一显示了表示匹配次数的符号,这些符号用来确定紧靠该符号左边的符号出现的次数:

假设我们要在文本文件中搜索美国的社会安全号码。这个号码的格式是999-99-9999。用来匹配它的正则表达式如图一所示。在正则表达式中,连字符(“-”)有着特殊的意义,它表示一个范围,比如从0到9。因此,匹配社会安全号码中的连字符号时,它的前面要加上一个转义字符“\”。

图一:匹配所有123-12-1234形式的社会安全号码

假设进行搜索的时候,你希望连字符号可以出现,也可以不出现——即,999-99-9999和999999999都属于正确的格式。这时,你可以在连字符号后面加上“?”数量限定符号,如图二所示:

图二:匹配所有123-12-1234和123121234形式的社会安全号码

下面我们再来看另外一个例子。美国汽车牌照的一种格式是四个数字加上二个字母。它的正则表达式前面是数字部分“[0-9]{4}”,再加上字母部分“[A-Z]{2}”。图三显示了完整的正则表达式。

图三:匹配典型的美国汽车牌照号码,如8836KV

1.5 “否”符号
“^”符号称为“否”符号。如果用在方括号内,“^”表示不想要匹配的字符。例如,图四的正则表达式匹配所有单词,但以“X”字母开头的单词除外。

图四:匹配所有单词,但“X”开头的除外

1.6 圆括号和空白符号
假设要从格式为“June 26, 1951”的生日日期中提取出月份部分,用来匹配该日期的正则表达式可以如图五所示:

图五:匹配所有Moth DD,YYYY格式的日期

新出现的“\s”符号是空白符号,匹配所有的空白字符,包括Tab字符。如果字符串正确匹配,接下来如何提取出月份部分呢?只需在月份周围加上一个圆括号创建一个组,然后用ORO API(本文后面详细讨论)提取出它的值。修改后的正则表达式如图六所示:

图六:匹配所有Month DD,YYYY格式的日期,定义月份值为第一个组

1.7 其它符号
为简便起见,你可以使用一些为常见正则表达式创建的快捷符号。如表二所示:
表二:常用符号

例如,在前面社会安全号码的例子中,所有出现“[0-9]”的地方我们都可以使用“\d”。修改后的正则表达式如图七所示:

图七:匹配所有123-12-1234格式的社会安全号码

二、Jakarta-ORO库
有许多源代码开放的正则表达式库可供Java程序员使用,而且它们中的许多支持Perl 5兼容的正则表达式语法。我在这里选用的是Jakarta-ORO正则表达式库,它是最全面的正则表达式API之一,而且它与Perl 5正则表达式完全兼容。另外,它也是优化得最好的API之一。
Jakarta-ORO库以前叫做OROMatcher,Daniel Savarese大方地把它赠送给了Jakarta Project。你可以按照本文最后参考资源的说明下载它。
我首先将简要介绍使用Jakarta-ORO库时你必须创建和访问的对象,然后介绍如何使用Jakarta-ORO API。
▲ PatternCompiler对象
首先,创建一个Perl5Compiler类的实例,并把它赋值给PatternCompiler接口对象。Perl5Compiler是PatternCompiler接口的一个实现,允许你把正则表达式编译成用来匹配的Pattern对象。
▲ Pattern对象
要把正则表达式编译成Pattern对象,调用compiler对象的compile()方法,并在调用参数中指定正则表达式。例如,你可以按照下面这种方式编译正则表达式“t[aeio]n”:
默认情况下,编译器创建一个大小写敏感的模式(pattern)。因此,上面代码编译得到的模式只匹配“tin”、“tan”、 “ten”和“ton”,但不匹配“Tin”和“taN”。要创建一个大小写不敏感的模式,你应该在调用编译器的时候指定一个额外的参数:
创建好Pattern对象之后,你就可以通过PatternMatcher类用该Pattern对象进行模式匹配。
▲ PatternMatcher对象
PatternMatcher对象根据Pattern对象和字符串进行匹配检查。你要实例化一个Perl5Matcher类并把结果赋值给PatternMatcher接口。Perl5Matcher类是PatternMatcher接口的一个实现,它根据Perl 5正则表达式语法进行模式匹配:
使用PatternMatcher对象,你可以用多个方法进行匹配操作,这些方法的第一个参数都是需要根据正则表达式进行匹配的字符串:
· boolean matches(String input, Pattern pattern):当输入字符串和正则表达式要精确匹配时使用。换句话说,正则表达式必须完整地描述输入字符串。
· boolean matchesPrefix(String input, Pattern pattern):当正则表达式匹配输入字符串起始部分时使用。
· boolean contains(String input, Pattern pattern):当正则表达式要匹配输入字符串的一部分时使用(即,它必须是一个子串)。
另外,在上面三个方法调用中,你还可以用PatternMatcherInput对象作为参数替代String对象;这时,你可以从字符串中最后一次匹配的位置开始继续进行匹配。当字符串可能有多个子串匹配给定的正则表达式时,用PatternMatcherInput对象作为参数就很有用了。用PatternMatcherInput对象作为参数替代String时,上述三个方法的语法如下:
· boolean matches(PatternMatcherInput input, Pattern pattern)
· boolean matchesPrefix(PatternMatcherInput input, Pattern pattern)
· boolean contains(PatternMatcherInput input, Pattern pattern)
三、应用实例
下面我们来看看Jakarta-ORO库的一些应用实例。
3.1 日志文件处理
任务:分析一个Web服务器日志文件,确定每一个用户花在网站上的时间。在典型的BEA WebLogic日志文件中,日志记录的格式如下:
分析这个日志记录,可以发现,要从这个日志文件提取的内容有两项:IP地址和页面访问时间。你可以用分组符号(圆括号)从日志记录提取出IP地址和时间标记。
首先我们来看看IP地址。IP地址有4个字节构成,每一个字节的值在0到255之间,各个字节通过一个句点分隔。因此,IP地址中的每一个字节有至少一个、最多三个数字。图八显示了为IP地址编写的正则表达式:

图八:匹配IP地址

IP地址中的句点字符必须进行转义处理(前面加上“\”),因为IP地址中的句点具有它本来的含义,而不是采用正则表达式语法中的特殊含义。句点在正则表达式中的特殊含义本文前面已经介绍。
日志记录的时间部分由一对方括号包围。你可以按照如下思路提取出方括号里面的所有内容:首先搜索起始方括号字符(“[”),提取出所有不超过结束方括号字符(“]”)的内容,向前寻找直至找到结束方括号字符。图九显示了这部分的正则表达式。

图九:匹配至少一个字符,直至找到“]”

现在,把上述两个正则表达式加上分组符号(圆括号)后合并成单个表达式,这样就可以从日志记录提取出IP地址和时间。注意,为了匹配“- -”(但不提取它),正则表达式中间加入了“\s-\s-\s”。完整的正则表达式如图十所示。

图十:匹配IP地址和时间标记

现在正则表达式已经编写完毕,接下来可以编写使用正则表达式库的Java代码了。
为使用Jakarta-ORO库,首先创建正则表达式字符串和待分析的日志记录字符串:
这里使用的正则表达式与图十的正则表达式差不多完全相同,但有一点例外:在Java中,你必须对每一个向前的斜杠(“\”)进行转义处理。图十不是Java的表示形式,所以我们要在每个“\”前面加上一个“\”以免出现编译错误。遗憾的是,转义处理过程很容易出现错误,所以应该小心谨慎。你可以首先输入未经转义处理的正则表达式,然后从左到右依次把每一个“\”替换成“\\”。如果要复检,你可以试着把它输出到屏幕上。
初始化字符串之后,实例化PatternCompiler对象,用PatternCompiler编译正则表达式创建一个Pattern对象:
现在,创建PatternMatcher对象,调用PatternMatcher接口的contain()方法检查匹配情况:
接下来,利用PatternMatcher接口返回的MatchResult对象,输出匹配的组。由于logEntry字符串包含匹配的内容,你可以看到类如下面的输出:
3.2 HTML处理实例一
下面一个任务是分析HTML页面内FONT标记的所有属性。HTML页面内典型的FONT标记如下所示:
程序将按照如下形式,输出每一个FONT标记的属性:
在这种情况下,我建议你使用两个正则表达式。第一个如图十一所示,它从字体标记提取出“”face=”Arial, Serif” size=”+2″ color=”red””。

图十一:匹配FONT标记的所有属性

第二个正则表达式如图十二所示,它把各个属性分割成名字-值对。

图十二:匹配单个属性,并把它分割成名字-值对

分割结果为:
现在我们来看看完成这个任务的Java代码。首先创建两个正则表达式字符串,用Perl5Compiler把它们编译成Pattern对象。编译正则表达式的时候,指定Perl5Compiler.CASE_INSENSITIVE_MASK选项,使得匹配操作不区分大小写。
接下来,创建一个执行匹配操作的Perl5Matcher对象。
假设有一个String类型的变量html,它代表了HTML文件中的一行内容。如果html字符串包含FONT标记,匹配器将返回true。此时,你可以用匹配器对象返回的MatchResult对象获得第一个组,它包含了FONT的所有属性:
接下来创建一个PatternMatcherInput对象。这个对象允许你从最后一次匹配的位置开始继续进行匹配操作,因此,它很适合于提取FONT标记内属性的名字-值对。创建PatternMatcherInput对象,以参数形式传入待匹配的字符串。然后,用匹配器实例提取出每一个FONT的属性。这通过指定PatternMatcherInput对象(而不是字符串对象)为参数,反复地调用PatternMatcher对象的contains()方法完成。PatternMatcherInput对象之中的每一次迭代将把它内部的指针向前移动,下一次检测将从前一次匹配位置的后面开始。
本例的输出结果如下:
3.3 HTML处理实例二
下面我们来看看另一个处理HTML的例子。这一次,我们假定Web服务器从widgets.acme.com移到了newserver.acme.com。现在你要修改一些页面中的链接:
执行这个搜索的正则表达式如图十三所示:

图十三:匹配修改前的链接

如果能够匹配这个正则表达式,你可以用下面的内容替换图十三的链接:
注意#字符的后面加上了$1。Perl正则表达式语法用$1、$2等表示已经匹配且提取出来的组。图十三的表达式把所有作为一个组匹配和提取出来的内容附加到链接的后面。
现在,返回Java。就象前面我们所做的那样,你必须创建测试字符串,创建把正则表达式编译到Pattern对象所必需的对象,以及创建一个PatternMatcher对象:
接下来,用com.oroinc.text.regex包Util类的substitute()静态方法进行替换,输出结果字符串:
Util.substitute()方法的语法如下:
这个调用的前两个参数是以前创建的PatternMatcher和Pattern对象。第三个参数是一个Substiution对象,它决定了替换操作如何进行。本例使用的是Perl5Substitution对象,它能够进行Perl5风格的替换。第四个参数是想要进行替换操作的字符串,最后一个参数允许指定是否替换模式的所有匹配子串(Util.SUBSTITUTE_ALL),或只替换指定的次数。
【结束语】在这篇文章中,我为你介绍了正则表达式的强大功能。只要正确运用,正则表达式能够在字符串提取和文本修改中起到很大的作用。另外,我还介绍了如何在Java程序中通过Jakarta-ORO库利用正则表达式。至于最终采用老式的字符串处理方式(使用StringTokenizer,charAt,和substring),还是采用正则表达式,这就有待你自己决定了。

1、Oracle8/8i/9i数据库(thin模式)
Class.forName(“oracle.jdbc.driver.OracleDriver”).newInstance();
String url=”jdbc:oracle:thin:@localhost:1521:orcl”;
//orcl为数据库的SID
String user=”test”;
String password=”test”;
Connection conn= DriverManager.getConnection(url,user,password);

2、DB2数据库
Class.forName(“com.ibm.db2.jdbc.app.DB2Driver “).newInstance();
String url=”jdbc:db2://localhost:5000/sample”;
//sample为你的数据库名
String user=”admin”;
String password=”";
Connection conn= DriverManager.getConnection(url,user,password);

3、Sql Server7.0/2000数据库
Class.forName(“com.microsoft.jdbc.sqlserver.SQLServerDriver”).newInstance();
String url=”jdbc:microsoft:sqlserver://localhost:1433;DatabaseName=mydb”;
//mydb为数据库
String user=”sa”;
String password=”";
Connection conn= DriverManager.getConnection(url,user,password);

4、Sybase数据库
Class.forName(“com.sybase.jdbc.SybDriver”).newInstance();
String url =” jdbc:sybase:Tds:localhost:5007/myDB”;
//myDB为你的数据库名
Properties sysProps = System.getProperties();
SysProps.put(“user”,”userid”);
SysProps.put(“password”,”user_password”);
Connection conn= DriverManager.getConnection(url, SysProps);

5、Informix数据库
Class.forName(“com.informix.jdbc.IfxDriver”).newInstance();
String url =
“jdbc:informix-sqli://123.45.67.89:1533/myDB:INFORMIXSERVER=myserver;
user=testuser;password=testpassword”;
//myDB为数据库名
Connection conn= DriverManager.getConnection(url);

6、MySQL数据库
Class.forName(“org.gjt.mm.mysql.Driver”).newInstance();
String url =”jdbc:mysql://localhost/myDB?user=soft&password=soft1234&useUnicode=true&characterEncoding=8859_1″
//myDB为数据库名
Connection conn= DriverManager.getConnection(url);

7、PostgreSQL数据库
Class.forName(“org.postgresql.Driver”).newInstance();
String url =”jdbc:postgresql://localhost/myDB”
//myDB为数据库名
String user=”myuser”;
String password=”mypassword”;
Connection conn= DriverManager.getConnection(url,user,password);

8.Access数据库
建立ODBC数据源
Class.forName(“sun.jdbc.odbc.JdbcOdbcDriver”);
Connection conn=DriverManager.getConnection(“jdbc:odbc:bookbase”);

2005年02月04日

 

Java Reflection (JAVA反射)   
 作者:  corlin
 日期:  04-05-10 10:32
 点击数:  748   
Reflection 是 Java 程序开发语言的特征之一,它允许运行中的 Java 程序对自身进行检查,或者说“自审”,并能直接操作程序的内部属性。例如,使用它能获得 Java 类中各成员的名称并显示出来。

Java 的这一能力在实际应用中也许用得不是很多,但是在其它的程序设计语言中根本就不存在这一特性。例如,Pascal、C 或者 C++ 中就没有办法在程序中获得函数定义相关的信息。

JavaBean 是 reflection 的实际应用之一,它能让一些工具可视化的操作软件组件。这些工具通过 reflection 动态的载入并取得 Java 组件(类) 的属性。

 

1. 一个简单的例子

考虑下面这个简单的例子,让我们看看 reflection 是如何工作的。

import java.lang.reflect.*;
public class DumpMethods {
    public static void main(String args[]) {
        try {
            Class c = Class.forName(args[0]);
            Method m[] = c.getDeclaredMethods();
            for (int i = 0; i < m.length; i++)
                System.out.println(m[i].toString());
        } catch (Throwable e) {
            System.err.println(e);
        }
    }
}

按如下语句执行:

java DumpMethods java.util.Stack

它的结果输出为:

public java.lang.Object java.util.Stack.push(java.lang.Object)

public synchronized java.lang.Object java.util.Stack.pop()

public synchronized java.lang.Object java.util.Stack.peek()

public boolean java.util.Stack.empty()

public synchronized int java.util.Stack.search(java.lang.Object)

这样就列出了java.util.Stack 类的各方法名以及它们的限制符和返回类型。

这个程序使用 Class.forName 载入指定的类,然后调用 getDeclaredMethods 来获取这个类中定义了的方法列表。java.lang.reflect.Methods 是用来描述某个类中单个方法的一个类。

2.开始使用 Reflection

用于 reflection 的类,如 Method,可以在 java.lang.relfect 包中找到。使用这些类的时候必须要遵循三个步骤:第一步是获得你想操作的类的 java.lang.Class 对象。在运行中的 Java 程序中,用 java.lang.Class 类来描述类和接口等。

下面就是获得一个 Class 对象的方法之一:

Class c = Class.forName(“java.lang.String”);

这条语句得到一个 String 类的类对象。还有另一种方法,如下面的语句:

Class c = int.class;

或者

Class c = Integer.TYPE;

它们可获得基本类型的类信息。其中后一种方法中访问的是基本类型的封装类 (如 Integer) 中预先定义好的 TYPE 字段。

第二步是调用诸如 getDeclaredMethods 的方法,以取得该类中定义的所有方法的列表。

一旦取得这个信息,就可以进行第三步了——使用 reflection API 来操作这些信息,如下面这段代码:

Class c = Class.forName(“java.lang.String”);

Method m[] = c.getDeclaredMethods();

System.out.println(m[0].toString());

它将以文本方式打印出 String 中定义的第一个方法的原型。

在下面的例子中,这三个步骤将为使用 reflection 处理特殊应用程序提供例证。

模拟 instanceof 操作符

得到类信息之后,通常下一个步骤就是解决关于 Class 对象的一些基本的问题。例如,Class.isInstance 方法可以用于模拟 instanceof 操作符:

class A {
}

public class instance1 {
    public static void main(String args[]) {
        try {
            Class cls = Class.forName(“A”);
            boolean b1 = cls.isInstance(new Integer(37));
            System.out.println(b1);
            boolean b2 = cls.isInstance(new A());
            System.out.println(b2);
        } catch (Throwable e) {
            System.err.println(e);
        }
    }
}

在这个例子中创建了一个 A 类的 Class 对象,然后检查一些对象是否是 A 的实例。Integer(37) 不是,但 new A() 是。

3.找出类的方法

找出一个类中定义了些什么方法,这是一个非常有价值也非常基础的 reflection 用法。下面的代码就实现了这一用法:

import java.lang.reflect.*;

public class method1 {
    private int f1(Object p, int x) throws NullPointerException {
        if (p == null)
            throw new NullPointerException();
        return x;
    }

    public static void main(String args[]) {
        try {
            Class cls = Class.forName(“method1″);
            Method methlist[] = cls.getDeclaredMethods();
            for (int i = 0; i < methlist.length; i++) {
                Method m = methlist[i];
                System.out.println(“name = ” + m.getName());
                System.out.println(“decl class = ” + m.getDeclaringClass());
                Class pvec[] = m.getParameterTypes();
                for (int j = 0; j < pvec.length; j++)
                    System.out.println(“param #” + j + ” ” + pvec[j]);
                Class evec[] = m.getExceptionTypes();
                for (int j = 0; j < evec.length; j++)
                    System.out.println(“exc #” + j + ” ” + evec[j]);
                System.out.println(“return type = ” + m.getReturnType());
                System.out.println(“—–”);
            }
        } catch (Throwable e) {
            System.err.println(e);
        }
    }
}

这个程序首先取得 method1 类的描述,然后调用 getDeclaredMethods 来获取一系列的 Method 对象,它们分别描述了定义在类中的每一个方法,包括 public 方法、protected 方法、package 方法和 private 方法等。如果你在程序中使用 getMethods 来代替 getDeclaredMethods,你还能获得继承来的各个方法的信息。

取得了 Method 对象列表之后,要显示这些方法的参数类型、异常类型和返回值类型等就不难了。这些类型是基本类型还是类类型,都可以由描述类的对象按顺序给出。

输出的结果如下:

name = f1

decl class = class method1

param #0 class java.lang.Object

param #1 int

exc #0 class java.lang.NullPointerException

return type = int

—–

name = main

decl class = class method1

param #0 class [Ljava.lang.String;

return type = void

-----


4.获取构造器信息

获取类构造器的用法与上述获取方法的用法类似,如:

import java.lang.reflect.*;

public class constructor1 {
    public constructor1() {
    }

    protected constructor1(int i, double d) {
    }

    public static void main(String args[]) {
        try {
            Class cls = Class.forName(“constructor1″);
            Constructor ctorlist[] = cls.getDeclaredConstructors();
            for (int i = 0; i < ctorlist.length; i++) {
                Constructor ct = ctorlist[i];
                System.out.println(“name = ” + ct.getName());
                System.out.println(“decl class = ” + ct.getDeclaringClass());
                Class pvec[] = ct.getParameterTypes();
                for (int j = 0; j < pvec.length; j++)
                    System.out.println(“param #” + j + ” ” + pvec[j]);
                Class evec[] = ct.getExceptionTypes();
                for (int j = 0; j < evec.length; j++)
                    System.out.println(“exc #” + j + ” ” + evec[j]);
                System.out.println(“—–”);
            }
        } catch (Throwable e) {
            System.err.println(e);
        }
    }
}

这个例子中没能获得返回类型的相关信息,那是因为构造器没有返回类型。

这个程序运行的结果是:

name = constructor1

decl class = class constructor1

—–

name = constructor1

decl class = class constructor1

param #0 int

param #1 double

—–

5.获取类的字段(域)

找出一个类中定义了哪些数据字段也是可能的,下面的代码就在干这个事情:


import java.lang.reflect.*;

public class field1 {
    private double d;
    public static final int i = 37;
    String s = “testing”;

    public static void main(String args[]) {
        try {
            Class cls = Class.forName(“field1″);
            Field fieldlist[] = cls.getDeclaredFields();
            for (int i = 0; i < fieldlist.length; i++) {
                Field fld = fieldlist[i];
                System.out.println(“name = ” + fld.getName());
                System.out.println(“decl class = ” + fld.getDeclaringClass());
                System.out.println(“type = ” + fld.getType());
                int mod = fld.getModifiers();
                System.out.println(“modifiers = ” + Modifier.toString(mod));
                System.out.println(“—–”);
            }
        } catch (Throwable e) {
            System.err.println(e);
        }
    }
}

这个例子和前面那个例子非常相似。例中使用了一个新东西 Modifier,它也是一个 reflection 类,用来描述字段成员的修饰语,如“private int”。这些修饰语自身由整数描述,而且使用 Modifier.toString 来返回以“官方”顺序排列的字符串描述 (如“static”在“final”之前)。这个程序的输出是:

name = d

decl class = class field1

type = double

modifiers = private

—–

name = i

decl class = class field1

type = int

modifiers = public static final

—–

name = s

decl class = class field1

type = class java.lang.String

modifiers =

—–

和获取方法的情况一下,获取字段的时候也可以只取得在当前类中申明了的字段信息 (getDeclaredFields),或者也可以取得父类中定义的字段 (getFields) 。


6.根据方法的名称来执行方法

文本到这里,所举的例子无一例外都与如何获取类的信息有关。我们也可以用 reflection 来做一些其它的事情,比如执行一个指定了名称的方法。下面的示例演示了这一操作:

import java.lang.reflect.*;
public class method2 {
    public int add(int a, int b) {
        return a + b;
    }
    public static void main(String args[]) {
        try {
            Class cls = Class.forName(“method2″);
            Class partypes[] = new Class[2];
            partypes[0] = Integer.TYPE;
            partypes[1] = Integer.TYPE;
            Method meth = cls.getMethod(“add”, partypes);
            method2 methobj = new method2();
            Object arglist[] = new Object[2];
            arglist[0] = new Integer(37);
            arglist[1] = new Integer(47);
            Object retobj = meth.invoke(methobj, arglist);
            Integer retval = (Integer) retobj;
            System.out.println(retval.intValue());
        } catch (Throwable e) {
            System.err.println(e);
        }
    }
}

假如一个程序在执行的某处的时候才知道需要执行某个方法,这个方法的名称是在程序的运行过程中指定的 (例如,JavaBean 开发环境中就会做这样的事),那么上面的程序演示了如何做到。

上例中,getMethod 用于查找一个具有两个整型参数且名为 add 的方法。找到该方法并创建了相应的 Method 对象之后,在正确的对象实例中执行它。执行该方法的时候,需要提供一个参数列表,这在上例中是分别包装了整数 37 和 47 的两个 Integer 对象。执行方法的返回的同样是一个 Integer 对象,它封装了返回值 84。

7.创建新的对象

对于构造器,则不能像执行方法那样进行,因为执行一个构造器就意味着创建了一个新的对象 (准确的说,创建一个对象的过程包括分配内存和构造对象)。所以,与上例最相似的例子如下:

import java.lang.reflect.*;

public class constructor2 {
    public constructor2() {
    }

    public constructor2(int a, int b) {
        System.out.println(“a = ” + a + ” b = ” + b);
    }

    public static void main(String args[]) {
        try {
            Class cls = Class.forName(“constructor2″);
            Class partypes[] = new Class[2];
            partypes[0] = Integer.TYPE;
            partypes[1] = Integer.TYPE;
            Constructor ct = cls.getConstructor(partypes);
            Object arglist[] = new Object[2];
            arglist[0] = new Integer(37);
            arglist[1] = new Integer(47);
            Object retobj = ct.newInstance(arglist);
        } catch (Throwable e) {
            System.err.println(e);
        }
    }
}

根据指定的参数类型找到相应的构造函数并执行它,以创建一个新的对象实例。使用这种方法可以在程序运行时动态地创建对象,而不是在编译的时候创建对象,这一点非常有价值。

8.改变字段(域)的值

reflection 的还有一个用处就是改变对象数据字段的值。reflection 可以从正在运行的程序中根据名称找到对象的字段并改变它,下面的例子可以说明这一点:

import java.lang.reflect.*;

public class field2 {
    public double d;

    public static void main(String args[]) {
        try {
            Class cls = Class.forName(“field2″);
            Field fld = cls.getField(“d”);
            field2 f2obj = new field2();
            System.out.println(“d = ” + f2obj.d);
            fld.setDouble(f2obj, 12.34);
            System.out.println(“d = ” + f2obj.d);
        } catch (Throwable e) {
            System.err.println(e);
        }
    }
}

这个例子中,字段 d 的值被变为了 12.34。

9.使用数组

本文介绍的 reflection 的最后一种用法是创建的操作数组。数组在 Java 语言中是一种特殊的类类型,一个数组的引用可以赋给 Object 引用。观察下面的例子看看数组是怎么工作的:

import java.lang.reflect.*;

public class array1 {
    public static void main(String args[]) {
        try {
            Class cls = Class.forName(“java.lang.String”);
            Object arr = Array.newInstance(cls, 10);
            Array.set(arr, 5, “this is a test”);
            String s = (String) Array.get(arr, 5);
            System.out.println(s);
        } catch (Throwable e) {
            System.err.println(e);
        }
    }
}

例中创建了 10 个单位长度的 String 数组,为第 5 个位置的字符串赋了值,最后将这个字符串从数组中取得并打印了出来。

下面这段代码提供了一个更复杂的例子:

import java.lang.reflect.*;

public class array2 {
    public static void main(String args[]) {
        int dims[] = new int[]{5, 10, 15};
        Object arr = Array.newInstance(Integer.TYPE, dims);
        Object arrobj = Array.get(arr, 3);
        Class cls = arrobj.getClass().getComponentType();
        System.out.println(cls);
        arrobj = Array.get(arrobj, 5);
        Array.setInt(arrobj, 10, 37);
        int arrcast[][][] = (int[][][]) arr;
        System.out.println(arrcast[3][5][10]);
    }
}
例中创建了一个 5 x 10 x 15 的整型数组,并为处于 [3][5][10] 的元素赋了值为 37。注意,多维数组实际上就是数组的数组,例如,第一个 Array.get 之后,arrobj 是一个 10 x 15 的数组。进而取得其中的一个元素,即长度为 15 的数组,并使用 Array.setInt 为它的第 10 个元素赋值。

注意创建数组时的类型是动态的,在编译时并不知道其类型。


作者Blog:http://blog.csdn.net/leek2000/
2005年01月19日
在本书的名字叫做《象青蛙一样思考》,为什么会起这样一个名字,青蛙的思考方式远比人更高级吗?但是如果你知道这本书的另外两个名字的话,你就不会再有这样的疑问了。
  
  这本书的另外两个名字分别叫《泥潭管理哲学研究》和《企业潜规则实操纲要》。无论你对青蛙怀有何种不以为然的见解,但有一点是毫无疑问的,在泥潭之中,青蛙拥有更广阔的生存空间。
  
  那么什么叫泥潭呢?你是否遭遇过泥潭呢?要想解决这个疑惑,请你先看看我们所列出的企业十大泥潭:
  
  
  泥潭之一:你是忠于职守,还是忠于老板或上司?
  
  泥潭现象解析:如果你回答说忠于职守,无疑是表明了自己不认同老板或上司,老板和上司只能考虑另行选择一个忠诚度更高的成员来替代你。反之,如果你说忠于老板而不是职守,那么……企业只能忍痛割爱,所有的组织系统无一例外的都只是需要蛙才而不是奴才。
  
  泥潭之二:上司或老板暗中询问你同事的动向。
  
  泥潭现象解析:如果你如实招来,则你做为一只青蛙的蛙品会大受怀疑,一只出卖朋友的青蛙是不可靠的,从此老板或上司就会对你敬而远之。反之,你拒绝实话实说,或者只是敷衍了事的话,则你的忠诚度就会成为问题,没有哪一个老板或上司喜欢不诚实的员工,你呀,就好自为之吧。
  
  泥潭之三:上司或老板吩咐你做一件明显触犯法律的事情。
  
  泥潭现象解析:你当然要做,因为这是老板吩咐下来的,只有把事情做好,让老板抓住你的缺陷和把柄,才能证明你的忠诚。然而你绝对不能做,如果你做了的话,那么未来等待你的将是非常可怕的事情。当然你可以向老板解释,不过,老板或上司对你的讨价还价是绝不会手下留情的,那么你到底应该怎么办呢?这对你来说真是一个难题啊。
  
  泥潭之四:你发现上司对老板不忠。
  
  泥潭现象解析:为什么这种行为偏偏会被你发现?如果你没有问过这个问题的话,你只能考虑以下几个方案,一,报告老板,后果是你的上司比你更重要,老板在上司的狡辨之下只好解聘你以安慰受到伤害的他。二,默不作声,那你就惨了,相信我吧,公司内部包括老板在内的所有动物都知道你看到了什么,大家都在跷首以盼,等待你的行动,然而你却装聋作哑,无论你的老板是何等的愚蠢愚笨,但我敢保证他决不想得到一个聋子哑吧员工。最后一个办法就是你和上司同流合污,可是你忘了,这只是你的一厢情愿,你的上司为了安全起见,会把所有的不轨行为全栽到你的头上。总之,一句话,你完了。
  
  泥潭之五:两个或两个以上的主管同时吩咐你做不同的事情。
  
  泥潭现象解析:立即行动,这是毫无疑问的,问题是你首先听从哪一个主管的指令。通常的答案是,首先选择职位更高的,其次选择直接主管。可是你忘了,当你撇开主管而直接为更高领导者做事的话,你的主管会怎么想?他内心中的惶急与危机意识又如何化解?总之,无论你如何选择只会出现一种结果,那就是让所有的主管和老板都对你产生看法,这对你的前途可不是件好事情。
  
  泥潭之六:两个或两个以上主管同时吩咐你做一件事,但他们要求你遵循的方案或程序迥然不同。
  
  泥潭现象解析:这个泥潭与上一个好象没有本质的不同,区别在于,主管或老板们似乎更喜欢用这种方式证明泥潭对于你的必要性,你只有在两个或几个方案中选择一个,换句话说,你需要在几个主管或主管与老板之间选择那个最终将你踢出企业的对象,你喜欢让谁来驱逐你这个自作主张不把管理者放在眼里的人选呢?你的偏好不会改变既定的结果。
  
  泥潭之七:处境糟糕的同事拿你当朋友,或是向你求助。
  
  泥潭现象解析:比糟糕的事情更为糟糕的是,遭到企业冷冻、废黜的某位员工突然发现了你,他死死的抓住你不放,拿你当他的救星亲人,推心置腹的把你和他在一起的场景拉到大众的视线之下,你应该怎么办?你的痛苦不在于对他解释些什么,而在于如何向别的人表明你和他根本没任何关系,但是这一点很难,无论你是如何的极力洗涮自己,都无法消除大家最期待的印象:那就是你完了,你居然不把公司的意旨放在眼里。
  
  泥潭之八:一个有背景的同事捅出了大疵漏,请求你为他遮掩。
  
  泥潭现象解析:这种事本是事不关已,理应高高挂起,可是你的同事认为你有义务帮助他,如果你不赞同他这个看法的话,就必然会发生你和他之间的“理念冲突”。而他有背景、有靠山,不是一个人而是一个“团队”,“理念冲突”的结果必然是他的“理念”战胜你的“理念”。可如果你答应他的要求的话,那你就彻底的死定了,企业会让你为自己的轻率付出惨重的代价,你为之懊悔的时间远比你想象的更要长。
  
  泥潭之九:你的上司,嗯,是一个异性,他或者她对你有着很过份亲怩的表示,你应该怎么办?
  
  泥潭现象解析:答应对方吧,及时行乐吧,管那么多干什么?你是不是这么样的?那你就惨了,办公室偷情的后果远不象小说中描写的那么美丽浪漫,公务和孽情纠缠在一起,这足以引起妒火中烧的同事们对你猛烈的攻击,被一踢出去决不是件美好的体验。什么?你不答应,你想法设法拒绝?你会得到善意的提醒的,办公室性骚扰可是大家最喜欢咀嚼的话题。
  
  泥潭之十:老板对你寄予了厚望,安排你做一件工作,不料却遭受到了来自于所有同事的强力狙击,你又何以自处?
  
  泥潭现象解析:一边是你的衣食父母老板,一边是你的同事朋友,如果你站在老板的一方,从此你就会获罪于所有的同事朋友,糟糕的是,老板远比你更需要他们,更糟糕的是,老板远比需要你更需要他们,当摊牌的那一天来到的时候,你就再也没有翻身的余地了。那么你选择同事和朋友怎么样?遗憾的是,这个选择是不存在的,因为老板不会允许。
  
  那么你到底应该怎么做呢?
  
  
  
  
  
  
  
  
  
  如果你在企业中遭遇到过这种情况,又或者你更希望自己能够拥有敏锐的思维避过或解决上述十大泥潭,那么,请走进这本书,让我们一起来破解隐密的社会组织系统运行中那些不为人所知的秘密规律,解析泥潭现象的形成及规避机制,所有的这一切过程,都有助于你的情商EQ的提高与成熟。
  《象青蛙一样思考》
  
  作者:雾满拦江
  
  序章:企业潜规则认知
  
  有一种现象,现在是、以前是,并且此后相当长的时期内仍然是我们主要关注的重点,那就是企业内部秘而不宣的潜规则。
  
  潜规则是企业文化中最为根深蒂固的一个组成,它构成了企业内部事务处理与人际关系的基本准则,但是这些准则的相关条款,却长期以来不为人知。有一种态度,或者说是一种认知思想,从根本上不承认这种潜规则的存在价值,这种思想下的企业内部运行,无异于在一团漆黑的世界中阔步行进,其危险是可想而知的:
  
  看不到的潜规则
  
  
  
  
  但是当我们在企业打拼过一段时间,感受到这种隐形力量的存在与制约的时候,我们的思想会发生变化,看待企业的眼光也会有所不同:
  
  发现潜规则
  
  
  
  
  思想发生了变化,认识事物的背景思想发生了变化,所谓的“潜规则”就得以凸显,成为我们思考时主要的指导依据与行为准则。在此之后我们学习认同潜规则,接受潜规则,这个时候,我们的思想背景又在不知不觉的发生着变化:
  
  解析潜规则
   当我们掌握了规律的存在之后,我们的思想就进入了一个成长期,在这个阶段里,娴熟的运用潜规则以达成于企业的发展目标,就成为了一个企业管理者最基本的技能,虽然这一技能从未在经典管理学中得以确认,但这一论断却是无可置疑的:
  
  利用潜规则
   就这样,我们在实践中不断的丰富我们自己的认知,如果不考虑到这一过程的残酷性与现实性的话,仅从学理的角度上我们仍然能够获得思想的升华。
  
  这一思想升华的过程阐述是依循如下机理:
  
  潜规则是企业内部的客观存在,是组织系统自身的固有规律,是系统推进机制的功能性损耗,是系统自然衍生并不断提高的熵值体现,无论它在不同时期的表现是何等的不同,也无论在不同的企业中潜规则的内容有何区别,但,它的客观性不会改变。
  
  唯一能够改变的,只是我们的思想背景,做为企业这个社会性组织系统内部成员的不同思想,所看到的潜规则是不同的。而事实上,潜规则就是潜规则,它从来没有发生过变化。
  
  不同思想背景下的潜规则认知状态
   
  潜规则在企业内部的主导力量与影响作用是决定性的,但对潜规则的认识与领悟,却更多的依赖于我们自己的悟性。为了化解这种领悟中的听天由命的宿命论调,更多的时候我们选择情商EQ来说明问题。
  
  在企业内部,情商EQ表现为对潜规则的认识与掌握能力。
  
  现在我们已经确信,情商EQ才是决定一个人在企业内部获得成功的最主要依凭。把话说得更清楚一些,谁具有敏锐把握企业中潜规则的能力,谁就最具成功者的潜质,这种潜质的发挥,比之于业务或技术领域中的能力更为重要。
    全面的能力包括:
  
  智商IQ
  认识显性规则的能力
  
  情商EQ
  认识隐性规则的能力
  
  不可思议的是,这种关键性能力的掌握,却从未被我们名正言顺的提起,而本书,正是试图通过架构一系列组织系统模型,改变组织成员的思维模式,使得在企业内部以潜规则形式表现出来的组织系统规律得以凸显。
  
  与《职场动物进化手册》相比,本书更着重于思维模式的引导与训练,但这个训练过程却整合于一个完整的故事体系之中。也正如《职场动物进化手册》一样,我们的故事是以寓言的形式来表达,让我们学会象青蛙那样思考。
  
  在这里,青蛙的思考模式被确定为一个明确的思想背景,在此背景下突出潜规则的存在与运用。因此,书中的某些情节难免会出现一些夸张、压缩与扭曲,如果以此来对企业的现状进行印证,就会得出非常令人沮丧的结论。
  
  同样的道理,书中的主要观点不是建立在空洞的一厢情愿之上,而是以系统内在的熵值数量为依据,所有的论证及推导,也是建立在这个基础之上的。
  
  与青蛙的思考模式相对应的,是恐龙的思维观念,这一观念隐含着一系列理想主义者的愿望与行为,当恐龙学会以青蛙的视角观察世界并进行思考的时候,庞大的知性思想才能够获得在潜规则泥潭中生存的最基本依据。
  
  本书的另一个侧面集中于权力管理的框架之上,对权力的要素进行数量分析,并导出相关的权力函数,相应的伴随着大量的权力运作案例。如前所述,这些现实性的权力实操赋予了我们更多的它寓言的色彩,从而避免让我们从这些刀光剑影中错误的汲取一些负面的东西,诸如争权夺利,诸如玩弄权术,诸如勾心斗角,诸如不择手段等,尽管这些负面的要素是企业潜规则中的重要组成部分,但作者仍然对此抱有信心。
  第一章:快乐的老青蛙
  
  1)
  
  雷龙集团董事长大头蛙遇到一件事,这让他说不出来的不开心。
  
  这件事说起来,已经有一段时间了。前些日子,大头蛙董事长闲暇的时候,喜欢独自一只蛙带着鱼竿鱼饵,躲到一座泥潭附近享受一下垂钓的乐趣。每一次他都是偷偷的溜出去,再偷偷的溜回来,谁也不知道他去了什么地方。日子久了,他结识了一只老青蛙,也是有着这方面的爱好,经常假借公事之机从公司里偷偷溜出来,跑来泥潭和大头蛙董事长坐在一起,一边垂钓,一边东拉西扯。
  
  老青蛙压根不知道这个和他坐在一起的普通老蛙就是大名鼎鼎的雷龙集团的董事长,大头蛙对这只老青蛙的情况也是一无所知。但是,这丝毫也没有妨碍到他们之间的情谊日益深厚。
  
  有一次,大头蛙无意问了一句:“老青蛙,你在哪一家公司做事儿,怎么会这么轻闲?”
  
  老青蛙反问:“老头,你知道雷龙集团吗?”
  
  大头蛙眨了延眼睛,连连点头:“知道知道。”
  
  老青蛙脸上露出神秘兮兮的表情:“我,老青蛙,就在雷龙集团下面的一家子公司工作。”
  
  “有这种事?”大头蛙吃了一惊,忍不住上下打量这只上班时间偷溜出来垂钓的老青蛙:“你上班时间偷偷跑出来,居然没有谁管你?”
  
  老青蛙哈哈一笑:“大头蛙,这种事,就不是你能明白的了。”说完,得意洋洋的叼上一支烟,哼起糊涂蛙进行曲:“糊涂蛙,糊涂蛙,糊涂青蛙乐哈哈……”不管大头蛙心里是何等的好奇,偏偏就是不肯告诉他秘密。
  
  那一天大头蛙心情恶劣已极,钓了半天什么也没钓到,等他回公司之后,也没有声张,悄悄的查询了一下,果然查到了老青蛙的名字,居然还是下属子公司的一个部门经理,身为部门经理竟然在上班时间偷偷溜出去垂钓,这象什么话嘛!最可气的是,下面报交上来的报告,还总是说公司的效率与效益不断在提高,员工考勤管理上了轨道,以前在搞绩效,现在又在弄平衡记分,钱花了好多,效果也都说很明显。
  
  大头蛙从来没有怀疑过部属的忠诚,也相信公司整体情形是越来越好。但面对这只老青蛙,他真的有些把握不准了。这件事,到底应该怎么办呢?
  
  这件事说明了雷龙集团公司的管理中存在着一个大大的漏洞,如果不赶快堵上的话,这个洞就会越来越大,直到威胁到公司的生存。但如果追究这件事……那他就有可能失去老青蛙这个朋友了。老青蛙虽然不是个好主管,但显而易见的,他是一个好朋友。
  
  有一种错误的观点,认为有钱的青蛙都是六亲不认,事实并不是这样,就拿大头蛙来说,他就是一只非常重视朋友情谊的蛤蟆。所以,在对待老青蛙这件事上,他感觉到了为难。
  
  既不能听之任之,又不想伤害到他和老青蛙的友情,那么这事到底应该怎么办呢?
  大头蛙正在发愁的时候,他的儿子小恐龙回来了。
    
  小恐龙和他爸爸大头蛙不同,他虽然年轻,却是毕业于侏罗纪工商管理学院的名牌MBA,对企业的管理有着自己专业的研究与见解,以往大头蛙在管理上遇到什么管理上的问题的时候,总是老气横秋的操起电话:“喂,儿子吗?我是老爸,你听着,老爸考你一个问题,看你是不是天天只顾泡恐龙妞不好好读书。”遇到这种情况的时候,小恐龙就不敢掉心轻心,认认真真的回答老爸大头蛙的问题,有的时候,小恐龙给他支的招还真的很管用,让大头蛙对儿子的信心越来越足。
    
  小恐龙毕业回来了,带回来很多新的思想,什么知识管理,什么非性线科学,什么企业战略,什么品牌营销企业文化,什么形象力领导力,什么决策力执行力,都是大头蛙公司里急需的东西,乐得大头蛙眉开眼笑,打心眼里认为儿子比他这个土包子老爸强多了。
    
  现在大头蛙遇到了这个问题,想了好久,决定再和儿子小恐龙商量一下。小恐龙听了老爸大头蛙的情形之后,脸上顿时泛起一股煞气,大爪子用力一挥:“这种事不能这么算了,要追查下去,一定要查个明白!”
    
  “可是,”大头蛙不开心的鼓着眼珠子,反对道:“老青蛙可是我的朋友啊。”
    
  “朋友归朋友,工作归工作。”小恐龙不屑的瞧着大头蛙:“老爸,不是我说你,你那用蛙唯亲的旧观念也该变一变了,现在是信息时代,否则你会被经济发展所淘汰的。”
    
  大头蛙不爱听这话:“胡说八道,不用蛙唯亲,将来公司里哪有你的位置?”
    
  小恐龙刚刚拿到MBA,正是雄心勃勃的时候,听到老爸的话心里不舒服,当即顶撞道:“我才不稀罕你那破公司呢,就算是你八台大轿来抬我去,我也不会进去的。”
    
  大头蛙听了后眨眨眼,问道:“你不来雷龙集团,那你想做什么?”
    
  小恐龙豪气万丈的说道:“我吗,我要打造一家国际性的大暴龙公司出来,超过你的小公司。”
    
  小恐龙的气势,惊得大头蛙倒退两步,连声说:“有志气,好,不愧是我大头蛙的儿子,有志气,那么你打算怎么做起呢?”
    
  “怎么做……”小恐龙搔了搔头上的龙角:“这个事……老爸你要不要先投资两千万?”
    
  大头蛙一听,目瞪口呆:“真的?”他心里有些说不出的失望,想不到儿子小恐龙竟然是这样的眼高手低,幸好,小恐龙哈哈笑了起来,后面的尾巴一撑,支住身体,上前搂住大头蛙的脖子:
    
  “老爸,骗你的,呵呵,你想啊,我还没有真正的进入企业实践过,怎么可能就搞大投资做公司呢?呵呵,老爸看你给吓得,肚皮都翻白了。”
    
  “去去去,一边去,”大头蛙气恼的把儿子推到一边,突然之间脑子里灵光一闪,叫道:
    
  “儿子,既然你想进一家企业实践,从基层做起,我倒有一个好的建议给你。”
    
  “什么好建议?”小恐龙急忙问道。
    
  “这个建议吗,”大头蛙眼珠滴溜溜的转动着:“儿子,你把门关好,过来听我讲给你听。”
2)
  
  过了几天,大头蛙又趁别的青蛙不注意的功夫悄悄溜了出去,当他到了泥潭附近坐下来的时候,就见老青蛙顺着烂泥塘急不可奈的蹦了过来:“哈罗,老头,这几天你跑哪儿去了?怎么不出来钓泥鳅了?”
  
  大头蛙从鼻子里哼了一声:“谁说我不出来了?这不是来了吗?”自从知道这只老青蛙是自己的部属之后,大头蛙心里就总是有气,这个老家伙,拿着他公司里开出来的优薪厚酬,却不务正业,天天偷偷跑出来垂钓,真是太不象话了。虽然心里有气,但大头蛙表面上却不动声色,只是怎么也无法让自己高兴起来。
  
  老青蛙却全然不知道大头蛙心里的想法,他得意洋洋的哼着糊涂蛙进行曲,坐了下来,把饵放在钩上,抛入泥潭中:“老头,你气色不太好,是不是最近遇到什么不开心的事情了?”
  
  大头蛙哼了一声,没有理会。
  
  虽然碰了一鼻子灰,却一点也影响不到老青蛙的快乐心情,他仍然是悠哉优哉的哼着小曲,全神贯注的盯着淤泥上的浮鳔:“老头,你到底有什么不开心的事,说出来听听。”
  
  大头蛙又哼了一声:“跟你说有什么用,你又不是雷龙集团的董事长。”
  
  老青蛙嘿嘿一乐:“老头,别小瞧我,虽然我不是雷龙集团的董事长,不过我敢拍着肚皮说,雷龙集团大头蛙董事长都办不到的事情,我老青蛙就敢打这个保票给你办到,你信不信?”
  
  这种大话一说出口,大头蛙差一点没气晕了头:“胡说!”
  
  “什么?老头你敢骂我胡说?”老青蛙不乐意了:“我来问你,老头,你看我三天两头溜出来垂钓,大头蛙他敢吗?他每走出一步,身后都跟着成群的青蛙,数不清的事务性工作缠着他,一个决策稍不留神就会给公司造成巨大损失,那就是生死关头,你说大头蛙怎么比得了我?”
  
  大头蛙心里很是赞同老青蛙的话,但还是扔过去一句话:“你说的这些,跟我说的是两码事。”
  
  “事是两码事,道理却是同一个道理。”滑头老青蛙却是不以为然:“说出来吧老头,到底是什么事让你这么愁眉不展的?是不是看上了哪只美丽的小青蛙?”
  
  “去你的,没一点正经!”大头蛙生气的踹了老青蛙一脚:“就怕我真的说出来,你又帮不上忙。”
  
  “到底能不能帮上忙,你不说出来是不清楚的,”老青蛙却很是驾定的神情:“别磨蹭了,老头你快点说吧。”
  
  大头蛙又假装犹豫了一会儿,才慢吞吞的说道:“这个事……是我儿子的事情。”
  
  “你儿子?”老青蛙诧异的望了望大头蛙:“那是因为你儿子的工作问题了,是不是?”
  
  大头蛙不由得看了看这只其貌不扬的老青蛙,看不出这个家伙真有点脑子,闻弦歌而知雅意。他不由得点了点头,说了声是。然后老青蛙追问道:“你儿子今年多大了?”
  
  大头蛙回答:“二十二,刚刚大学毕业。”
  老青蛙又问道:“嗯,大学毕业蛙,好啊,学什么专业的?”
  
  大头蛙吱唔道:“这个……专业是工商管理。”
  
  “这个专业好啊,来我们公司正合适!”老青蛙呱呱的叫了起来。
  
  “可是……”大头蛙看老青蛙这副大包大揽的模样,心里有气,就想难为难为他,撒谎说道:“问题是我儿子已经去咱……去你们雷龙集团面试过,没成功啊,人家嫌他没有工作经验。”
  
  老青蛙满不在乎的晒然一笑:“这没关系,你让他到我这里来,他要是愿意先进子公司的话,相信我好了,把你儿子交给我教导,几年之后,我保证他一帆风顺的坐到副总的职位上。”
  
  大头蛙再也忍不住了:“吹牛!雷龙公司管理制度那么严格,你说你还能把一个落聘的应届毕业蛙招进去,就已经吹得够离谱的了,还说什么几年后让他坐上副总的职位,你这也实在是有点吹得没边了。”
  
  “怎么,你不相信?”老青蛙不高兴了,扭头望着大头蛙。
  
  大头蛙也是极为诧异的望着老青蛙,说什么也难以相信这件事,就大声的叫道:“当然不相信了。”老青蛙也不高兴了:“那好,我也不跟你多说,明天,你让你儿子来我这里,看我怎么把他安排进公司里去。”
  
  晚上回家后,大头蛙和儿子小恐龙说起了这事,小恐龙对于老爸把自己和一只世故的老青蛙安排在一起的做法,很是不以为然,但是他也想瞧瞧这只老青蛙到底有什么办法把他弄进管理严格的雷龙集团,就不情愿的答应了下来。
  
  第二天,小恐龙就去子公司找老青蛙,由于这些年来他一直在海外读书,公司里的人谁也不知道他是董事长大头蛙的儿子。他也就装着一副不谙世故的样子,按照老爸事先交待过的,见到老青蛙后,只字不提自己刚刚从侏罗纪恐龙工商管理学院毕业的事情,谎说自己只是毕业于一所普通的青蛙大学,想看看老青蛙怎么安排。
  
  老青蛙听了小恐龙的自我介绍之后,就眯起眼睛,想了一会儿,吩咐小恐龙留下一份简历给他:“你先回去,最多不过一个星期,不过一个星期你听我的电话,你就可以来上班了。”
  
  几天之后,老青蛙所在的子公司果然开始去青蛙市场招聘,听到这个消息之后,大头蛙特意悄悄跑去青蛙市场看了看,发现应聘者中不乏优秀的恐龙,按小恐龙现在那份编造出来的假简历,根本就连第一关也过不了。
  
  可是情况大出大头蛙的预料,小恐龙那份条件远不够格的简历,居然过关斩将,进入了最后的面试阶段。
  
  这事让大头蛙吃了一惊,悄悄找人拿过来全部应聘青蛙的简历一看,顿时明白了过来。
  
  那些能力和经验超过小恐龙的青蛙们的简历,一份也不见了。那些简历哪里去了?想都不用想,大头蛙就立即知道,这两天老青蛙办公室里的碎纸机,一定是处于超负荷的运转状态之中。
  
  这个老混蛋,竟敢跟我来这一手!发现问题的真相之后,大头蛙气得咬牙切齿!但是他现在还不想揭穿老青蛙的诡计,他要把这笔帐记下来,等到时候跟老青蛙一块算个清楚。
  3)
  
  蛙龙对话:《泥潭管理哲学》第一课,青蛙最快乐
  
  “听着,从今天开始,你每天要跟着我学习。”当小恐龙如愿以偿的进入了雷龙集团公司之后,老青蛙盘踞在大班椅上,大模大样的对他说道。
  
  “学习?学什么呢?”小恐龙忍住厌恶,假装认真的问道。
  
  “学习我的‘泥潭管理哲学’”,老青蛙一本正经的说道:“今天我们开讲第一课,泥潭之中,只有青蛙最快乐!”
  
  “泥潭管理哲学?”重复着这个古怪的名称,小恐龙差一点失笑出声。
  
  小恐龙打心里瞧不起这只油滑的老青蛙,他早已拿定了主意,一旦对这只滑头油蛙对公司管理上所造成的损害做出正确评估之后,就立即将这个老滑头撵出公司去。不只是这只滑头油蛙,凡是他的同类,都在驱逐之列,雷龙集团迟早也要成为国际性的大公司,与国际市场上的巨型恐龙公司相竞争,这就要求雷龙集团一定要建立起现代化的管理体制,容不得这只滑头油蛙的不和谐鸣叫掺杂其中。
  
  只有引进先进管理体制的公司,才有可能决胜于风云变幻的国际市场之上,这一点,是毫无疑问的。
  
  “没错,是泥潭管理学,”老青蛙点头道:“事实上你已经开始了学习,为什么你能坐在这里,而那些从简历上看起来远比你更优秀的恐龙们却没有获得这个资格呢?原因很简单,他们遭遇到了职场上的获准进入资格泥潭,或者我们也可以简单一些,就称之为资格泥潭吧。”
  
  “资格泥潭?”小恐龙的眼睛一下子瞪大了。
  
  “没错,正是资格泥潭。”说着话,老青蛙站了起来,拿一支笔在身后的白板上画了起来:“从道理上来说,一家企业,只有不断引进最优秀的恐龙,淘汰那些跟不上公司发展速度的青蛙,这样企业才有可能真正成长为一只强大的恐龙集团,你是不是这样认为?”看到小恐龙不由自主的点了点头,老青蛙继续说下去:“但是,你这个道理只是一种理论上的,而在实际中,能够在企业中站住脚并最终决定企业发展的,往往是那些出乎你意料之外的老青蛙,而那些理论上理应成为公司发展核心力量的恐龙们,他们却根本无法在企业中立足,除非他们愿意蜕变成为一只快乐的青蛙,否则的话,他们甚至连进入企业的资格都难以获得,更遑论成为企业发展的主导力量了。”
  
  “怎么会这样?”小恐龙忍不住问道。
  
  “这是因为,泥潭的存在。”老青蛙加重了语气:“只有青蛙的思考,才适合于泥潭的生存,只有青蛙,才能够在泥潭中获得快乐,而那些徒具理论却缺乏缺乏实践的恐龙,他们多半会陷入泥潭之中无法自拨。”说到这里,老青蛙在白板上写下“泥潭”两个字,然后猛然回身,目视小恐龙:“有没有听说过大猪说有,小猪说没有的故事?”
  
  “没有……”小恐龙回答道:“不对,是有……也不对……还是没有……”他没有想到正襟危坐对他授课的老青蛙突然开起了这么一个玩笑,仅仅是一个玩笑而已。有趣的是,这个玩笑里边藏有一个圈套,无论他怎么回答,都只能承认自己是一头蠢猪,区别无非是大小而已。
  
  “哈哈哈,”看着小恐龙抓耳搔腮的样子的样子,老青蛙快乐的大笑起来:“现在你知道了,什么叫泥潭呢?就是指的这样一种现实,它没有是非,不具价值,理论上的正常判断能力在这里派不上用场,是进亦忧,退亦忧,无论你如何努力或者是选择,都是一个错误。”说着,老青蛙用手里的油性笔重重的敲了敲白板:
  
  “比如说,在这一次竞争中,你的竞争对手们就遭遇到了进入泥潭。”
  
  “设计这个泥潭,对你又有什么好处?”小恐龙一气之下,脱口冒出这么一句话。
  
  “这个泥潭并不是我设计的,它是企业内外部各方博奕力量取得均衡的结果。”老青蛙沉声回答:“泥潭是一种客观的存在,无论我做出任何决定,都无法改变这个事实。”
  
  小恐龙困惑了:“这是什么意思?你是说即使你不做这种事,别的青蛙也会这么干吗?”
  
  “一点没错。”老青蛙冷笑着,俯身过来,用他那一双暴凸的蛙眼紧盯着小恐龙:“这种泥潭,它的本质是源于几千以来极为发达的谋略文化,它们相互之间盘根错节,渗透在民俗、民风、习惯与习性之中,它甚至融入了我们的血液,植根于我们的基因之中,主导着我们的思维方式,与我们存在须臾不可分割。”
  
  “所以我们要创建优秀的企业文化,”小恐龙眼睛一亮:“企业竞争之中,唯有先进的文化是不可以克隆的,我们要用先进的企业文化,摒弃这种小农经济状态下生长出来的不良氛围,彻底的改造我们的企业。”
  
  “哦,你在跟我谈企业文化,很好,真的很好。”老青蛙冷笑着:“那么,恐龙先生,你可以告诉我什么叫企业文化,它又是如何起到作用的吗?”
  
  听到这个问题,小恐龙的眼睛顿时一亮:“关于企业文化吗,可以解释为是在一定的历史条件下,一个企业或经济组织在长期实践中形成并被公众普遍认同的价值观念,企业精神,英雄模范,文化环境,产品品牌及经营战略的集合体,是一种凝聚人心实现自我价值、提升企业核心竞争力的无形力量和资本。而麦肯锡有一句简单的解释,所谓企业文化,就是我们做事的方法。”
  
  “一点没错,”老青蛙点头表示同意:“现在,你已经知道我们做事的方法了,你对此有什么疑问吗?”
  
  “当然有,”小恐龙兴致勃勃的道:“我们目前这种做法是不利于企业发展的,因此,我们才有必要创建全新的企业文化,引导我们的员工改变过去那种不规范的做法,实现群体效益的最大化,而不是相反。”
  
  “嗯,不错,”老青蛙笑道:“说到创建企业文化,我可以给你讲一个故事。”
  老青蛙的故事:酋长的淋浴室
  
  一个非洲酋长受邀前往美国访问,这个食人生番在全新的现代文明面前感受到了强烈的震撼,最让他为之惊讶的,是现代化的淋浴装置,这种可以自行调节水温的设置令他如醉如痴,于是他决定,等他回到部落之后,一定也要照这个样子制作一套。
  
  酋长回去之后,果然很快就制作成功了一套功能完整的淋浴设备,于是他喜洋洋的邀请美国人前来参观,最先来到的是一个贵妇人,她很惊讶于文明的传播竟然是如此之快。于是她走进浴室,脱下衣服,体验一下在这个野蛮的国度里盛开的文明之花的快乐。她试着拧开一个水龙头,淌出来的是凉水,再扭开另一个,流出来的是热水,正当她洗得高兴的时候,却突然发现身后的墙壁上有一个孔洞,一只眼睛正从孔洞中死死的盯着她看。
  
  贵妇人吓了一跳,她急忙穿上衣服,走出浴室,转到后面一看,原来是一个老年的黑人,正一只手提着一桶凉水,另一只手提着一桶热水,站在那个孔洞前入神的向里边瞧着。
  
  贵妇人非常气愤,问道:“你在看什么?”
  
  “我?”老黑人惊讶的回答道:“当然是在看你洗澡了。”
  
  贵妇人气得脸色痛红:“你为什么要看我洗澡?”
  
  老黑人提起手中的两只水桶,不高兴的回答道:“我要是不看着你洗澡,怎么知道你究竟是想要热水,还是想要凉水呢?”
  
  故事哲理:模仿永远只是外在的,核心的精神是无法模仿的。
  
  
  
  
  讲完这个故事之后,老青蛙站起来,走到小恐龙的面前,沉声说道:“听着,小恐龙,你要明白,企业文化不是无源之水,不是无根之木,它植根于现实的土壤之中,并受现实的力量所左右。不要自我陶醉在你那徒具外表的淋浴室中了,也不要拎着水桶趴在浴室外边偷窥女浴客了,睁大你的眼睛认清楚现实吧。”
  
  “现实!”老青蛙突然转身,厉声喝道:“现实就是这样,我们处身于无所不在的泥潭之中,在这里,只有青蛙的思想才获得了生存与发展的权力,庞然大物的恐龙式思维与观念只会沉陷在泥淖中无法自拨,如果你想体验到成长的快乐,那么,就从今天开始,抛开你那不切实际的理论和想法,认真的跟我学习泥潭生存哲学吧。”
  
  “在一桶脏水中,你不可能倒出一杯清水!”
  
  “只有当你学会了在泥潭中的生存,才谈得突破泥潭的制梏获得发展的可能。”
  
  老青蛙最后说道。
  4)
  
  《泥潭管理哲学》第二课
  
  “正因为有这些现象的存在,才需要我们付出更多的努力。”
  
  听了老青蛙的泥潭管理哲学之后,小恐龙很是不以为然:“文化中的负面因素固然是存在的,但那并不是全部,同样的道理,正因为有这些负面的、消极的因素存在,我们才需要引进全新的管理技术和管理思想,事实上,正是这些先进的管理思想与管理方法,才使得我们的雷龙集团在短短的时间内成长为一家大型的集团公司,这你总无法否认吧。”
  
  “说得没错,一点也没错!”老青蛙连连点头,他站起来,走到白板前:“我们泥潭国的经济发展,才不过二十几个年头,与侏罗纪那些恐龙公司相比,差得很远。远的不仅仅是公司的规模,最重要的是管理学上的思想。所以我们认真的学习,并将那些所谓的先进管理思想全盘照搬过来,看一看我们是如何搬来那些对我们的企业发展来说有价值的思想组成部分的吧。”
  
  说着,老青蛙在白板上画了两个三角形,并加以注明:(图形贴不上)
  
  
  这是在实施的层次面上,有关先进的营销思想、先进的研发模式乃至先进的产品技术,我们能够模仿得极为逼真,甚至比原有的管理思想体系更为完善,这个已经在实践中得到证实了。
  
  在掌握了先进的管理及经营思想之后,我们同样也学习了对方的运作面上的体系,但在这个层次面上,我们遭遇到了阻碍:说到这里,老青蛙又在黑板上画了一个正方形,一个平行四边形(图贴不上,只好略掉)
  
  
  
  这是因为,这些运作思想更多的体现在通过技术方面的功能集成,最终实现管理上的职能集成,而这种运作思想,它与我们的泥潭文化发生了直接冲突。所以,完好的体系在现实的泥淖中被扭曲,被变形,臂如说,那些风行一时的管理技术与工具,如ERP、如CRM等,在实际的导入过程中面临着空前的阻力,最终,这些原本应该体现在效益与效率上的管理工具,却演化成为企业的形象工程,这不能不说是我们本土文化力量抗拒先进管理思想的一次巨大成功。
  
  先进的管理学思想得以长驱直入,而在运作面上却遭遇到软性的抵抗,这与我们的泥潭文化有着重大的干系。究其本质,先进的管理思想能够满足所有的员工的好奇心与求知欲望,但在运作这一层次面上,事情就不那么简单了。
  
  运作层次面上的技术导入直接对企业的现状造成了冲击,生存意识的本能使得员工抗拒改变,这一点无可厚非。尽管管理学专家再三解释说企业的利益与员工的利益是一致的,但我们为什么需要这个解释?是因为员工的利益与企业的利益形成了冲突的现实。
  
  那么这种运作思想为什么在西方侏罗世界得以畅通无阻?
  
  不是这个样子的,西方的商业文化已经发展了两百余年,在这两百余年之间,企业与员工之间不断的在调整双方的关系,连续两百年不间断的调整,才推动了西方侏罗世界的信用文化的实现,劳资双方的博奕终于形成了现有的均衡局势。而在我们的泥潭国,这种信用是一种极为稀缺的猎物,不是说它不会出现,只是它一旦露头就会迅速的被不择手段的利益所轰毙!
  
  也就是说,构成这两个世界的心理文化基础不同,商业社会要求一种信用,对承诺的信守,唯其如此才得以保证整个社会的运转自如。而在泥潭国,因为缺乏信用,大家只好以一种警戒的目光打量着四周,防止遭受到欺骗或坑害,往往,这种情况都是在一种信任的状况下所发生的。所以油滑的处世态度才得以大行其道。
  
  中西文化对比图(也略了,靠)
  
  
  好,现在我们可以得到两个不同世界的管理体系的全部架构组合。说着,老青蛙把上面的三个图形组合起来,让小恐龙看清楚:
  
  侏罗纪恐龙世界文化与泥潭文化下的企业管理思想对比图(略)
  
  小恐龙狐疑的望着白板上的两个图形,好长时间,才问了一句:“你所说的大众心理文化基础,是不是指形成企业文化要素的基本心理条件?”
  
  老青蛙心满意足的点着头:“一点也没错,你很聪明。”
  
  “可是,”小恐龙愤懑的叫了起来:“我只是想知道,你所说的这种心理文化基础,它究竟是怎么妨碍我们企业成长的!”
  
  “这个吗,”老青蛙脸色阴郁的看着他:“你会知道的,你很快就会知道的。”
  5)
  
  第二天,小恐龙早早来到公司,老青蛙来得比他还早,打过卡之后,装腔做势的巡视一番,就偷偷溜出去吃早点了,上午快要过去了也没见他回来。小恐龙独自坐在座位上正东张西望,突然见到公司的总裁助理、一只漂亮的肉寇蛙跑过来叫他:“小恐龙,老青蛙哪里去了?老总让你们来他办公室一下。”
  
  小恐龙找不到老青蛙,只好吱唔道:“老青蛙他……我也不知道。”
  
  “不知道你早点说吗,真麻烦。”肉寇蛙总助白了他一眼:“那你先过来吧。”
  
  小恐龙不知是什么事,就跟着肉寇蛙总助进了总经理的办公室,总经理是一只胖头蛙,肥肥的大脑袋,正蹲踞在座位上听着对面的两只鳄鱼说话,见小恐龙进来,胖头蛙总经理皱起了眉头,问肉寇蛙总助:“老青蛙呢?他怎么没来?”总助回答了一句:“老青蛙不在,就小恐龙在。”胖头蛙总经理不高兴的瞪了小恐龙一眼:“他行吗?”
  
  小恐龙还没说话,一只大鳄鱼已经兴高采烈的叫了起来:“不就是去你们财务部门开张支票吗,谁都一样的。胖头蛙老总我可跟你说清楚了,这次市政府庆典活动是市长主抓的项目,你们雷龙集团是市里重点扶持的企业,在这关键时候一定要给其它企业做出表率作用,就这样说吧,你们对市政府这次庆典的支持力度,将直接决定本次庆典成功与否。”
  
  胖头蛙总经理脸上的皮肉抽搐着:“没那么严重,鳄鱼秘书长你言重了,象我们这种小公司……”他的眼睛落在了小恐龙身上:“小恐龙,你带这只小鳄鱼去财务处开张两百万的支票,市政府的庆典活动,我们公司资金再紧张,也是一定要支持的。”
  
  “才两百万?”鳄鱼秘书长不高兴了:“胖头蛙,我堂堂市政府秘书长的一张鳄鱼脸,才值两百万?”
  
  胖头蛙哈哈大笑起来:“鳄鱼秘书长,你可真会开玩笑,”然后他的声音突然压得低低的:“鳄鱼秘书长啊,你瞧瞧这家破公司,你是不知道啊,这么多的青蛙每天都要吃饭,现在的市场又是那么难做……”
  
  “好了好了,不要说了,两百万就两百万吧,总比没有强。”鳄鱼秘书长不高兴的打断胖头蛙的诉苦,凑近一些继续说道:“对了胖头蛙,我有个表弟,刚刚从村儿里进城,工作不是太好找,胖头蛙你看看是不是给安排一下?”
  
  小恐龙还待要听下去,一边的肉寇蛙总助悄悄的在他尾巴上踹了一脚:“还楞着干什么?老总不是说了让你办事去%

多媒体通信技术已广泛应用于社会的各个行业、各个领域,影响着人类的生活方式和生活质量,多媒体技术在电话网 ( 包括固定和移动电话网 ) 、广电网、计算机网上的应用取得了迅猛发展。在 Internet 上流媒体技术广泛应用,如视频点播、在线影院、远程医疗、远程教育、交互式电视等,满足各个行业网络化发展的需要。 由于多媒体技术的日渐成熟、手机技术的突破以及移动骨干网的扩容,给无线终端带来新的机遇和挑战,也给用户带来新的视听感受。

• 流媒体技术介绍

  流媒体指在 Internet/Intranet 中使用流式传输技术的连续时基媒体,如音频、视频或多媒体文件。 流媒体的核心部分是传输协议和文件格式。流式传输的实现有特定的实时传输协议,其中包括 Internet 本身的多媒体传输协议,以及一些实时流式传输协议等,只有采用合适的协议才能更好的发挥流媒体的作用,保证传输质量。 IETF ( Internet 工程任务组, Internet 规划与发展的主要标准化组织)已经设计出几种支持流媒体传输的协议。以下是几种传输协议的介绍:

1 实时传输协议 RTP

  RTP(Real-time Transport Protocol)是用于Internet 上针对多媒体数据流的一种传输协议。RTP被定义为在一对一或一对多的传输情况下工作,其目的是提供时间信息和实现流同步。RTP通常使用UDP来传送数据,但RTP也可以在TCP或ATM等其他协议之上工作。当应用程序开始一个RTP 会话时将使用两个端口:一个给RTP,一个给RTCP。RTP本身并不能为按顺序传送数据包提供可靠的传送机制,也不提供流量控制或拥塞控制,它依靠RTCP提供这些服务。通常RTP算法并不作为一个独立的网络层来实现,而是作为应用程序代码的一部分。

2 实时传输控制协议RTCP

  RTCP(Real-time Transport Control Protocol)和RTP一起提供流量控制和拥塞控制服务。在RTP会话期间,各参与者周期性地传送RTCP包。RTCP包中含有已发送的数据包的数量、丢失的数据包的数量等统计资料,因此,服务器可以利用这些信息动态地改变传输速率,甚至改变有效载荷类型。RTP和RTCP配合使用,它们能以有效的反馈和最小的开销使传输效率最佳化,因而特别适合传送网上的实时数据。

3 实时流协议RTSP

  实时流协议 RTSP(RealTime Streaming Protocol)是 由Real Networks和Netscape共同提出的,该协议定义了一对多应用程序如何有效地通过IP网络传送多媒体数据。RTSP在体系结构上位于RTP和RTCP之上,它使用TCP或RTP完成数据传输。

4 RSVP协议

  RSVP(Resource Reserve Protocol)是正在开发的Internet上的资源预订协议,使用RSVP能在一定程度上为流媒体的传输提供QoS,它是不传输数据的。

  RealSystem遵循上述所有传输协议。

• 移 动流媒体的基本业务和 编码基本要求

  移动流媒体基本业务可以分为以下三种典型业务模式:点播、直播、下载。 RealSystem能很好的实现这三种业务。

  移动流媒体相对于互联网上的流媒体有一些区别,兼容的格式更多,功能更强。要求在 20K、30K码率的基础上能达到一定的视频效果。

  移动流媒体系统编码基本要求 :

• 视频编解码应支持 H.263 和 MPEG-4

• 在 QCIF ( 176 × 144 ), 65K 色模式下视频帧频不低于 12 帧 / 秒

• 音频编解码应支持 G.723.1 、 AMR 、 AAC 、 MIDI 和 13K QCELP 编码

• 可选支持 EVRC 、 MP3 和 SMV 格式

• 要保证视频和音频的同步

• 支持 3g2 、 mp4 、 3gp 、 RM 和 WMV 格式

  RealSystem 支持目前联通 CDMA 网和中国移 GSM 网要求的所有流媒体格式。

  RealSystem 的编码有其独有的特点: RealSystem 采用可扩展视频技术作为其主要视频编解码,利用基于小波变换技术的 Real 专用算法,如连接速率低于编码时采用的速率,播放时服务器端丢弃不重要的信息,播放器解码尽可能还原视频质量。通过 SVT(scalablevideotechnology) 技术可以让速度较慢的电脑或手机不需要解开所有的原始图像数据也能流畅地观看节目;双向编码技术类似于可变化特率 (VBR) ,根据带宽的限制选择最优化压缩码率。为了更好地适应在网上传播,它还可以根据带宽来选择最佳压缩比率的 Real 文件, RealSystem 的编码工具能将多媒体信息记录成不同码率存在同一个文件,这就是所谓的 SureStream( 智能流 ) 技术。

• 基于 RealSystem的移动流媒体平台的系统实现

3.1 系统实现方案

  由于 RealSystem 具有上述的诸多优点,是实现移动流媒体平台一种比较好的选择方案,用 RealSystem 搭建的流媒体平台实现如下图:

根据不同的业务内容,在交换机上划分了不同的网段。

  管理网段:设置了 2台SUN F480作为多媒体管理平台服务器,采用SUN 3510磁盘阵列,形成HA架构。设置一台SUN F240作为PORTAL SERVER。

  点播 /直播网段:设置了16台点播/直播服务器,8台备份点播/直播服务器,服务器采用PC SERVER,REDHAT LINUX操作系统,通过4层交换机实现业务的负载均衡。

  下载网段:设置了 8台下载服务器,4台备份下载服务器,服务器采用PC SERVER,REDHAT LINUX操作系统,通过4层交换机实现业务的负载均衡。

  内容分发网段:设置了 2台内容分发服务器,1台备份内容分发服务器,服务器采用SUN F240,配置了SUN 3510磁盘阵列作为内容存储设备,通过4层交换机实现业务的负载均衡。

  采编服务器:设置一台 PC SERVER作为采编服务器,配置视频捕捉卡,对直播节目源进行编码。

  上述方案在单节点情况下满足 2万用户 并发使用下载服务, 3万用户 并发使用点播 /直播服务,采用50%的冗余服务器。如果有更多用户,则要扩展多节点模式。 系统采用多节点服务器来减轻中心服务器的压力,用户连接时系统总是寻找最近的流媒体服务器,如果该服务器上没有才从中心服务器复制。实况直播时采用这种结构进行分流,中心服务器将实况流传给所有节点服务器; Vod点播时流媒体服务器具有 Cache 功能,当后一个用户点播的和前一个用户点播内容相同时,不需要重新打开,节省时间,加快速度。

3.2 系统功能特点

1) 对网络带宽的适配功能

  对于移动用户,在同一地点的不同时间或在同一时间的不同地点所能使用的网络带宽会有很大不同,所以用统一带宽速率压缩的内容无法满足不同用户的实时播放需求。流媒体业务应根据用户的实际使用状况,提供带宽适配的功能。当用户在播放流媒体内容时,流媒体业务平台能够探测用户当前的实际带宽,然后把以接近实际带宽速率压缩的内容发送给用户,保障用户能够在不同的带宽情况下都能看到无中断的播放。

2) 负载均衡功能

  当流媒体系统有多个流媒体服务器时,系统具备为用户的流媒体服务请求选择最合适的流媒体服务器的能力。

3) 流媒体服务的中断和续传

  无线传输由于其网络的特殊性,容易出现阻塞和中断,影响用户观看,RealSystem提供断点续传功能,用户可从断点处往下观看,而不用从头开始观看。

4) 容错功能

  无线电传播环境恶劣或用户处于移动状态等诸多因素,均能造成无线电传播的损耗。多媒体信息经过压缩后对错误特别敏感,所以多媒体信息通过无线信道传播时,极易出现错误。 RealSystem通过采用带宽冗余和丢包重发机制来保证容错。

5) 跨平台性

  Real同微软相比,比较有优势的地方是Real的服务器和客户端的平台比较广泛,UNIX,LINUX,WINDOWS NT,都可以支持,并且在UNIX的平台上能够支持很多的用户,达到很稳定的效果。

四、 结语

  随着 2.5G 、 3G 等高速移动通信技术的逐渐成熟,同时手机、 PDA 等移动通信设备的不断完善,移动通信网已不仅能够提供传统的语音业务,还能提供高速率的带宽视频业务,支持高质量的语音、分组数据业务以及视频业务,流媒体技术将在移动通信中获得广泛应用,最终发展成为移动多媒体业务的主流。

原文:http://info.broadcast.hc360.com/html/001/002/014/019/001/59796.htm

2005年01月18日

目前网络上关于对象序列化的文章不少,但是我发现详细叙述用法和原理的文章太少。本人把自己经过经验总结和实际运用中的体会写成的学习笔记贡献给大家。希望能为整个java社区的繁荣做一点事情。
    序列化的过程就是对象写入字节流和从字节流中读取对象。将对象状态转换成字节流之后,可以用java.io包中的各种字节流类将其保存到文件中,管道到另一线程中或通过网络连接将对象数据发送到另一主机。对象序列化功能非常简单、强大,在RMI、Socket、JMS、EJB都有应用。对象序列化问题在网络编程中并不是最激动人心的课题,但却相当重要,具有许多实用意义。
一:对象序列化可以实现分布式对象。主要应用例如:RMI要利用对象序列化运行远程主机上的服务,就像在本地机上运行对象时一样。
二:java对象序列化不仅保留一个对象的数据,而且递归保存对象引用的每个对象的数据。可以将整个对象层次写入字节流中,可以保存在文件中或在网络连接上传递。利用对象序列化可以进行对象的“深复制”,即复制对象本身及引用的对象本身。序列化一个对象可能得到整个对象序列。
  从上面的叙述中,我们知道了对象序列化是java编程中的必备武器,那么让我们从基础开始,好好学习一下它的机制和用法。

    java序列化比较简单,通常不需要编写保存和恢复对象状态的定制代码。实现java.io.Serializable接口的类对象可以转换成字节流或从字节流恢复,不需要在类中增加任何代码。只有极少数情况下才需要定制代码保存或恢复对象状态。这里要注意:不是每个类都可序列化,有些类是不能序列化的,例如涉及线程的类与特定JVM有非常复杂的关系。

序列化机制:


序列化分为两大部分:序列化反序列化。序列化是这个过程的第一部分,将数据分解成字节流,以便存储在文件中或在网络上传输。反序列化就是打开字节流并重构对象。对象序列化不仅要将基本数据类型转换成字节表示,有时还要恢复数据。恢复数据要求有恢复数据的对象实例。ObjectOutputStream中的序列化过程与字节流连接,包括对象类型和版本信息。反序列化时,JVM用头信息生成对象实例,然后将对象字节流中的数据复制到对象数据成员中。下面我们分两大部分来阐述:


处理对象流:

(序列化过程和反序列化过程)

  java.io包有两个序列化对象的类。ObjectOutputStream负责将对象写入字节流,ObjectInputStream从字节流重构对象。
    我们先了解ObjectOutputStream类吧。ObjectOutputStream类扩展DataOutput接口。
writeObject()方法是最重要的方法,用于对象序列化。如果对象包含其他对象的引用,则writeObject()方法递归序列化这些对象。每个ObjectOutputStream维护序列化的对象引用表,防止发送同一对象的多个拷贝。(这点很重要)由于writeObject()可以序列化整组交叉引用的对象,因此同一ObjectOutputStream实例可能不小心被请求序列化同一对象。这时,进行反引用序列化,而不是再次写入对象字节流。
下面,让我们从例子中来了解ObjectOutputStream这个类吧。

  1. // 序列化 today’s date 到一个文件中.
  2.     FileOutputStream f = new FileOutputStream(“tmp”);
  3.     ObjectOutputStream s = new ObjectOutputStream(f);
  4.     s.writeObject(“Today”);
  5.     s.writeObject(new Date());
  6.     s.flush();


   现在,让我们来了解ObjectInputStream这个类。它与ObjectOutputStream相似。它扩展DataInput接口。ObjectInputStream中的方法镜像DataInputStream中读取Java基本数据类型的公开方法。readObject()方法从字节流中反序列化对象。每次调用readObject()方法都返回流中下一个Object。对象字节流并不传输类的字节码,而是包括类名及其签名。readObject()收到对象时,JVM装入头中指定的类。如果找不到这个类,则readObject()抛出ClassNotFoundException,如果需要传输对象数据和字节码,则可以用RMI框架。ObjectInputStream的其余方法用于定制反序列化过程。
例子如下:

  1. //从文件中反序列化 string 对象和 date 对象
  2.     FileInputStream in = new FileInputStream(“tmp”);
  3.     ObjectInputStream s = new ObjectInputStream(in);
  4.     String today = (String)s.readObject();
  5.     Date date = (Date)s.readObject();



定制序列化过程:



序列化通常可以自动完成,但有时可能要对这个过程进行控制。java可以将类声明为serializable,但仍可手工控制声明为static或transient的数据成员。
例子:一个非常简单的序列化类。

  1. public class simpleSerializableClass implements Serializable{
  2.     String sToday=“Today:”;
  3.     transient Date dtToday=new Date();
  4. }


序列化时,类的所有数据成员应可序列化除了声明为transient或static的成员。将变量声明为transient告诉JVM我们会负责将变元序列化。将数据成员声明为transient后,序列化过程就无法将其加进对象字节流中,没有从transient数据成员发送的数据。后面数据反序列化时,要重建数据成员(因为它是类定义的一部分),但不包含任何数据,因为这个数据成员不向流中写入任何数据。记住,对象流不序列化static或transient。我们的类要用writeObject()与readObject()方法以处理这些数据成员。使用writeObject()与readObject()方法时,还要注意按写入的顺序读取这些数据成员。
关于如何使用定制序列化的部分代码如下:

  1. //重写writeObject()方法以便处理transient的成员。
  2. public void writeObject(ObjectOutputStream outputStream) throws IOException{
  3.     outputStream.defaultWriteObject();//使定制的writeObject()方法可以
  4.                         利用自动序列化中内置的逻辑。
  5.     outputStream.writeObject(oSocket.getInetAddress());
  6.     outputStream.writeInt(oSocket.getPort());
  7. }
  8. //重写readObject()方法以便接收transient的成员。
  9. private void readObject(ObjectInputStream inputStream) throws IOException,ClassNotFoundException{
  10.     inputStream.defaultReadObject();//defaultReadObject()补充自动序列化
  11.     InetAddress oAddress=(InetAddress)inputStream.readObject();
  12.     int iPort =inputStream.readInt();
  13.     oSocket = new Socket(oAddress,iPort);
  14.     iID=getID();
  15.     dtToday =new Date();
  16. }



完全定制序列化过程:


如果一个类要完全负责自己的序列化,则实现Externalizable接口而不是Serializable接口。Externalizable接口定义包括两个方法writeExternal()与readExternal()。利用这些方法可以控制对象数据成员如何写入字节流.类实现Externalizable时,头写入对象流中,然后类完全负责序列化和恢复数据成员,除了头以外,根本没有自动序列化。这里要注意了。声明类实现Externalizable接口会有重大的安全风险。writeExternal()与readExternal()方法声明为public,恶意类可以用这些方法读取和写入对象数据。如果对象包含敏感信息,则要格外小心。这包括使用安全套接或加密整个字节流。到此为至,我们学习了序列化的基础部分知识。关于序
列化的高级教程,以后再述。

参考资料:http://java.sun.com/j2se/1.3/docs/guide/serialization/spec/serialTOC.doc.html

原文:http://www.javaresearch.org/article/showarticle.jsp?column=544&thread=11566

当在文件中定义了顶级类(top-level Class)的时候,文件名必须和顶级类的名字相同

一个类被定义为public的时候才可以被继承

警告:星号形式可能会增加编译时间——特别是在你引入多个大包时。因为这个原因,明确的命名你想要用到的类而不是引入整个包是一个好的方法。然而,星号形式对运行时间性能和类的大小绝对没有影响

任何声明为public的内容可以被从任何地方访问。被声明成private的成员不能被该类外看到。如果一个成员不含有一个明确的访问说明,它对于子类或该包中的其他类是可见的。这是默认访问。如果你希望一个元素在当前包外可见,但仅仅是元素所在类的子类直接可见,把元素定义成protected

對於類的聲明,類只能聲明為public或者默認,默認時只能夠被相同包中的其他類訪問

2package中如果存在相同名字的类,必须明确的在import语句中说明要使用的哪个类

Interface中可以定义方法的原形,并且不提供访问控制说明,因为在interface中声明的方法都是需要实现interface的类来实现的,在实现Interface的类中实现Interface中所声明的方法是,方法必须声明为public

警告:因为Java中在运行时动态查询方法与通常的方法调用相比会有一个非常庞大的花费,所以在对性能要求高的代码中不应该随意的使用接口。

通过Interface的应用变量调用实现后的方法和超类的应用调用子类的方法相似,同样的,这样的2个应用都是不能访问子类或者实现类的特有的方法的,这个可以归结为超类或者Interface所调用的是自己申明或者实现的而又被子类或者实现类实现或者重载的方法

抽象类的子类如果不声明为abstract那就比许实现首相类定义的所有抽象方法,这个是显而易见的,子类在继承父类的同时,也继承了父类的抽象方法,这个与Interface是相似的,如果一个类只是部分实现了Interface中定义的方法,那必须声明为abstract

通过接口引用变量获得接口的多重实现是Java完成运行时多态的最有力的办法finally创建一个代码块。该代码块在一个try/catch 块完成之后另一个try/catch出现之前执行。finally块无论有没有异常引发都会执行。如果异常被引发,finally甚至是在没有与该异常相匹配的catch子句情况下也将执行。一个方法将从一个try/catch块返回到调用程序的任何时候,经过一个未捕获的异常或者是一个明确的返回语句,finally子句在方法返回之前仍将执行。这在关闭文件句柄和释放任何在方法开始时被分配的其他资源是很有用的。finally子句是可选项,可以有也可以无。然而每一个try语句至少需要一个catchfinally子句。

自定義的異常類通過條件判斷用throw語句抛出,然後捕獲處理,不過這樣的處理好象多次一舉,直接通過條件判斷處理就行了,可能異常處理機制還有更深層次的玄機*^-^* 慢慢體會吧!有一點想法:儅有可能發生很多異常的時候,自定義的異常的處理就顯得合理了,因爲異常發生的不確定性,所以異常處理機制就使得程序的結構更加清晰,功能分離了- -||

如果你像多数程序员一样,那么你可能习惯于在方法失败时返回一个错误代码。在你用Java编程时,你应该打破这个习惯。当方法可能失败时,引发一个异常。这是处理失败模式的一个更简洁的方法。

最后说明一点:Java的异常处理语句不应该被当作是一个非本地分支的通常机制,如果你这样认为,它将困扰你的代码并使代码难于维护。

线程存在于好几种状态。线程可以正在运行(running)。只要获得CPU时间它就可以运行。运行的线程可以被挂起(suspend),并临时中断它的执行。一个挂起的线程可以被恢复(resume,允许它从停止的地方继续运行。一个线程可以在等待资源时被阻塞(block)。在任何时候,线程可以终止(terminate),这立即中断了它的运行。一旦终止,线程不能被恢复。

 

Java提供一个清晰的解决方案。没有“Monitor”类;相反,每个对象都拥有自己的隐式管程,当对象的同步方法被调用时管程自动载入。一旦一个线程包含在一个同步方法中,没有其他线程可以调用相同对象的同步方法。这就使你可以编写非常清晰和简洁的多线程代码,因为同步支持是语言内置的。

run()中可以定义代码来构建新的线程。理解下面内容是至关重要的:run()方法能够像主线程那样调用其他方法,引用其他类,声明变量。仅有的不同是run()在程序中确立另一个并发的线程执行入口。当run()返回时,该线程结束。直接調用run()方法屬於用戶調用,而實現多綫程需要JVM級的調用(public synchronized native void start();),所以用戶對run()方法的直接調用和普通方法的調用時一樣,並不能實現多綫程處理的預期。

构造函数(constructor)在对象创建时初始化。一旦定义了构造函数,在对象创建后,在new运算符完成前,构造函数立即自动调用。构造函数看起来有点奇怪,因为它没有任何返回值,即使是void型的值也不返回。这是因为一个类的构造函数内隐藏的类型是它自己类的类型。如果聲明了void型,构造函数(constructor)將不能被正確調用。

死锁发生在当两个线程对一对同步对象有循环依赖关系时。

Java 2中不能使用suspend()resume()stop() 方法来控制线程,线程必须被设计以使run() 方法定期检查以来判定线程是否应该被挂起,恢复或终止它自己的执行。由建立一个指示线程状态的标志变量来完成。當然一般也會用到繼承自Object類的方法wait()notify()

有效运用多綫程支持的关键是并发思考而不是连续思考。仔细的运用多线程,你能编写出非常有效的程序。然而要注意:如果你创建太多的线程,你可能会减弱而不是加强程序的性能。记住,上下文转换是需要开销的。如果你创建了太多的线程,更多的CPU时间会用于上下文转换而不是用来执行程序。

注意小应用程序没有main()方法,不像Java应用程序,小应用程序不以main()为程序起始。实际上,大多数小应用程序甚至不含main()方法。相反,当小应用程序类名被传输到小应用程序阅读器(applet view)或网络浏览器时它开始执行。

· 小应用程序不一定包含 main( ) 方法。

· 小应用程序必须在小应用程序阅读器或兼容JAVA的浏览器中运行。

· 用户输入/输出不是由Java的输入/输出流类来完成的。相反,小应用程序运用AWT提供的界面。

Transient 如果用transient声明一个实例变量,当对象存储时,它的值不需要维持。用来表示一个域不是该对象串行化的一部分。当一个对象被串行化的时候,transient型变量的值不包括在串行化的表示中,然而非transient型的变量是被包括进去的。

Volatile

Strictfp strictfp来修饰类或方法,可以确保浮点运算(以及所有切断)正如它们在早期Java版本中那样准确。切断只影响某些操作的指数。当一个类被strictfp修饰,所有该类的方法都自动被strictfp修饰。

Instanceof object instanceof type 这里,object是类的实例,而type是类的类型。如果object是指定的类型或者可以被强制转换成指定类型,instanceof将它评估成true,若不是,则结果为false。这样,instanceof是你的程序获得对象运行时类型信息的方法。似乎可以進行類型檢查?

 

2005年01月17日

线程的
  我知道Java是面向象的程序言,用Java行程序设计就是设计和使用Java提供了线Thread线程,线程与建普通的象的操作是一的,而线程就是Thread或其子象。下面是一个建启一个线程的句:
  Thread thread1=new Thread(); file://声明一个例,即建一个线程;
  Thread1.run(); file://Thread中的run()方法启动线程;
  从个例子,我可以通Thread()构造方法建一个线程,并启动该线程。事上,启动线程,也就是启动线程的run()方法,而Thread中的run()方法没有任何操作句,所以线程没有任何操作。要使线实现预定功能,必自己的run()方法。Java中通常有两方式定run()方法:
  通一个Thread的子,在中重写run()方法。Thread象就是一个线程,然,该线程有我自己设计线程体run()方法,启动线程就启了子中重写的run()方法。
  通Runnable接口,在接口中定run()方法的接口。所接口跟非常似,主要用来实现特殊功能,如复杂关系的多重承功能。在此,我一个实现Runnable() 接口的,在该类中定自己的run()方法,然后以该类参数Thread的构造方法来建一个线程。
  线程被实际创建后于待命状,激活(启线程就是启动线程的run()方法,是通过调线程的start()方法来实现的。
  下面一个例子践了如何通上述两方法线程并启
  // Thread的子类创建的线
   class thread1 extends Thread
    { file://自定义线程的run()方法;
     public void run()
      {
       System.out.println(“Thread1 is running…”);
      }
     }
   file://Runnable接口建的另外一个线程;
  class thread2 implements Runnable
   { file://自定义线程的run()方法;
    public void run()
    {
     System.out.println(“Thread2 is running…”);
    }
   }
   file://程序的主
   class Multi_Thread file://声明主
    {
     plubic static void mail(String args[]) file://声明主方法;
      {
       thread1 threadone=new thread1(); file://Thread的子类创线程;
       Thread threadtwo=new Thread(new thread2()); file://Runnable接口线程;
       threadone.start(); threadtwo.start(); file://strat()方法启动线程;
      }
     }
  运行程序就可以看出,线threadonethreadtwo交替占用CPU于并行运行状。可以看出,启动线程的run()方法是通过调线程的start()方法来实现(上例中主)start()方法启动线程的run()方法不同于一般的用方法,用一般方法,必等到一般方法行完才能返回start()方法,而启动线程的run()方法后,start()统该线程准可以启run()方法后,就返回start()方法start()方法句下面的句,这时run()方法可能在运行,这样线程的启和运行并行行,实现了多操作。
  线程的
  于多线程程序,线程的重要程度是不尽相同,如多个线程在等待CPU时间时,往往我需要高的线占到CPU时间得以行;又如多个线程交替决定了级别高的线程得到CPU的次数多一些且时间一些;这样,高线理的任效率就高一些。
  Java线程的从低到高以整数1~10表示,共分10是通过调线象的setPriority()方法,如上例中,
  thread1 threadone=new thread1(); file://Thread的子类创线程;
  Thread threadtwo=new Thread(new thread2()); file://Runnable接口线程;
  threadone.setPriority(6); file://threadone6
  threadtwo.setPriority(3); file://threadtwo3
  threadone.start(); threadtwo.start(); file://strat()方法启动线程;
  这样线threadone将会先于线threadtwo行,并将占有更多的CPU时间例中,级设置放在线程启前,也可以在启置,以足不同的需求。
 线程的(同)控制
  一个Java程序的多线程之可以共享数据。当线程以异方式访问共享数据,有候是不安全的或者不和逻辑的。比如,同一刻一个线程在取数据,另外一个线程在理数据,当理数据的线程没有等到取数据的线取完就去理数据,必然得到错误果。和我前面提到的取数据和理数据并行多任并不矛盾,儿指的是理数据的线程不能理当前没有束的数据,但是可以理其它的数据。
  如果我采用多线程同控制机制,等到第一个线取完数据,第二个线程才能数据,就会避免错误。可线程同是多线程的一个相当重要的技
  在讲线程的同控制前我需要交代如下概念:
  1 Java关键synchonized步对共享数据操作的方法
  在一个象中,用synchonized声明的方法方法。Java中有一个同模型-监视器,负责管理线对对象中的同方法的访问,它的原理是:该对象唯一一把,当多个线象,只有取得该对匙的线程才可以访问方法,其它线程在该对象中等待,直到该线程用wait()方法放弃匙,其它等待的线该钥匙,占到匙的线程后才可得以行,而没有取得匙的线程仍被阻塞在该对象中等待。
  file://声明同的一方式:将方法声明同
  class store
   {
    public synchonized void store_in()
    {
      ….
    }
    public synchonized void store_out(){
       ….}
    }
  2 利用wait()notify()notifyAll()方法送消息实现线的相互
  Java程序中多个线程通消息来实现动联系的,方法实现线的消息送。例如定一个象的synchonized 方法,同一刻只能有一个线访问该对象中的同方法,其它线程被阻塞。通常可以用notify()notifyAll()方法醒其它一个或所有线程。而使用wait()方法来使该线于阻塞状,等待其它的线程用notify()醒。
  一个实际的例子就是生售,生产单元将品生出来放在仓库中,仓库中提走品,在程中,元必仓库中有才能提;如果仓库中没有品,则销元必等待。
  程序中,假如我一个仓库类store该类象就相当于仓库,在store中定两个成方法:store_in(),用来模拟产品制造者仓库中添加品;strore_out()方法用来模拟销售者从仓库中取走品。然后定两个线customer,其中的run()方法通过调仓库类中的store_out()仓库中取走品,模拟销售者;另外一个线producer中的run()方法通过调仓库类中的store_in()方法向仓库添加品,模拟产品制造者。在主建并启动线程,实现仓库中添加品或取走品。
  如果仓库类中的store_in() store_out()方法不声明同就是个一般的多线程,我知道,一个程序中的多线程是交替行的,运行也是无序的,这样,就可能存在这样问题
  仓库中没有品了,售者在不断光,而且不停的在品,现实中是不可思的,在程序中就表现为负值;如果将仓库类中的stroe_in()store_out()方法声明同,如上例所示:就控制了同一刻只能有一个线访问仓库对象中的同方法;即一个生产类线访问被声明store_in()方法,其它线程将不能够访问对象中的store_out()方法,当然也不能访问store_in()方法。必等到该线wait()方法放弃匙,其它线程才有机会访问方法。
  个原理实际中也很好理解,当生者(producer)取得仓库唯一的匙,就向仓库中添放品,此其它的售者(customer,可以是一个或多个)不可能取得匙,只有当生者添放束,交还钥匙并且通知售者,不同的售者根据取得匙的先后与否决定是否可以仓库中提走

2005年01月14日

JCreator作爲輕量級的Java集成開發環境,非常適合個人學習使用,相比較JBuilder

Eclipse等的Java開發工具而言JCreator啓動的速度非常快,操作也很簡單,

在非大規模的企業應用時,JCreator也可以作爲輔助的代碼編寫工具,對於編寫.java.jsp文件來用起來也是得心應手。

EditPlus相比,JCreator代碼完成的功能比較悍,sigh

如果EditPlus支持代碼完成,偶就用EditPlus *^-^*

現在說下SourceFormatX,從名字就能看出來了SourceFormatX是代碼格式化的工具- -||

蝦米要把這個東東拿來和JCreator一起用涅? 原因也很明顯~JCreator不能格式化代碼 這個也是EditPlus的不足之

代碼完成麽實現,可能是通過API文檔~也想過反射機制,不過抽象類麽實現?所以應該是通過API文檔實現的了

C/C++通過同文件,,這樣的話,Java代碼的完成就很可能是通過文檔的了,JCreator通過開始用戶加載,Eclipse集成文檔

 

JCreator加入SourceFormatX的代碼格式化方法:

1.安裝JCreatorSourceFormatX(湊點字 – -b

2.運行JCreator打開Configure->Option找到Tool分支創建新工具

3.創建新工具的時候選擇Program,找到SourceFormatX所在目錄並選中SoureceFormatX.exe

4.選中Tool分支下生成的新工具,設定參數(Arguments)$[FileName] 目錄(Initial directory)隨便

5.JCreator中激活Tools工具條View->Toolbar->Tools

6.Ctrl+相應數字鍵或者直接點選就可以使用了(- -||這條好像有點過了)

 

呼呼,使用方法到此結束了,EditPlus中使用SoureFormatX方法也是一樣的

至於定義Scheme那就得根據個人來了,可能代碼規範不禁相同,不過運行SoureFormatX自己修改就是了,偶就不多說了

也不知道這算不算給SoureFormatX做廣告了,要是算,是不是可以弄點贊助 *^-^*