测试之路,与你同行!

发布新日志

  • 1.2

    2010-05-14 13:47:37



       UC评审,开发人员写完UC,给测试人员留足UC预审的时间,一般是在正式UC评审的前两天通知到测试人员。测试人员UC预审发现问题记录在预审文档中,在正式评审前,这些问题都必须关闭。正式评审时,开发人员讲解系统设计的流程,业务规则的逻辑判断,如果有demo,需在UC中体现出来。对于比较难思考的业务模块,一定要有demo的原型。
       设计文档评审,重点是开发人员对系统间接口的设计。接口测试的同学应当注意,了解输入参数和输出参数。同时,项目经理也要明确系统间依赖的强弱和优先级,对后续工作需要依赖的接口要优先实现,如果人员不足要积极的争取资源解决,避免使项目周期延长。

  • 今天心情不错

    2010-05-10 09:14:33

          今天心情不错,工作很多,积极应对。不同的事情,不同的态度,会收到不同的效果哦~~
  • 1.1

    2010-05-07 09:19:48

    1、项目需求文档评审
          接到一个项目,首先熟悉项目的性质,是原有功能改造,还是新功能增加,抑或系统优化。
          此项目是属于原有功能改造加系统优化,主要目的是节约成本。
          需求评审阶段,要预先熟悉PRD,功能改造后,是否解决了客户反馈的需求问题,性能上是否能满足客户的需求,是否影响用户体验。这些点有时候是相互制约的,有可能技术上为了提高性能会砍掉一部分需求,这时PD要评估此时的需求是否是达到了这个项目的预期。否则做上去的项目仍解决不了最根本的问题,就是浪费资源和时间了。
          在需求评审过程中,对于GUI级别的,可以从以往的经验中,发表自己认为合适的解决方案。对于节约系统成本这些,我们如果有能力去感知,那最好不过了。
    2、项目测试计划编写
          测试计划模板给出了测试计划中要反映的一些参照点,方便新人在做计划时不遗漏。测试计划主要涵盖以下几个方面:功能需求分解、测试时间安排、人员分工职责、项目约定、风险预估。
          现在重点是对于项目约定的执行和风险预估的把控。
          项目约定是由测试人员去推动的,没有约定不成方圆,项目约定在于规划和管理项目,用一些成功的项目经验来管理项目,最好在项目立项阶段就将约定发出来。
          风险把控这块,是大家要尝试着持续做下去。怎样识别风险,系统的,资源的。

           

  • JSP

    2010-04-22 15:52:56

       昨天学习了jdbc连接sqlserver。实践写了个登录的例子。
       今天学习了jsp,星星点点如下:

    JSP java服务器端页面技术)

    Java servlet服务器端技术,解释网络上相关数据。传统的Java程序通过命令行或运行可执行文件,  servelet通过加载在服务器段的web服务器上,所以服务器上必须安装java虚拟机。

    Asp使用的是vbjs. 运行方式是脚本级运行

    jsp使用的是java.编译生成字节码文件,后运行,运行速度快。

    JSP引擎 JSP服务器端

    Tomcat合成了两者,但不是很高效。

    JSP页面包括:HTML标记符、JAVA程序片(包含在<% %>间的内容)

                   静态            动态

    标记符区分大小写

    修改server.xml后需要重启tomcat。拷贝Connector可以增加端口

    Html标签:meta字体,采用协议。。。

    分隔标签:<br> ,换行

    <p>,换行,并其分段(上下文字隔了一行)

    分隔线:<hr>,横向分隔线

            <hr color=”#ff8000”> <hr width=”240”>  align=”right”右靠

    排盘标签:<p align=”left”> ..  </p>

    向右缩排标签:<blockquote> 向右缩排

         <pre> 。。</pre> 原封不动的呈现出中间的文字

    字形标签:<b>粗体 <i>斜体 <u>下划线

    JSP页面的基本结构:

    普通html标记

    Jsp标签,如指令标签、动作标签

    变量和方法的声明 %!开头 <%! Date date; %> 要以;结尾。 Jsp的类的成员变量,在整个jsp页面有效。只要jsp引擎服务器不重启,都有效。<%!%>之间声明类,在java程序片中可以使用该类创建对象。

    Java程序片 %之间,这里定义的变量是局部变量

    Java表达式 <%= %>之间插入一个表达式

    p标签

    <%@ page contentType=”text/html;charset-GB2312”%>

    <HTML>

    <BODY

     <%!

    Int i=0;                  

    %>

    <%

    I++;

    %>

    <p>

    您是本站的第

    <%  i=i++ %>个顾客

    </BODY>

    </HTML>

    charset=gb2312" /iso-8859-1" /

    服务器重启后,计数器会清空,所以将计数结果保存在文件中。

    Jsp中的注释分为两种:html注释 jsp注释

    Html注释 <-- -->之间加入注释内容

    Jsp注释 <%-- --%>之间。Jsp引擎忽略jsp注释,客户端浏览器查看Jsp源文件时,不能看到jsp注释        

    Jsp指令标签

    Page指令标签 ,告诉服务器jsp页面具有哪些属性,字符集、文件属性

    <%@ page 属性1=“属性1的值”  属性2=“属性2的值”…%>

    Page指令与其书写位置无关,习惯写在页面前面。

    属性值一般用双引号括起来。除了import属性外,其他属性只能指定一个值。Import可指定多值,用逗号隔开。

    <%@ page import=”java.util.*”java.io.*”,”java.awt.*””%>

    <%@ page contentType=”text/html;charset=GB2312”%>

    可以指定多个page指令,但是不能重复指定相同的属性和值

    Page指令的参数

    1Language属性

    Language定义jsp页面使用的脚本语言,属性默认值是java.<%A page language=”java” %>可不写

    2import属性 引入Java核心包中的类

    3contentType属性 定义jsp页面响应的MIME类型和JSP页面字符的编码。

    属性值的一般形式是”MIME类型”MIME类型;charset=编码”.

    contentType的默认值是”text/html;charset=ISO-8859-1”

    4session属性

    设置是否需要使用内置的session对象,属性值为truefalse

    默认属性值是true

    5buffer属性

    指定内置的输出流对象out设置的缓冲区大小或不使用缓冲区 <%@ page buffer=”24kb” %>

    6autoFlush属性

    指定out的缓冲区被填满时,缓冲区是否自动刷新。Truefalse。默认值是tru

  • Java 实现连接sql server 2000(JDBC数据库访问例子)

    2010-04-21 13:14:35

    Java 实现连接sql server 2000(JDBC数据库访问例子)

     

    第一种:通过ODBC连接数据库

    JAVA语言的跨平台的工作能力(Write Once ,Run Anywhere)、优秀的图像处理能力(我相信现在没有那种语言可以超过JAVA在网络上的图形处理能力)、网络通信功能、通过JDBC数据库访问技术等等,让我们谁都不可否认JAVA语言是SUN公司对于计算机界的一个巨大的贡献。笔者可以描述这样一个场景:有一天你上网完全可以不用IE 或者NETSCAPE,上网就像是玩游戏,你可以获得游戏那么精美的图像和互动的感觉,如果你玩过UO,也许你就知道那种感觉了,但是JAVA做成的东西一定会超过UO的,因为不单单是游戏,也不是单单是浏览器,如果你愿意(要你有钱,有时间,有优秀的JAVA人才)你可以把所有的这一切用Java完全集成出来!!!我不是夸大JAVA的功能,大家可以访问一下http://www.simchina.net的那个社区程序,你就能找到一种感觉了:相信我没有说什么假话 。好了,不说废话了,现在我向你介绍JAVA的数据库访问技术----JDBC数据库访问技术(你可千万不要搞成ODBC了哟!)。

      JDBC技术事实上是一种能通过JAVA语言访问任何结构化数据库的应用程序接口(API)(Sun这样说的,我也不知道是不是真的),而且现在的JDBC 3.0Sun说也能访问Execel等电子表格程序
    !

      JDBC对于数据库的访问有四种方式,我们这里只是介绍两种:


      第一种是通过ODBC做为”(Bridge)对数据库访问,第二种是直接对数据库访问。


      我们先来看看第一种JDBC<-->ODBC访问的流程:

      JDBC Driver Mannager->JDBC<->ODBC->ODBC->数据库客户机驱动库->数据库服务器->返回查询结果,在这种访问中值的我们注意的是虽然JAVA"Write Once ,Run Anywhere",但是如果通过这种访问的话,需要客户端必须设置ODBC和有相应的数据库客户机的驱动,当你看了下面的另外一个流程的时候或许你会想:明明下一种更方面,为什么还要有这个东西的产生!呵呵,因为,未必所有的数据库服务器提供商都提供下面的JDBC驱动程序(给JDBC访问提供相应的接口),所以就有了JDBC<->ODBC Bridge

      接着再让我们来看看第二种访问流程:


      JDBC Driver Mannager->局部JDBC驱动->客户端数据库->数据库服务器->返回查询结果,这种访问事实上是转换JDBC调用为相应的数据库(Oracle, Sybase, Informix, DB2, 和其他的数据库数据库管理系统)的客户端API调用(这么说,不知道大家能不能懂,说简单点就好像ASP不是通过DSN对数据库访问而是通过OLEDB访问,说道这里我还是不知道大家能不能明白我的意思。哎呀,不要扔鸡蛋嘛!),这种方式的访问需要相应的数据库提供商提供相应的JDBC驱动程序,但是有一种好处,可以独立于odbc用于可以随处可Run的客户端的浏览器中的Applet程序。

    我们下面将给大家一个通过JDBC-ODBC桥数据库访问的实例,但是在看下面的事例前我想问大家一次:JDK1.3装了吗?数据库驱动装了吗(我使用的是SQLserver)?你该没有使用Linux吧?虽然java支持Linux,但是老兄我可没有使用Linux(这同JAVAWrite Once ,Run Anywhere没有关系),由于使用了运行于Win下面的ODBC,我建议你看看这篇东西http://www.aspcn.com/showarticle.asp?id=112,否则你要是有了问题,出不了结果那岂不是要怪我(不过欲加之罪,何患无吃... ...),冤枉呀!

    哎呀,说了这么多的废话,还是让我们来看看到底JDBC的调用吧!既然我们是通过odbc访问数据库,所以这个odbc是跑不了的,我们先来设置你的odbc:打开你的odbc数据源->选择系统dsn(Click加新的dsn-)->接下来输入选择数据库类型、输入dsn:、选择服务器、连接数据库的方式、输入数据库的登陆用户和密码->测试连接,如果测试成功的话,那么你的dsn就建立好了,我的dsn名为Sqlserver.使用的是sqlserver7.0, “sa”登陆,密码为空。这些东西都是后面要用道的!

      好了下面让我们来看程序代码: (该代码已经通过运行)

    //###########################################################
    //
    代码开始
    //###########################################################

    import java.sql.*;
    //
    加载java数据连接包,java基本所有的数据库的调用的都在这个东西里面

    public class InsertCoffees {

    public static void main(String args[]) {

    String url = "jdbc:odbc:sqlserver";
    //
    取得连接的url名,注意sqlserverdsn

    Connection con;
    //
    实例化一个Connection对象

    Statement stmt;
    String query = "select * from col_link";
    //
    选择所有的Col_link表中的数据输出


    try {
    Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
    //
    加载jdbc-odbc桥驱动


    } catch(java.lang.ClassNotFoundException e) {
    System.err.print("ClassNotFoundException: ");
    //
    加载jdbc-odbc桥错误

    System.err.println(e.getMessage());
    //
    其他错误

    }

    try {

    con = DriverManager.getConnection(url, "sa", "");
    //
    数据库连接



    stmt = con.createStatement();
    //Create
    一个声明

    stmt.executeUpdate("CREATE TABLE col_link (sitename varchar (20) NULL ,siteurl varchar (50) NULL) ");
    //
    执行了一个sql语句生成了一个表col_link的表

    stmt.executeUpdate("insert into col_link values('ASP
    中华网
    ','http://www.aspcn.com')");
    stmt.executeUpdate("insert into col_link values('
    永远到底有多远
    ','http://xuankong.com')");
    //
    执行一个insert into语句

    stmt.executeUpdate("update col_link set siteurl='http://www.aspcn.com/xuankong/xuankongt.jpg' where siteurl='http://xuankong.com'");
    //
    执行一个update语句,更新数据库

    ResultSet rs = stmt.executeQuery(query);
    //
    返回一个结果集

    System.out.println("Col_link
    表中的数据如下(原始数据)");
    //
    下面的语句使用了一个while循环打印出了col_link表中的所有的数据

    System.out.println("
    站点名 "+" "+"站点地址
    ");
    System.out.println("---------------"+" "+"----------------");
    while (rs.next()) {
    String s = rs.getString("sitename");
    String f = rs.getString("siteurl");
    //
    取得数据库中的数据

    System.out.println(s + " " + f);
    /*String t = rs.getString(1);
    String l = rs.getString(2);
    System.out.println(t + " " + l);*/
    /*jdbc
    提供了两种方法识别字段,一种是使用getXXX(注意这里的getXXX表示取不同类型字段的不同的方法)获得字段名,

    第二种*是通过字段索引,在这里我把第二种方法注释了
    */
    /*
    你可以访问这个连接获得getxxx的用法:
    http://java.sun.com/docs/books/tutorial/jdbc/basics/_retrievingTable.html*/
    }
    stmt.close();
    con.close();
    //
    上面的语句关闭声明和连接

    } catch(SQLException ex) {
    System.err.println("SQLException: " + ex.getMessage());
    //
    显示数据库连接错误或者查询错误

    }
    }
    }

    //###########################################################
    //
    代码结束
    //###########################################################


      在上面这个程序中我想你展示了如何使用JDBC-ODBC连接数据库,使用SQL语句生成一个表,使用SELECTINSERT UPDATE语句取的、插入和更新一个表中的数据,如何通过字段名和字段索引访问数据库中的东东!我希望你能从上面的代码真正的学习到一些东西!


      发挥你的想象力,设想一下JAVA到底,比如说可以通过数据库做一个不需要GUI(图形用户界面)的聊天室,呵呵,感觉起来就像在DOS环境下打字的聊天室!哈哈!


      最后需要说的是笔者的调试上面程序的环境:WIN2000 , JDK1.3,MS SQLSERVER编辑软件:EDITPLUS 2.01a(这最后的东西可不是废话,虽然早就了一些专业的JAVA开发工具,但是笔者建议JAVA初学者使用文本软件开发JAVA程序)

    第二种:直接用jdbc访问数据库

    (1) 该实例已经运行通过

    jsp连接Sql Server7.0/2000数据库
      testsqlserver.jsp如下:

      
    <%@ page contentType="text/html;charset=gb2312"%>
      
    <%@ page import="java.sql.*"%>
      
    <html>
      
    <body>
      
    <%Class.forName("com.microsoft.jdbc.sqlserver.SQLServerDriver").newInstance();
      
    String url="jdbc:microsoft:sqlserver://localhost:1433;DatabaseName=pubs";
      //pubs为你的数据库的

      
    String user="sa";
      
    String password="";
      

      Connection conn= DriverManager.getConnection(url,user,password);
      
    Statement stmt=conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,ResultSet.CONCUR_UPDATABLE);
      
    String sql="select * from test";
      
    ResultSet rs=stmt.executeQuery(sql);
      
    while(rs.next()) {%>
      您的第一个字段内容为:
    <%=rs.getString(1);%>
      您的第二个字段内容为:
    <%=rs.getString(2);%>
      
    <%}%>
      <%out.print("数据库操作成功,恭喜你
    ");%>
      
    <%rs.close();
      
    stmt.close();
      
    conn.close();
      

      %>
      
    </body>
      </html>

    (2)java访问sqlserver服务器

    第一步:安装jdbc

    点击SQL Server for JDBC驱动程序安装程序setup.exe(可以到微软网站下载 http://msdn.microsoft.com/library/default.asp?rul=/downloads/list/sqlserver.asp下载)

    第二步:设置系统变量classpath

    假设SQL Server for JDBC 驱动程序安装在d\jdbc\,则classpath应该设置如下:

    classpath:=.;…;d:\jdbc\lib; d:\jdbc\lib\mssqlserver.jar; d:\jdbc\lib\msutil.jar; d:\jdbc\lib\msbase.jar;

    注意:设置时要在最前面的点号和分号

    第三步:编辑java程序并且运行

    实例1如下:

    //import com.microsoft.*;

    //注意:在javasql server 连接时不需要这个包,其他书上说这个包是必需的,这个问题有待进一步讨论

    import java.sql.*;

    import java.net.URL;

    class insert

    {

           public static void main(String[] args)

           {

            String url="jdbc:microsoft:sqlserver://localhost:1433;DatabaseName=northwind";

                  String query="select * from categories";

                  String query1="insert categories values(10,'Hanbao','Sweet')";

                  String query2="insert categories values(11,'Naicha','Coffee taste')";

                  try

                  {

                     Class.forName("com.microsoft.jdbc.sqlserver.SQLServerDriver");

                     Connection con=DriverManager.getConnection(url,"sa","739555");

                     Statement stmt=con.createStatement();

                     stmt.executeUpdate(query1);

                     stmt.executeUpdate(query2);

                     stmt.close();

                     con.close();

                  }

                  catch(SQLException ex)

                  {

                  }

                  catch(java.lang.Exception ex)

                  {

  • 毕业后的五年拉开大家差距的原因(转)

    2010-04-19 09:41:50

    有人工作, 有人继续上学,大家千万不要错过这篇文章,能看到这篇文章也是一种幸运,真的受益匪浅,对我有很大启迪,这篇文章将会改变我的一生,真的太好了,希望与有 缘人分享,也希望对有缘人有所帮助!看完之后有种“相见恨晚”的感觉,特别激动,希望大家好好的珍藏这篇文章,相信多年以后,再来看这篇文章,一定有不同 的感觉。
            正如"打工皇帝"唐骏说:"我觉得有两种人不要跟别人争利益和价值回报。第一种人就是刚刚进入企业的人,头5年千万不要说你能不能多给我一点儿工资,最重要的是能在企业里学到什么,对发展是不是有利……"
           人总是从平坦中获得的教益少,从磨难中获得的教益多;从平坦中获得的教益浅,从磨难中获得的教益深。一个人在年轻时经历磨难,如能正确视之,冲出黑暗,那就是一个值得敬慕的人。最要紧的是先练好内功,毕业后这5年就是练内功的最佳时期,练好内功,才有可能在未来攀得更高。
            出路在哪里?出路在于思路!
      其实,没有钱、没有经验、没有阅历、没有社会关系,这些都不可怕。没有钱,可以通过辛勤劳动去赚;没有经验,可以通过实践操作去总结;没有阅历,可以一步一步去积累;没有社会关系,可以一点一点去编织。但是,没有梦想、没有思路才是最可怕的,才让人感到恐惧,很想逃避!
      人必须有一个正确的方向。无论你多么意气风发,无论你是多么足智多谋,无论你花费了多大的心血,如果没有一个明确的方向,就会过得很茫然,渐渐就丧失了斗志,忘却了最初的梦想,就会走上弯路甚至不归路,枉费了自己的聪明才智,误了自己的青春年华。
        荷马史诗《奥德赛》中有一句至理名言:"没有比漫无目的地徘徊更令人无法忍受的了。"毕业后这5年里的迷茫,会造成10年后的恐慌,20年后的挣扎,甚至一辈子的平庸。如果不能在毕业这5年尽快冲出困惑、走出迷雾,我们实在是无颜面对10年后、20年后的自己。毕业这5年里,我们既有很多的不确定,也有很多的可能性。
      毕业这5年里,我们既有很多的待定,也有很多的决定。
      迷茫与困惑谁都会经历,恐惧与逃避谁都曾经有过,但不要把迷茫与困惑当作可以自我放弃、甘于平庸的借口,更不要成为自怨自艾、祭奠失意的苦酒。生命需要自己去承担,命运更需要自己去把握。在毕业这5年里,越早找到方向,越早走出困惑,就越容易在人生道路上取得成就、创造精彩。无头苍蝇找不到方向,才会四处碰壁;一个人找不到出路,才会迷茫、恐惧。
       生活中,面对困境,我们常常会有走投无路的感觉。不要气馁,坚持下去,要相信年轻的人生没有绝路,困境在前方,希望在拐角。只要我们有了正确的思路,就一定能少走弯路,找到出路!
           成功的人不是赢在起点,而是赢在转折点。
        不少刚刚毕业的年轻人,总是奢望马上就能找到自己理想中的工作。然而,很多好工作是无法等来的,你必须选择一份工作作为历练。职业旅程中的第一份工作,无 疑是踏入社会这所大学的起点。也许你找了一份差强人意的工作,那么从这里出发,好好地沉淀自己,从这份工作中汲取到有价值的营养,厚积薄发。千里之行,始 于足下,只要出发,就有希望到达终点。
        起点可以相同,但是选择了不同的拐点,终点就会大大不同!
        毕业这几年,我们的生活、感情、职业等都存在很多不确定的因素,未来也充满了各种可能。这个时候,必须学会选择,懂得放弃,给自己一个明确的定位,使自己稳定下来。如果你不主动定位,就会被别人和社会"定型"!
      可以这么说:一个人在毕业这5年培养起来的行为习惯,将决定他一生的高度。我们能否成功,在某种程度上取决于自己对自己的评价,这就是定位。你给自己定位是什么,你就是什么。定位能决定人生,定位能改变命运。丑小鸭变成白天鹅,只要一双翅膀;灰姑娘变成美公主,只要一双水晶鞋。
        人的命,三分天注定,七分靠打拼,有梦就"会红",爱拼才会赢。只要不把自己束缚在心灵的牢笼里,谁也束缚不了你去展翅高飞。
        现实情况远非他们所想的那样。于是,当优越感逐渐转为失落感甚至挫败感时,当由坚信自己是一块"金子"到怀疑自己是一粒"沙子"时,愤怒、迷茫、自卑就开始与日俱增。
        其实,应该仔细掂量一下自己,你是否真是金子?是真金,手中要有绝活,才能上要有过人之处才行。一句话:真金是要靠实力来证明的,只有先把自己的本领修炼好了,才有资格考虑伯乐的事情
       每颗珍珠原本都是一粒沙子,但并不是每一粒沙子都能成为一颗珍珠。
       想要卓尔不群,就要有鹤立鸡群的资本。忍受不了打击和挫折,承受不住忽视和平淡,就很难达到辉煌。年轻人要想让自己得到重用,取得成功,就必须把自己从一粒沙子变成一颗价值连城的珍珠。
           天有下雨与日出,人生高峰与低谷。
            莫为浮云遮望眼,风物长宜放眼量。
        只要拂去阴霾,就能亮出朗朗晴空。如果你在工作上有些不如意,要相信自己不会一直处于人生的低谷期,总有一天能冲破重重云层。告诉自己:我并没有失败,只是暂时没有成功!只要在内心点亮一盏希望之灯,一定能驱散黑暗中的阴霾,迎来光明。
        的确,论资历,他们是不折不扣的职场菜鸟,业务涉及不深,人脉一穷二白,在工作中经常碰壁。他们的压力并不一定都像千钧大石,而是像大雨来临前的天色,灰色低沉,明明有空间,却被灰色填满每个缝隙,只能等待大雨倾盆之后的晴空。
      "起得比鸡早,睡得比狗晚,干得比驴多,吃得比猪差。"这是很多刚刚毕业的人喜欢用来调侃自己生活状态的话。虽然有点儿夸张,但是,他们中的很多人的确一直都被灰色心情所笼罩--心里永远是多云转阴。记得有位哲人曾说:"我们的痛苦不是问题本身带来的,而是我们对这些问题的看法产生的。"换个角度看人生,是一种突破、一种解脱、一种超越、一种高层次的淡泊与宁静,从而获得自由自在的快乐。
        一位哲人说:"人生就是一连串的抉择,每个人的前途与命运,完全把握在自己手中,只要努力,终会有成。"就业也好,择业也罢,创业亦如此,只要奋发努力,都会成功。你是不是准备把生命的承诺全部都交给别人?
      毕业后这5年,是改变自己命运的黄金时期。在最能决定自己命运时,如果还不把握,那你还要等到什么时候呢?我的人生我做主,命运由己不由人。
      不要活在别人的嘴里,不要活在别人的眼里,而是把命运握在自己手里。
       别说你没有背景,自己就是最大的背景。美国作家杰克·凯鲁亚克说过一句话:"我还年轻,我渴望上路。"在人生的旅途中,我们永远都是年轻人,每天都应该 满怀渴望。每个人的潜能都是无限的,关键是要发现自己的潜能和正确认识自己的才能,并找到一个能充分发挥潜能的舞台,而不能只为舞台的不合适感到不快。要 客观公正地看待自己的能力,结合自己的实际情况和爱好冷静选择,尽可能到最需要自己、最适合自己的地方。
         在人力资源管理界,特别流行一个说法,即"骑马,牵牛,赶猪,打狗"理论:人品很好,能力又很强的,是千里马,我们要骑着他;人品很好但能力普通的,是老 黄牛,我们要牵着他;人品、能力皆普通的,就是"猪",我们要赶走他;人品很差能力很强的,那是"狗",我们要打击他。
        我想,刚刚毕业几年的你,一样胸怀大志,一样想成为一匹被人赏识、驰骋沙场的千里马吧?那么,就好好沉淀下来。低就一层不等于低人一等,今日的俯低是为了明天的高就。所谓生命的价值,就是我们的存在对别人有价值。能被人利用是一件好事,无人问津才是真正的悲哀!
        能干工作、干好工作是职场生存的基本保障。
        任何人做工作的前提条件都是他的能力能够胜任这项工作。能干是合格员工最基本的标准,肯干则是一种态度。一个职位有很多人都能胜任,都有干好这份工作的基本能力,然而,能否把工作做得更好一些,就要看是否具有踏实肯干、苦于钻研的工作态度了。
        在能干的基础上踏实肯干。
        工作中,活干得比别人多,你觉得吃亏;钱拿得比别人少,你觉得吃亏;经常加班加点,你觉得吃亏……其实,没必要这样计较,吃亏不是灾难,不是失败,吃亏也是一种生活哲学。现在吃点儿小亏,为成功铺就道路,也许在未来的某个时刻,你的大福突然就来了。
       能吃亏是做人的一种境界,是处世的一种睿智
        在工作中并不是多做事或多帮别人干点儿活就是吃亏。如果领导让你加加班、赶赶任务,别以为自己吃了大亏,反而应该感到庆幸,因为领导只叫了你,而没叫其他人,说明他信任你、赏识你。吃亏是一种贡献,你贡献得越多,得到的回报也就越多。乐于加班,就是这样的一种吃亏。
        舍得舍得,有舍才有得;学会在适当时吃些亏的人绝对不是弱智,而是大智。
      给别人留余地就是给自己留余地,予人方便就是予己方便,善待别人就是善待自己。
       傻人有傻福,因为傻人没有心计。和这样的人在一起,身心放松,没有太多警惕,就能相互靠近。傻在很多时候意味着执着和忠贞,也意味着宽厚和诚实,让人不 知不觉站到他一边。傻人无意中得到的,比聪明人费尽心机得到的还多。毕业这几年,你的天空中只飘着几片雪花,这样你就满足了吗?成功需要坚持与积累,与其专注于搜集雪花,不如省下力气去滚雪球。巴菲特说:"人生就像滚雪球,最重要的是发现很湿的雪和很长的坡。"让自己沉淀下来,学着发现"很湿的雪",努力寻找"很长的坡"。记住:散落的雪花会很快融化,化为乌有,只有雪球才更实在,才能长久。
    在毕业这几年里,你要是能做到比别人多付出一分努力,就意味着比别人多积累一分资本,就比别人多一次成功的机会。
       什么是职业化呢?职业化就是工作状态的标准化、规范化、制度化,即在合适的时间、合适的地点用合适的方式说合适的话、做合适的事,使知识、技能、观念、思维、态度、心理等符合职业规范和标准。" 在每个行业里,都有很多出色的人才,他们之所以能存在,是因为比别人更努力、更智慧、更成熟。但是,最重要的是,他们比一般人更加职业化!这就是为什么我 现在能当你老板的原因。一个人仅仅专业化是不够的,只有职业化的人才能飞在别人前面,让人难以超越!"不要以为我们现在已经生存得很安稳了。对于毕业5年 的人来讲,一定要认清即将面临的五大挑战。

    一、赡养父母。
    二、结婚生子。
    三、升职加薪。
    四、工作压力。
    五、生活质量。
        有的人为生存而雀跃,目光总是停在身后,三天打鱼两天晒网,有始无终。
       有的人为发展而奋斗,目光总是盯在正前方,每天进步一点点,坚持不懈。
      毕业这几年,不能没有追求和探索,不能没有理想和目标。人生如逆水行舟,不进则退。甘于现状的生活就是不再前行的船,再也无法追上时代前进的步伐。一定要抓紧每一秒钟的时间来学习,要明白学习不是学生的专利。小聪明的人最得意的是:自己做过什么?大智慧的人最渴望的是:自己还要做什么?
      小聪明是战术,大智慧是战略;小聪明看到的是芝麻,大智慧看到的是西瓜。
      在这个世界上,既有大人物,也有小角色,大人物有大人物的活法,小人物有小人物的潇洒,每个人都有自己的生活方式,谁也勉强不了谁。但是,小聪明只能有小成绩和小视野,大智慧才能有大成就和大境界。小企业看老板,中企业看制度,大企业看文化。
        小公司与大企业都有生存之道,没有好坏之分,但对一个人不同阶段的影响会不同。
      小公司肯定想要发展为大企业,这是一种目标,年轻人也要给自己的职业生涯制定目标。毕业几年的你,是否经常会怯场或者是感到没有底气?居安思危绝对不是危言耸听!此刻打盹,你将做梦;此刻学习,你将圆梦。在竞争激烈的人生战场上,打盹的都是输家!
       每个人在年轻的时候似乎都豪情万丈,什么都不怕,可是随着年龄的增长,每天想着房子、工作、养家糊口这些俗事儿,再也没有年轻时那种敢于"上天探星、下海 捞月"的勇气了。是我们改变了生活,还是生活改变了我们?我们的思想越来越复杂,因为有了越来越多的舍不得、越来越多的顾虑,我们总是在徘徊、总是在犹 豫。毕业开始一两年,生活的重担会压得我们喘不过气来,挫折和障碍堵住四面八方的通口,我们往往在压迫得自己发挥出潜能后,才能杀出重围,找到出路。可是 两三年后,身上的重担开始减轻,工作开始一帆风顺,我们就松懈了下来,渐渐忘记了潜在的危险。直到有一天危机突然降临,我们在手足无措中被击败……毕业这 几年,仍然处于危险期,一定要有居安思危的意识,好好打拼,这样才能有一个真正的安全人生!
       生于忧患,死于安乐。如果你想跨越自己目前的成就,就不能画地自限,而是要勇于接受挑战。对畏畏缩缩的人来说,真正的危险正在于不敢冒险!
        年轻人在社会的重压下,适应能力已变得越来越强,只是他们不自觉地习惯被环境推着走。他们不敢冒险,怕给自己带来终身的遗憾,于是告慰自己:"我对得起自己、对得起家人,因为我已竭尽全力。"其实,人只有不断挑战和突破才能逐渐成长。长期固守于已有的安全感中,就会像温水里的青蛙一样,最终失去跳跃的本能
        经历了这几年社会生活,你应该明白:这个世界上有富也有贫,有阴也有亮,有丑也有美,到底看到什么,取决于自己是积极还是消极。在年轻时学会勤勉地工作,用一种光明的思维对待生活,那么,只要张开手掌,你就会发现,里面有一片灿烂的人生。
        把感恩刻在石头上,深深地感谢别人帮助过你,永远铭记,这是人生应有的一种境界;把仇恨写在沙滩上,淡淡忘掉别人伤害过你,学会宽容,让所有的怨恨随着潮水一去不复返,这也是一种人生境界。
       学会倒出水,才能装下更多的水。从毕业那天开始,学会把每天都当成一个新的起点,每一次工作都从零开始。如果你懂得把"归零"当成一种生活的常态,当成一种优秀的延续,当成一种时刻要做的事情,那么,经过短短几年,你就可以完成自己职业生涯的正确规划与全面超越。
       在职业起步的短短道路上,想要得到更好、更快、更有益的成长,就必须以归零思维来面对这个世界。不要以大学里的清高来标榜自己,不要觉得自己特别优秀, 而是要把自己的姿态放下,把自己的身架放低,让自己沉淀下来,抱着学习的态度去适应环境、接受挑战。放下"身段"才能提高身价,暂时的俯低终会促成未来的 高就。
      年轻人从校园或者从一个环境进入一个新环境,就要勇于将原来环境里熟悉、习惯、喜欢的东西放下,然后从零开始。我们想在职场上获得成 功,首先就要培养适应力。从自然人转化为单位人是融入职场的基本条件。一个人起点低并不可怕,怕的是境界低。越计较自我,便越没有发展前景;相反,越是主 动付出,那么他就越会快速发展。很多今天取得一定成就的人,在职业生涯的初期都是从零开始,把自己沉淀再沉淀、倒空再倒空、归零再归零,正因为这样,他们 的人生才一路高歌,一路飞扬。
      在毕业这几年里,我们要让过去归零,才不会成为职场上那只背着重壳爬行的蜗牛,才能像天空中的鸟儿那样轻盈地飞翔。请好好品味一下杰克·韦尔奇说过的一句话:"纠正自己的行为,认清自己,从零开始,你将重新走上职场坦途。" 吐故才能纳新,心静才能身凉,有舍才能有得,杯空才能水满,放下才能超越。
        归零思维五大表现:心中无我,眼中无钱,念中无他,朝中无人,学无止境。
        年轻人难免带着几分傲气,认为自己无所不能、所向披靡,其实不然,初入职场的新人还是个"婴儿",正处在从爬到走的成长阶段。在毕业这几年里,一定要让自己逐步培养起学徒思维、海绵思维、空杯思维,具有这样思维的人心灵总是敞开的,能随时接受启示和一切能激发灵感的东西,他们时刻都能感受到成功女神的召唤。
  • 几种创建接口对象的方法

    2010-04-08 20:49:21

    1.直接用new
       类似: Parent son = new Son();
    2.用java的反射机制
      
    public class PersonFactory{
       
    public static Person getPersonInstence(String str){
            
    if("man".equal(str)){
                 
    return new Man();
         }
            
    if("woman".equal(str)){
                  
    return new Woman(); 
            }    

    }

    3.使用Spring的DI
     在AplicationContext.xml中配置bean的id,class
     在应用中直接调getBean(id)
       

    获得上下文:
    ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml");
    通过上下文来获得实体对象的应用

    Man man = (Man)context.getBean("man"); 
  • 关于Spring的注入方式

    2010-04-08 20:48:15

    spring的三种注入方式:


    1. 接口注入(不推荐
    2. getter,setter方式注入(比较常用
    3. 构造器注入(死的应用


    关于getter和setter方式的注入
    •  autowire="defualt"
    •  autowire=“byName”
    •  autowire="bytype"
    例如:有如下两个类需要注入
     1 package org.jia;
     2 
     3 public class Order {
     4     private String orderNum;
     5     @SuppressWarnings("unused")
     6     private OrderItem orderitem;
     7 
     8     public OrderItem getOrderitem() {
     9         return orderitem;
    10     }
    11 
    12     public void setOrderitem(OrderItem orderitem) {
    13         this.orderitem = orderitem;
    14     }
    15 
    16     public String getOrderNum() {
    17         return orderNum;
    18     }
    19 
    20     public void setOrderNum(String orderNum) {
    21         this.orderNum = orderNum;
    22     }
    23     
    24 }
    25 package org.jia;
    26 
    27 public class OrderItem {
    28     private String orderdec;
    29 
    30     public String getOrderdec() {
    31         return orderdec;
    32     }
    33 
    34     public void setOrderdec(String orderdec) {
    35         this.orderdec = orderdec;
    36     }
    37 }
    38 
    getter&&setter方式第一种注入:
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">

    <beans>
        
    <bean id="orderItem" class="org.jia.OrderItem">
            
    <property name="orderdec" value="item00001"></property>
        
    </bean>
        
    <bean id="order" class="org.jia.Order" >
            <!-----注入变量 名字必须与类中的名字一样------->
            <property name="orderNum" value="order000007"></property>
             <!--注入对象 名字为orderitem,所属的类的应用id为orderItem-->
            <property name="orderitem" ref="orderItem"></property>
        
        -->
    </bean>


    </beans>
    getter&&setter方式第二种注入: byName
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
    <beans>
        <!--此时的id就必须与Order.java中所定义的OrderItem的对象名称一样了,不然就会找不到-->
        <bean id="orderitem" class="org.jia.OrderItem">
            
    <property name="orderdec" value="item00001"></property>
        
    </bean>
        
    <bean id="order" class="org.jia.Order" autowire="byName">
            
    <property name="orderNum" value="order000007"></property>
        
    </bean>
    </beans>
    getter&&setter方式第三种注入:byType
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
    <beans>
        <!--按照byType注入则就与id没有关系,可以随便定义id !!!但是不能出现多个此类的id-->
        <bean id="orderitdfadafaem" class="org.jia.OrderItem">
            
    <property name="orderdec" value="item00001"></property>
        
    </bean>
        
    <bean id="order" class="org.jia.Order" autowire="byType">
            
    <property name="orderNum" value="order000007"></property>
        
    </bean>
    </beans>


    关于构造器的注入:

     autowire="constructor"
    需要在Order.java中加入一个构造器
    public Order(OrderItem item ){ rderitem = item; }
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
    <beans>
        
    <bean id="orderItem" class="org.jia.OrderItem">
            
    <property name="orderdec" value="item00001"></property>
        
    </bean>
        
    <bean id="order" class="org.jia.Order" autowire="constructor">
            
    <property name="orderNum" value="order000007"></property>
        
    </bean>
    </beans>
  • 工厂模式定义:提供创建对象的接口.

    2010-04-08 20:45:47


    工厂模式定义:提供创建对象的接口.

    为何使用?
    工厂模式是我们最常用的模式了,著名的Jive论坛 ,就大量使用了工厂模式,工厂模式在Java程序系统可以说是随处可见。

    为什么工厂模式是如此常用?因为工厂模式就相当于创建实例对象的new,我们经常要根据类Class生成实例对象, 如A a=new A() 工厂模式也是用来创建实例对象的,所以以后new时就要多个心眼,是否可以考虑实用工厂模式,虽然这样做,可能多做一些工作,但会给你系统带来更大的可扩 展性和尽量少的修改量。

    我们以类Sample为例, 如果我们要创建Sample的实例对象:

    Sample sample=new Sample();

    可是,实际情况是,通常我们都要在创建sample实例时做点初始化的工作,比如赋值 查询数据库等。

    首先,我们想到的是,可以使用Sample的构造函数,这样生成实例就写成:

    Sample sample=new Sample(参数);

    但是,如果创建sample实例时所做的初始化工作不是象赋值这样简单的事,可能是很长一段代码,如果也写入构造函数中,那你的代码很难看了(就需要Refactor重整)。

    为什么说代码很难看,初学者可能没有这种感觉,我们分析如下,初始化工作如果是很长一段代码,说明要做的工作很多, 将很多工作装入一个方法中,相当于将很多鸡蛋放在一个篮子里,是很危险的,这也是有背于Java面向对象的原则,面向对象的封装 (Encapsulation)和分派(Delegation)告诉我们,尽量将长的代码分派“切割”成每段,将每段再“封装”起来(减少段和段之间偶合 联系性),这样,就会将风险分散,以后如果需要修改,只要更改每段,不会再发生牵一动百的事情。

    在本例中,首先,我们需要将创建实例的工作与使用实例的工作分开, 也就是说,让创建实例所需要的大量初始化工作从Sample的构造函数中分离出去。

    这时我们就需要Factory工厂模式来生成对象了,不能再用上面简单new Sample(参数)。还有,如果Sample有个继承如MySample, 按照面向接口编程,我们需要将Sample抽象成一个接口.现在Sample是接口,有两个子类MySample 和HisSample .我们要实例化他们时,如下:

    Sample mysample=new MySample();
    Sample hissample=new HisSample();

    随着项目的深入,Sample可能还会"生出很多儿子出来", 那么我们要对这些儿子一个个实例化,更糟糕的是,可能还要对以前的代码进行修改:加入后来生出儿子的实例.这在传统程序中是无法避免的.

    但如果你一开始就有意识使用了工厂模式,这些麻烦就没有了.

    工厂方法
    你会建立一个专门生产Sample实例的工厂:

    public class Factory{

      public static Sample creator(int which){

      //getClass 产生Sample 一般可使用动态类装载装入类。
      if (which==1)
        return new SampleA();
      else if (which==2)
        return new SampleB();

      }

    }

    那么在你的程序中,如果要实例化Sample时.就使用

    Sample sampleA=Factory.creator(1);

    这样,在整个就不涉及到Sample的具体子类,达到封装效果,也就减少错误修改的机会,这个原理可以用很通俗的话 来比喻:就是具体事情做得越多,越容易范错误.这每个做过具体工作的人都深有体会,相反,官做得越高,说出的话越抽象越笼统,范错误可能性就越少.好象我 们从编程序中也能悟出人生道理?呵呵.

    使用工厂方法 要注意几个角色,首先你要定义产品接口,如上面的Sample,产品接口下有Sample接口的实现类,如SampleA,其次要有一个factory类,用来生成产品Sample,如下图,最右边是生产的对象Sample:

    进一步稍微复杂一点,就是在工厂类上进行拓展,工厂类也有继承它的实现类concreteFactory了。

    抽象工厂
    工厂模式中有: 工厂方法(Factory Method) 抽象工厂(Abstract Factory).

    这两个模式区别在于需要创建对象的复杂程度上。如果我们创建对象的方法变得复杂了,如上面工厂方法中是创建一个对象Sample,如果我们还有新的产品接口Sample2.

    这里假设:Sample有两个concrete类SampleA和SamleB,而Sample2也有两个concrete类Sample2A和SampleB2

    那么,我们就将上例中Factory变成抽象类,将共同部分封装在抽象类中,不同部分使用子类实现,下面就是将上例中的Factory拓展成抽象工厂:

    public abstract class Factory{

      public abstract Sample creator();

      public abstract Sample2 creator(String name);

    }

    public class SimpleFactory extends Factory{

      public Sample creator(){
        .........
        return new SampleA
      }

      public Sample2 creator(String name){
        .........
        return new Sample2A
      }

    }

    public class BombFactory extends Factory{

      public Sample creator(){
        ......
        return new SampleB
      }

      public Sample2 creator(String name){
        ......
        return new Sample2B
      }

    }


    从上面看到两个工厂各自生产出一套Sample和Sample2,也许你会疑问,为什么我不可以使用两个工厂方法来分别生产Sample和Sample2?

    抽象工厂还有另外一个关键要点,是因为 SimpleFactory内,生产Sample和生产Sample2的方法之间有一定联系,所以才要将这两个方法捆绑在一个类中,这个工厂类有其本身特 征,也许制造过程是统一的,比如:制造工艺比较简单,所以名称叫SimpleFactory。


    在实际应用中,工厂方法用得比较多一些,而且是和动态类装入器组合在一起应用,

    举例

    我们以Jive的ForumFactory为例,这个例子在前面的Singleton模式中我们讨论过,现在再讨论其工厂模式:

    public abstract class ForumFactory {

      private static Object initLock = new Object();
      private static String className = "com.jivesoftware.forum.database.DbForumFactory";
      private static ForumFactory factory = null;

      public static ForumFactory getInstance(Authorization authorization) {
        //If no valid authorization passed in, return null.
        if (authorization == null) {
          return null;
        }
        //以下使用了Singleton 单态模式
        if (factory == null) {
          synchronized(initLock) {
            if (factory == null) {
                ......

              try {
                  //动态转载类
                  Class c = Class.forName(className);
                  factory = (ForumFactory)c.newInstance();
              }
              catch (Exception e) {
                  return null;
              }
            }
          }
        }

        //Now, 返回 proxy.用来限制授权对forum的访问
        return new ForumFactoryProxy(authorization, factory,
                        factory.getPermissions(authorization));
      }

      //真正创建forum的方法由继承forumfactory的子类去完成.
      public abstract Forum createForum(String name, String description)
      throws UnauthorizedException, ForumAlreadyExistsException;

      ....

    }


    因为现在的Jive是通过数据库系统存放论坛帖子等内容数据,如果希望更改为通过文件系统实现,这个工厂方法ForumFactory就提供了提供动态接口:

    private static String className = "com.jivesoftware.forum.database.DbForumFactory";

    你可以使用自己开发的创建forum的方法代替com.jivesoftware.forum.database.DbForumFactory就可以.

    在上面的一段代码中一共用了三种模式,除了工厂模式外,还有Singleton单态模式,以及proxy模 式,proxy模式主要用来授权用户对forum的访问,因为访问forum有两种人:一个是注册用户 一个是游客guest,那么那么相应的权限就不一样,而且这个权限是贯穿整个系统的,因此建立一个proxy,类似网关的概念,可以很好的达到这个效 果.  

    看看Java宠物店中的CatalogDAOFactory:

    public class CatalogDAOFactory {

      /**

      * 本方法制定一个特别的子类来实现DAO模式。
      * 具体子类定义是在J2EE的部署描述器中。
      */

      public static CatalogDAO getDAO() throws CatalogDAOSysException {

        CatalogDAO catDao = null;

        try {

          InitialContext ic = new InitialContext();
          //动态装入CATALOG_DAO_CLASS
          //可以定义自己的CATALOG_DAO_CLASS,从而在无需变更太多代码
          //的前提下,完成系统的巨大变更。

          String className =(String) ic.lookup(JNDINames.CATALOG_DAO_CLASS);

          catDao = (CatalogDAO) Class.forName(className).newInstance();

        } catch (NamingException ne) {

          throw new CatalogDAOSysException("
            CatalogDAOFactory.getDAO: NamingException while
              getting DAO type : \n" + ne.getMessage());

        } catch (Exception se) {

          throw new CatalogDAOSysException("
            CatalogDAOFactory.getDAO: Exception while getting
              DAO type : \n" + se.getMessage());

        }

        return catDao;

      }

    }


    CatalogDAOFactory是典型的工厂方法,catDao是通过动态类装入器className获得 CatalogDAOFactory具体实现子类,这个实现子类在Java宠物店是用来操作catalog数据库,用户可以根据数据库的类型不同,定制自 己的具体实现子类,将自己的子类名给与CATALOG_DAO_CLASS变量就可以。

    由此可见,工厂方法确实为系统结构提供了非常灵活强大的动态扩展机制,只要我们更换一下具体的工厂方法,系统其他地方无需一点变换,就有可能将系统功能进行改头换面的变化。

    设计模式如何在具体项目中应用见《Java实用系统开发指南》



  • java数组、List、Set、Map

    2010-04-07 11:10:51

    数组是Java语言内置的类型,除此之外,Java有多种保存对象引用的方式。Java类库提供了一套相当完整的容器类,使用这些类的方法可以保存和操纵对象。下面分别进行讨论,在研究Java容器类之前,先了解一下Java数组的基本功能和特性。
    1. 数组的基本特性
    数组与其它种类的容器(List/Set/Map)之间的区别在于效率、确定的类型和保存基本类型数据的能力。数组是一种高效的存储和随机访问对象引用序列的方式,使用数组可以快速的访问数组中的元素。但是当创建一个数组对象(注意和对象数组的区别)后,数组的大小也就固定了,当数组空间不足的时候就再创建一个新的数组,把旧的数组中所有的引用复制到新的数组中。
    Java中的数组和容器都需要进行边界检查,如果越界就会得到一个RuntimeException异常。这点和C++中有所不同,C++中vector 的操作符[]不会做边界检查,这在速度上会有一定的提高,Java的数组和容器会因为时刻存在的边界检查带来一些性能上的开销。
    Java中通用的容器类不会以具体的类型来处理对象,容器中的对象都是以Object类型处理的,这是Java中所有类的基类。另外,数组可以保存基本类型,而容器不能,它只能保存任意的Java对象。
    一般情况下,考虑到效率与类型检查,应该尽可能考虑使用数组。如果要解决一般化的问题,数组可能会受到一些限制,这时可以使用Java提供的容器类。
    2. 操作数组的实用功能
    在java.util.Arrays类中,有许多static静态方法,提供了操作数组的一些基本功能:
    equals()方法----用于比较两个数组是否相等,相等的条件是两个数组的元素个数必须相等,并且对应位置的元素也相等。
    fill()方法----用以某个值填充整个数组,这个方法有点笨。
    asList()方法----接受任意的数组为参数,将其转变为List容器。
    binarySearch()方法----用于在已经排序的数组中查找元素,需要注意的是必须是已经排序过的数组。当 Arrays.binarySearch()找到了查找目标时,该方法将返回一个等于或大于0的值,否则将返回一个负值,表示在该数组目前的排序状态下此目标元素所应该插入的位置。负值的计算公式是“-x-1”。x指的是第一个大于查找对象的元素在数组中的位置,如果数组中所有的元素都小于要查找的对象,则x = a.size()。如果数组中包含重复的元素,则无法保证找到的是哪一个元素,如果需要对没有重复元素的数组排序,可以使用TreeSet或者 LinkedHashSet。另外,如果使用Comparator排序了某个对象数组,在使用该方法时必须提供同样的Comparator类型的参数。需要注意的是,基本类型数组无法使用Comparator进行排序。
    sort()方法----对数组进行升序排序。
    在Java标准类库中,另有static方法System.arraycopy()用来复制数组,它针对所有类型做了重载。
    3. 数组的排序
    在Java1.0和1.1两个版本中,类库缺少基本的算法操作,包括排序的操作,Java2对此进行了改善。在进行排序的操作时,需要根据对象的实际类型执行比较操作,如果为每种不同的类型各自编写一个不同的排序方法,将会使得代码很难被复用。一般的程序设计目标应是“将保持不变的事物与会发改变的事物相分离”。在这里,不变的是通用的排序算法,变化的是各种对象相互比较的方式。
    Java有两种方式来实现比较的功能,一种是实现 java.lang.Comparable接口,该接口只有一个compareTo()方法,并以一个Object类为参数,如果当前对象小于参数则返回负值,如果相等返回零,如果当前对象大于参数则返回正值。另一种比较方法是采用策略(strategy)设计模式,将会发生变化的代码封装在它自己的类 (策略对象)中,再将策略对象交给保持不变的代码中,后者使用此策略实现它的算法。因此,可以为不同的比较方式生成不同的对象,将它们用在同样的排序程序中。在此情况下,通过定义一个实现了Comparator接口的类而创建了一个策略,这个策略类有compare()和equals()两个方法,一般情况下实现compare()方法即可。
    使用上述两种方法即可对任意基本类型的数组进行排序,也可以对任意的对象数组进行排序。再提示一遍,基本类型数组无法使用Comparator进行排序。
    Java标准类库中的排序算法针对排序的类型进行了优化——针对基本类型设计了“快速排序”,针对对象设计的“稳定归并排序”。一般不用担心其性能。

    Java容器分析--List和Set
    容器类可以大大提高编程效率和编程能力,在Java2中,所有的容器都由SUN公司的Joshua Bloch进行了重新设计,丰富了容器类库的功能。
    Java2容器类类库的用途是“保存对象”,它分为两类:
    Collection----一组独立的元素,通常这些元素都服从某种规则。List必须保持元素特定的顺序,而Set不能有重复元素。
    Map---- 一组成对的“键值对”对象,即其元素是成对的对象,最典型的应用就是数据字典,并且还有其它广泛的应用。另外,Map可以返回其所有键组成的Set和其所有值组成的Collection,或其键值对组成的Set,并且还可以像数组一样扩展多维Map,只要让Map中键值对的每个“值”是一个Map即可。
    1.迭代器
    迭代器是一种设计模式,它是一个对象,它可以遍历并选择序列中的对象,而开发人员不需要了解该序列的底层结构。迭代器通常被称为“轻量级”对象,因为创建它的代价小。
    Java中的Iterator功能比较简单,并且只能单向移动:
    (1) 使用方法iterator()要求容器返回一个Iterator。第一次调用Iterator的next()方法时,它返回序列的第一个元素。
    (2) 使用next()获得序列中的下一个元素。
    (3) 使用hasNext()检查序列中是否还有元素。
    (4) 使用remove()将迭代器新返回的元素删除。
    Iterator是Java迭代器最简单的实现,为List设计的ListIterator具有更多的功能,它可以从两个方向遍历List,也可以从List中插入和删除元素。
    2.List的功能方法
    List(interface): 次序是List最重要的特点;它确保维护元素特定的顺序。List为Collection添加了许多方法,使得能够向List中间插入与移除元素(只推荐 LinkedList使用)。一个List可以生成ListIterator,使用它可以从两个方向遍历List,也可以从List中间插入和删除元素。
    ArrayList: 由数组实现的List。它允许对元素进行快速随机访问,但是向List中间插入与移除元素的速度很慢。ListIterator只应该用来由后向前遍历ArrayList,而不是用来插入和删除元素,因为这比LinkedList开销要大很多。
    LinkedList: 对顺序访问进行了优化,向List中间插入与删除得开销不大,随机访问则相对较慢(可用ArrayList代替)。它具有方法addFirst()、 addLast()、getFirst()、getLast()、removeFirst()、removeLast(),这些方法(没有在任何接口或基类中定义过)使得LinkedList可以当作堆栈、队列和双向队列使用。
    3.Set的功能方法
    Set(interface): 存入Set的每个元素必须是唯一的,因为Set不保存重复元素。加入Set的Object必须定义equals()方法以确保对象的唯一性。Set与Collection有完全一样的接口。Set接口不保证维护元素的次序。
    HashSet: 为快速查找而设计的Set。存入HashSet的对象必须定义hashCode()。
    TreeSet: 保持次序的Set,底层为树结构。使用它可以从Set中提取有序的序列。
    LinkedHashSet: 具有HashSet的查询速度,且内部使用链表维护元素的顺序(插入的次序)。于是在使用迭代器遍历Set时,结果会按元素插入的次序显示。
    HashSet采用散列函数对元素进行排序,这是专门为快速查询而设计的;TreeSet采用红黑树的数据结构进行排序元素;LinkedHashSet 内部使用散列以加快查询速度,同时使用链表维护元素的次序,使得看起来元素是以插入的顺序保存的。需要注意的是,生成自己的类时,Set需要维护元素的存储顺序,因此要实现Comparable接口并定义compareTo()方法。

    Java容器分析--Map
    标准的Java类库中包含了几种类型的Map,它们都拥有同样的基本接口Map,但是行为特性各不相同,主要表现在效率、键值对的保存、元素呈现次序、对象的保存周期和判定键是否等价的策略等方面。
    1.Map的功能方法
    Map(interface): 维护label和value的关联性,使得可以通过label查找value。
    HashMap: Map基于散列表的实现,取代了Hashtable。插入和查询label/value的开销是固定的,并且可以通过构造器设置容量和负载因子,以调整容器的性能。
    LinkedHashMap: 在HashMap的基础上做了一些改进,在迭代遍历它时,取得label/value的顺序是其插入的次序,或者是最近最少使用(LRU)的次序,速度上比HashMap要慢一点,但在迭代访问时速度会更快,主要原因是它使用了链表维护内部次序。
    TreeMap: 查看label或label/value时,元素会被排序,其次序由Comparable或Comparator决定,因此查询所得到的结果是经过排序的。另外,它是唯一带有subMap()方法的Map具体类,即返回一个子树。它也是SortedMap接口的唯一实现,subMap()方法也是从该接口继承的。
    WeakHashMap: Weak Key映射,允许释放映射所指向的对象。当映射之外没有引用指向某个label时,此label可以被垃圾收集器回收。
    IdentityHashMap: 使用==代替equals()对label进行比较的散列映射。
    2.hashCode()
    当使用标准库中的类Integer作为HashMap的label时,程序能够正常运行,但是使用自己创建的类作为HashMap的label时,通常犯一个错误。
    在HashMap中通过label查找value时,实际上是计算label对象地址的散列码来确定value的。一般情况下,我们是使用基类 Object的方法hashCode()来生成散列码,它默认是使用对象的地址来计算的,因此由第一个对象new Apple(5)和第二个对象new Apple(5)生成的散列码是不同的,不能完成正确的查找。通常,我们可以编写自己的hashCode()方法来覆盖基类的原始方法,但与此同时,我们必须同时实现equals()方法来判断当前的label是否与表中存在的label相同。正确的equals()方法满足五个条件:
    (1) 自反性。对于任意的x,x.equals(x)一定返回true。
    (2) 对称性。对于任意的x和y,如果y.equals(x)返回true,则x.equals(y)也返回true。
    (3) 传递性。对于任意的x、y、z,如果有x.equals(y)返回true,y.equals(z)返回true,则x.equals(z)一定返回true。
    (4) 一致性。对于任意的x和y,如果对象中用于等价比较的信息没有改变,那么无论调用x.equals(y)多少次,返回的结果应该保持一致,要么一直是true,要么一直是false。
    (5) 对任何不是null的x,x.equals(null)一定返回false。
    equals()比较的是对象的地址,如果要使用自己的类作为HashMap的label,必须同时重载hashCode()和equals()方法。
    使用散列的目的:想要使用一个对象来查找另一个对象。使用TreeSet或TreeMap也能实现此目的。另外,还可以自己实现一个Map,此时,必须提供Map.entrySet()方法来生成Map.Entry对象的Set。
    使用散列的价值:速度,散列使得查询可以快速进行。散列将label保存载数组中方便快速查询,因为存储一组元素最快的数据结构是数组,用它来表示 label的信息(后面有信息的描述),而不是label本身。通过label对象计算得到一个数字,作为数组的下标,这个数字就是散列码(即前面所述的信息)。该散列码具体是通过定义在基类Object中,可能由程序员自定义的类覆盖的hashCode()方法,即散列函数生成。为了解决数组容量带来的限制,可以使不同的label生成相同的下标,保存在一个链表list中,每一个链表就是数组的一个元素。查询label时就可以通过对list中的信息进行查找,当散列函数比较好,数组的每个位置中的list长度较短,则可以快速查找到数组元素list中的某个位置,提高了整体速度。
    散列表中的slot通常称为bucket,为了使散列分步均匀,bucket的值一般取质数。但事实证明,质数实际上并不是散列bucket的理想容量,近来Java散列实现都使用2的幂,具体如何验证以后再续。
    3.HashMap的性能因子
    容量(capacity): 散列表中bucket的数量。
    初始化容量(initial capacity): 创建散列表时bucket的数量。可以在构造方法中指定HashMap和HashSet的初始化容量。
    尺寸(size): 散列表中记录的数量。(数组的元素个数,非list中元素总和)
    负载因子(load factor): 尺寸/容量。负载因子为0,表示空的散列表,0.5表示半满的散列表。轻负载的散列表具有冲突少,适宜插入与查询的特点,但是使用迭代器遍历会比较慢。较高的负载会减少所需空间大小。当负载达到指定值时,容器会自动成倍地增加容量,并将原有的对象重新分配,存入新的bucket中,这个过程称为“重散列 ”。
    4.重写hashCode()的关键
    (1) 对同一个对象调用hashCode()都应该生成同样的值。
    (2) hashCode()方法不要依赖于对象中易变的数据,当数据发生变化时,hashCode()就会生成一个不同的散列码,即产生了一个不同的label。
    (3) hashCode()不应依赖于具有唯一性的对象信息,例如对象地址。
    (4) 散列码应该更关心速度,而不是唯一性,因为散列码不必是唯一的。
    (5) 好的hashCode()应该产生分步均匀的散列码。在Effective Java(Addison-Wesley 2001)中,Joshua Bloch给hashCode()给出了设计指导,可以参考。
    编写正确高效的hashCode()和equals()可以参考Apache的Jakarta Commons项目中的工具。

    java集合类总结
    对象的集合
    如果程序的对象数量有限,且寿命可知,那么这个程序是相当简单的。
    数组
    数组与其它容器的区别体现在三个方面:效率,类型识别以及可以持有primitives。数组是Java提供的,能随机存储和访问reference序列的诸多方法中的,最高效的一种。数组是一个简单的线性序列,所有它可以快速的访问其中的元素。但是速度是有代价的;当你创建了一个数组之后,它的容量就固定了,而且在其生命周期里不能改变。也许你会提议先创建一个数组,等到快不够用的时候,再创建一个新的,然后将旧的数组里的reference全部导到新的里面。其实(我们以后会讲的)ArrayList就是这么做的。但是这种灵活性所带来的开销,使得ArrayList的效率比起数组有了明显下降。
    Java对数组和容器都做边界检查;如果过了界,它旧会给一个RuntimeException。这种异常表明这个错误是由程序员造成的,这样你就用不着再在程序里面检查了。
    还有一些泛型容器类包括List,Set和Map。他们处理对象的时候就好像这些对象都没有自己的具体类型一样。也就是说,容器将它所含的元素都看成是(Java中所有类的根类)Object的。这样你只需要建一种容器,就能把所有类型的对象全都放进去。从这个角度来看,这种做法很不错(只是苦了 primitive。如果是常量,你还可以用Java的primitive的Wrapper类;如果是变量,那就只能放在你自己的类里了)。与其他泛型容器相比,这里体现数组的第二革优势:创建数组的时候,你也同时指明了它所持有的对象的类型(这又引出了第三点--数组可以持有primitives,而容器却不行)。也就是说,它会在编译的时候作类型检查,从而防止你插入错误类型的对象,或者是在提取对象的时候把对象的类型给搞错了。Java在编译和运行时都能阻止你将一个不恰当的消息传给对象。所有这并不是说使用容器就有什么危险,只是如果编译器能够帮你指定,那么程序运行会更快,最终用户也会较少收到程序运行异常的骚扰。
    从效率和类型检查的角度来看,使用数组总是没错的。但是,如果你在解决一个更为一般的问题,那数组就会显得功能太弱了点。
    数组是第一流的对象
    不管你用的是那种类型的数组,数组的标识符实际上都是一个“创建在堆(heap)里的实实在在的对象的”reference。实际上是那个对象持有其他对象的reference。你即可以用数组的初始化语句,隐含地创建这个对象,也可以用new表达式,明确地创建这个对象,只读的length属性能告诉你数组能存储多少元素。它是数组对象的一部分(实际上也是你唯一能访问的属性或方法)。‘[]’语法是另一条访问数组对象的途径。
    你没法知道数组里面究竟放了多少元素,因为length只是告诉你数组能放多少元素,也就是说是数组对象的容量,而不是它真正已经持有的元素的数量。但是,创建数组对象的时候,它所持有的reference都会被自动地初始化为null,所以你可以通过检查数组的某个“槽位”是否为null,来判断它是否持有对象。以此类推,primitive的数组,会自动来数字初始化为零,字符初始化为(char)0,boolean初始化为false。
    primitive容器
    容器类只能持有Object对象的reference。而数组除了能持有Objects的reference之外,还可以直接持有primitive。当然可以使用诸如Integer,Double之类的wrapper类。把primitive的值放到容器中,淡这样总有点怪怪的。此外, primitive数组的效率要比wrapper类容器的高出许多。
    当然,如果你使用primitive的时候,还需要那种“能随需要自动扩展的”容器类的灵活性,那就不能用数组了。你只能用容器来存储primitive的wrapper类。
    返回一个数组
    假设你写了一个方法,它返回的不是一个而是一组东西。那么在Java中就可以返回的“就是一个数组”。与C++不同,你永远也不必为Java的数组操心--只要你还需要它,它就还在;一旦你用完了,垃圾回收器会帮你把它打扫干净。
    Arrays类
    java.util 里面有一个Arrays类,它包括了一组可用于数组的static方法,这些方法都是一些实用工具。其中有四个基本方法:用来比较两个数组是否相等的 equals();用来填充的fill();用来对数组进行排序的sort();以及用于在一个已排序的数组中查找元素的 binarySearch()。所有这些方法都对primitive和Object进行了重载。此外还有一个asList()方法,它接受一个数组,然后把它转成一个List容器。
    虽然Arrays还是有用的,但它的功能并不完整。举例来说,如果它能让我们不用写for循环就能直接打印数组,那就好了。此外,正如你所看到的fill()只能用一个值填数组。所以,如果你想把随即生成的数字填进数组的话,fill()是无能为力的。
    复制一个数组
    Java标准类库提供了一个System.arraycopy()的static方法。相比for循环,它能以更快的速度拷贝数组。System.arraycopy()对所有类型都作了重载。
    对象数组和primitive数组都能拷贝。但是如果你拷贝的是对象数组,那么你只拷贝了它们的reference--对象本身不会被拷贝。这被成为浅拷贝(shallow copy)。
    数组的比较
    为了能比较数组是否完全相等,Arrays提供了经重载的equals()方法。当然,也是针对各种primitive以及Object的。两个数组要想完全相等,他们必须有相同数量的元素,而且数组的每个元素必须与另一个数组的相对应的位置上的元素相等。元素的相等姓,用equals()判断。(对于 primitive,它会使用其wrapper类的equals();比如int使用Integer.equals()。)。
    数组元素的比较
    Java 里面有两种能让你实现比较功能的方法。一是实现java.lang.Comparable接口,并以此实现类“自有的”比较方法。这是一个很简单的接口,它只有一个方法compareTo()。这个方法能接受另一个对象作为参数,如果现有对象比参数小,它就会返回一个负数,如果相同则返回零,如果现有的对象比参数大,它就返回一个正数。
    static randInt()方法会生成一个介于0到100之间的正数。
    现在架设,有人给你一个没有实现Comparable接口的类,或者这个类实现了Comparable接口,但是你发现它的工作方式不是你所希望的,于是要重新定义一个新的比较方法。Java没有强求你一定要把比较代码塞进类里,它的解决方案是使用“策略模式(strategy design pattern)”。有了策略之后,你就能把会变的代码封装到它自己的类里(即所谓的策略对象strategy object)。你把策略对象交给不会变的代码,然后用它运用策略完成整个算法。这样,你就可以用不同的策略对象来表示不同的比较方法,然后把它们都交给同一个排序程序了。接下来就要“通过实现Comparator接口”来定义策略对象了。这个接口有两个方法compare()和equals()。但是除非是有特殊的性能要求,否则你用不着去实现equals()。因为只要是类,它就都隐含地继承自Object,而Object里面已经有了一个 equals()了。所以你尽可以使用缺省的Object的equals(),这样就已经满足接口的要求了。
    Collections类里专门有一个会返回与对象自有的比较法相反的Comparator的方法。它能很轻易地被用到CompType上面。
    Collections.reverseOrder()返回了一个Comparator的reference。
    compare()方法会根据第一个参数是小于,等于还是大于第二个参数,分别返回负整数,零或是正整数。
    数组的排序
    有了内置的排序方法之后,你就能对任何数组排序了,不论是primitive的还是对象数组的,只要它实现了Comparable接口或有一个与之相关的Comparator对象就行了。
    Java标准类库所用的排序算法已经作了优化--对primitive,它用的是“快速排序(Quicksort)”,对对象,它用的是“稳定合并排序(stable merge sort)”。所以除非是prolier表明排序算法是瓶颈,否则你不用为性能担心。
    查询有序数组
    一旦数组排完序,你就能用Arrays.binarySearch()进行快速查询了。但是切忌对一个尚未排序的数组使用binarySearch();因为这么做的结果是没意义的。
    如果Arrays.binarySearch()找到了,它就返回一个大于或等于0的值。否则它就返回一个负值,而这个负值要表达的意思是,如果你手动维护这个数组的话,这个值应该插在哪个位。
  • 一个java接口实例

    2010-04-07 10:01:00

    在java中,定义一个接口,声明计算长方形面积和周长的抽象方法,再用一个类去实现这个接口,再编写一个测试类去使用这个接口。

    calrect.java

    public interface calrect
    {//定义接口,接口包含抽象类
     public abstract int calarea();
     public abstract int calgirth();
     public abstract int getx();
     public abstract int getY();
     
    }

    RRect.java

    public class RRect implements calrect{

     public RRect()
     {
      x=3;y=4;
     }
     
     
     public  int calarea()//实现抽象类时,不用再写public abstract int calarea()
     {
      return x*y;
     }
     public  int calgirth()
     {
      return x*2+y*2;
     }
     public  int getx()
     {
      return x;
     }
     public  int getY()
     {
      return y;
     }
     
    private int x;
    private int y;
     
    }

    Class1.java

    public class Class1 {

     RRect rect;
     public static void main(String[] args)
     {
      RRect rect = new RRect();
      System.out.println("巨星的长"+rect.getx());
      System.out.println("巨星的宽"+rect.getY());
      System.out.println("巨星的面积"+rect.calarea());
      System.out.println("巨星的周长"+rect.calgirth());
      
     }
    }

     

    将它们放在一个包中运行Class.java输出结果如下:

    巨星的长3
    巨星的宽4
    巨星的面积12
    巨星的周长14

  • Java接口和抽象类区别

    2010-04-06 19:47:02

    一个软件设计的好坏,我想很大程度上取决于它的整体架构,而这个整体架构其实就是你对整个宏观商业业务的抽象框架,当代表业务逻辑的高层抽象层结构 合理时,你底层的具体实现需要考虑的就仅仅是一些算法和一些具体的业务实现了。当你需要再开发另一个相近的项目时,你以前的抽象层说不定还可以再次利用 呢,面对对象的设计,复用的重点其实应该是抽象层的复用,而不是具体某一个代码块的复用,是不是一下子感觉自己对复用理解的高度又上升了一层?^_^

    说到了抽象,我就不能不提到曾让我头痛的Java接口和Java抽象类了,这也是本文我想说的重点。

    既然面向对象设计的重点在于抽象,那Java接口和Java抽象类就有它存在的必然性了。

    Java接口和Java抽象类代表的就是抽象类型,就是我们需要提出的抽象层的具体表现。OOP面向对象的编程,如果要提高程序的复用率,增加程序 的可维护性,可扩展性,就必须是面向接口的编程,面向抽象的编程,正确地使用接口、抽象类这些太有用的抽象类型做为你结构层次上的顶层。

    Java接口和Java抽象类有太多相似的地方,又有太多特别的地方,究竟在什么地方,才是它们的最佳位置呢?把它们比较一下,你就可以发现了。

    1、Java接口和Java抽象类最大的一个区别,就在于Java抽象类可以提供某些方法的部分实现,而Java接口不可以,这大概就是Java抽象类唯一的优点吧,但这个优点非常有用。
    如 果向一个抽象类里加入一个新的具体方法时,那么它所有的子类都一下子都得到了这个新方法,而Java接口做不到这一点,如果向一个Java接口里加入一个 新方法,所有实现这个接口的类就无法成功通过编译了,因为你必须让每一个类都再实现这个方法才行,这显然是Java接口的缺点。

    2、一个抽象类的实现只能由这个抽象类的子类给出,也就是说,这个实现处在抽象类所定义出的继承的等级结构中,而由于Java语言的单继承性,所以抽象类作为类型定义工具的效能大打折扣。
    在这一点上,Java接口的优势就出来了,任何一个实现了一个Java接口所规定的方法的类都可以具有这个接口的类型,而一个类可以实现任意多个Java接口,从而这个类就有了多种类型。

    3、从第2点不难看出,Java接口是定义混合类型的理想工具,混合类表明一个类不仅仅具有某个主类型的行为,而且具有其他的次要行为。

    4、结合1、2点中抽象类和Java接口的各自优势,具精典的设计模式就出来了:声明类型的工作仍然由Java接口承担,但是同时给出一个Java 抽象类,且实现了这个接口,而其他同属于这个抽象类型的具体类可以选择实现这个Java接口,也可以选择继承这个抽象类,也就是说在层次结构中,Java 接口在最上面,然后紧跟着抽象类,哈,这下两个的最大优点都能发挥到极至了。这个模式就是“缺省适配模式”。
    在Java语言API中用了这种模式,而且全都遵循一定的命名规范:Abstract +接口名。

    Java接口和Java抽象类的存在就是为了用于具体类的实现和继承的,如果你准备写一个具体类去继承另一个具体类的话,那你的设计就有很大问题了。Java抽象类就是为了继承而存在的,它的抽象方法就是为了强制子类必须去实现的。

    使用Java接口和抽象Java类进行变量的类型声明、参数是类型声明、方法的返还类型说明,以及数据类型的转换等。而不要用具体Java类进行变量的类型声明、参数是类型声明、方法的返还类型说明,以及数据类型的转换等
  • 相信自己,努力去做

    2010-03-26 16:40:45

     

         最近老有种怀才不遇的感觉。呵呵,也许是自己有些心浮气躁了。开始还觉得自己很喜欢这种工作氛围,慢慢的觉得有些时候受到些不公平待遇,觉得自己被冷落。我给自己说:这样的心态很危险,要拥抱变化,融入团队。可是脑海中却有另一个我在说,怎么可以这样,怎么是这样的团队。之前一直在考虑,自己能给团队带来什么。考虑了些许觉得目前也许不能创造明显的价值,但至少不会出漏子,会让产品保质保量的上去。现在觉得要在团队中汲取些东西,也许是为了将来可以跳出这个框框。想学很多东西,每天在跟时间奔跑。

         感觉6:30起床也不是那么困难的事,以前总会睡到8点的样子才起来,到公司会9点多一点。现在巴不得晚上不要休息了。又有了读书时代的狂想,要是人可以连续工作7天然后集中休息一天该多好。呵呵,不要有黑夜,光明的日子一大把。

          前方的路很艰难,每个人都很努力,大部分人会死在今天晚上。现在感觉把这些感受写出来自己心里会舒服些,像是在跟另一个自己聊天,解读自己。我想如果要离开,那也是最辉煌的时刻离开,因为我不要别人看到我的落魄。所以,收起自己的恐惧和抱怨,埋头苦干,相信自己,我会成功!

  • 不要抱怨,提升自我

    2010-03-25 17:36:44

               

          最近做一个日常,跟开发合作感觉很郁闷。我发现的问题给他提bug,他在自己本机试验了下,说我这是OK的。然后颠颠的跑过来,我给他演示一遍,他说明白了,我去看下代码。半天那个bug还是new,该bug影响了我后续测试的执行。我问他:改好了吗?他说:还没找到问题,不确定是环境问题还是代码问题。我感觉莫名的恼火,但也不好意思发火。任务很多,他修复不了我等下去也会延续后续的任务,这样推下去不是办法。末了,我想起另外一个开发,以前项目中合作过,感觉他能力很强,把问题反馈给他,他帮我查了下,2下就搞定了查处了问题。我反馈给和我合作的这个开发,他说:辛苦了,是这个问题。之后,他去修复,又过了半天,我问他:好了吗?他说:还没好。我说:是什么原因?他说:要找人审批。我心里想,这么半天了还没弄好么,我说:那你问问身边的人吧。过了会,他给我回复:已经找人了。又过了半天,我问他,他说:应该好了。我试了下,还是没好,反馈给他,他说他催下。他总不会主动回复我,每次我都要去追着问他,又问,答:应该好了吧。我说:你试下好了修复后我再验证。过了会,他说:给我个宝贝。我很晕!给了他宝贝,他说还没好。然后。。。。。。我催他,他催别人,然后。。。。。。终于听到好了,你验证下。我验证了下,这回确实是OK了。

          看了我这么多废话,你们有没遇到这样的情况,这样的开发真的很让人恼火。同时,我也在想,作为测试,要做这么多工作,肩负很重的责任。到底怎样才能保证质量,提高效率。靠我们来推动力量是很渺小的,那不是我们,是who?不再想想那么多了,自己先提高自身的能力,学好编码,以后希望可以跟开发说,这个bug你应该修改程序中的哪行代码。。。。。。

          我想,这样的目标并不遥远,在不久的将来我就能实现。相信自己,坚持下去,努力再努力。

  • 什么是Spring

    2010-03-15 20:10:09

    Spring是一种Framework,就像struts是framework一样。
    hibernate是一种“数据库-对象”映射的解决方案,就是你只要写一句SQL语句,它就自动把SQL语句的结果封装成对象...当然,理论上这样,实际上并不是你想象的那么理想,实际还是要做很多工作的。类似的还有iBatis.
    一、    Spring诞生
    Spring是一个开源框架,目前在开源社区的人气很旺,被认为是最有前途的开源框架之一。她是由Rod Johnson创建的,她的诞生是为了简化企业级系统的开发。说道Spring就不得不说EJB,因为Spring在某种意义上是EJB的替代品,她是一种轻量级的容器。用过EJB的人都知道EJB很复杂,为了一个简单的功能你不得不编写多个Java文件和部署文件,他是一种重量级的容器。也许你不了解EJB,你可能对“轻(重)量级”和“容器”比较陌生,那么这里我简单介绍一下。
    1、什么是容器
    “容器”,这个概念困扰我好久。从学习Tomcat开始就一直对此感到困惑。感性的来讲,容器就是可以用来装东西的物品。那么在编程领域就是指用来装对象(OO的思想,如果你连OO都不了解,建议你去学习OO先)的对象。然而这个对象比较特别,它不仅要容纳其他对象,还要维护各个对象之间的关系。这么讲可能还是太抽象,来看一个简单的例子:
    代码片断1:
  • public class Container 
  • {
  •     public void init()
  •     {
  •     Speaker s = new Speaker();
  •     Greeting g = new Greeting(s);
  •     }
  • }

    1. 可以看到这里的Container类(容器)在初始化的时候会生成一个Speaker对象和一个Greeting对象,并且维持了它们的关系,当系统要用这些对象的时候,直接问容器要就可以了。这就是容器最基本的功能,维护系统中的实例(对象)。如果到这里你还是感到模糊的话,别担心,我后面还会有相关的解释。

      2、轻量级与重量级
      所谓“重量级”是相对于“轻量级”来讲的,也可以说“轻量级”是相对于重量级来讲的。在Spring出现之前,企业级开发一般都采用EJB,因为它提供的事务管理,声明式事务支持,持久化,分布计算等等都“简化”了企业级应用的开发。我这里的“简化”打了双引号,因为这是相对的。重量级容器是一种入侵式的,也就是说你要用EJB提供的功能就必须在你的代码中体现出来你使用的是EJB,比如继承一个接口,声明一个成员变量。这样就把你的代码绑定在EJB技术上了,而且EJB需要JBOSS这样的容器支持,所以称之为“重量级”。
      相对而言“轻量级”就是非入侵式的,用Spring开发的系统中的类不需要依赖Spring中的类,不需要容器支持(当然Spring本身是一个容器),而且Spring的大小和运行开支都很微量。一般来说,如果系统不需要分布计算或者声明式事务支持那么Spring是一个更好的选择。

      二、    几个核心概念
      在我看来Spring的核心就是两个概念,反向控制(IoC),面向切面编程(AOP)。还有一个相关的概念是POJO,我也会略带介绍。
      1、POJO
      我所看到过的POJO全称有两个,Plain Ordinary Java Object,Plain Old Java Object,两个差不多,意思都是普通的Java类,所以也不用去管谁对谁错。POJO可以看做是简单的JavaBean(具有一系列Getter,Setter方法的类)。严格区分这里面的概念没有太大意义,了解一下就行。
      2、    IoC
      IoC的全称是Inversion of Control,中文翻译反向控制或者逆向控制。这里的反向是相对EJB来讲的。EJB使用JNDI来查找需要的对象,是主动的,而Spring是把依赖的对象注入给相应的类(这里涉及到另外一个概念“依赖注入”,稍后解释),是被动的,所以称之为“反向”。先看一段代码,这里的区别就很容易理解了。
      代码片段2:

    2. public void greet()
    3. {
    4. Speaker s = new Speaker();
    5. s.sayHello();
    6. }

      1. 代码片段3:

      2. public void greet()
      3. {
      4. Speaker s = (Speaker)context.lookup("ejb/Speaker");
      5. s.sayHello();
      6. }

        1. 代码片段4:

        2. public class Greeting 
        3. {
        4.     public Speaker s;
        5.     public Greeting(Speaker s)
        6.     {
        7.         this.s = s;
        8.     }
        9.     public void greet()
        10.     {
        11.         s.sayHello();
        12.     }
        13. }
          1. 我们可以对比一下这三段代码。其中片段2是不用容器的编码,片段3是EJB编码,片段4是Spring编码。结合代码片段1,你能看出来Spring编码的优越之处吗?也许你会觉得Spring的编码是最复杂的。不过没关系,我在后面会解释Spring编码的好处。
            这里我想先解释一下“依赖注入”。根据我给的例子可以看出,Greeting类依赖Speaker类。片段2和片段3都是主动的去获取Speaker,虽然获取的方式不同。但是片段4并没有去获取或者实例化Speaker类,而是在greeting函数中直接使用了s。你也许很容易就发现了,在构造函数中有一个s被注入(可能你平时用的是,传入)。在哪里注入的呢?请回头看一下代码片段1,这就是使用容器的好处,由容器来维护各个类之间的依赖关系(一般通过Setter来注入依赖,而不是构造函数,我这里是为了简化示例代码)。Greeting并不需要关心Speaker是哪里来的或是从哪里获得Speaker,只需要关注自己分内的事情,也就是让Speaker说一句问候的话。
            3、    AOP
            AOP全称是Aspect-Oriented Programming,中文翻译是面向方面的编程或者面向切面的编程。你应该熟悉面向过程的编程,面向对象的编程,但是面向切面的编程你也许是第一次听说。其实这些概念听起来很玄,说到底也就是一句话的事情。
            现在的系统往往强调减小模块之间的耦合度,AOP技术就是用来帮助实现这一目标的。举例来说,假如上文的Greeting系统含有日志模块,安全模块,事务管理模块,那么每一次greet的时候,都会有这三个模块参与,以日志模块为例,每次greet之后,都要记录下greet的内容。而对于Speaker或者Greeting对象来说,它们并不知道自己的行为被记录下来了,它们还是像以前一样的工作,并没有任何区别。只是容器控制了日志行为。如果这里你有点糊涂,没关系,等讲到具体Spring配置和实现的时候你就明白了。
            假如我们现在为Greeting系统加入一个Valediction功能,那么AOP模式的系统结构如下:
            G|RET|TIN|G
            V|ALE|DIT|ION
            |   |   |
            日志 安全 事务

            这些模块是贯穿在整个系统中的,为系统的不同的功能提供服务,可以称每个模块是一个“切面”。其实“切面”是一种抽象,把系统不同部分的公共行为抽取出来形成一个独立的模块,并且在适当的地方(也就是切入点,后文会解释)把这些被抽取出来的功能再插入系统的不同部分。
            从某种角度上来讲“切面”是一个非常形象的描述,它好像在系统的功能之上横切一刀,要想让系统的功能继续,就必须先过了这个切面。这些切面监视并拦截系统的行为,在某些(被指定的)行为执行之前或之后执行一些附加的任务(比如记录日志)。而系统的功能流程(比如Greeting)并不知道这些切面的存在,更不依赖于这些切面,这样就降低了系统模块之间的耦合度。

            三、    Spring初体验
            这一节我用一个具体的例子Greeting,来说明使用Spring开发的一般流程和方法,以及Spring配置文件的写法。
            首先创建一个Speaker类,你可以把这个类看做是POJO。
            代码片段5:

          2. public class Speaker 
          3. {
          4.     public void sayHello()
          5.     {
          6.         System.out.println("Hello!");
          7.     }
          8. }
            1. 再创建一个Greeting类。
              代码片段6:

            2. public class Greeting 
            3. {
            4.     private Speaker speaker;
            5.     public void setSpeaker(Speaker speaker)
            6.     {
            7.         this.speaker = speaker;
            8.     }
            9.     public void greet()
            10.     {
            11.         speaker.sayHello();
            12.     }
            13. }

              1. 然后要创建一个Spring的配置文件把这两个类关联起来。
                代码片段7(applicationContext.xml):

              2. "1.0" encoding="UTF-8"?>
              3. "-//SPRING//DTD BEAN//EN" 
              4.     "http://www.springframework.org/dtd/spring-beans.dtd">
              5.     "Speaker" class="Speaker">
              6.     "Greeting" class="Greeting">
              7.          "speaker">
              8.             "Speaker"/>
              9.         

                要用Spring Framework必须把Spring的包加入到Classpath中,我用的是Eclipse+MyEclipse,这些工作是自动完成的。推荐用Spring的配置文件编辑器来编辑,纯手工编写很容易出错。我先分析一下这个xml文件的结构,然后再做测试。从节点开始,先声明了两个,第二个bean有一个speaker属性(property)要求被注入,注入的内容是另外一个bean Speaker。这里的命名是符合JavaBean规范的,也就是说如果是speaker属性,那么Spring容器就会调用setSpeaker()来注入这个属性。是reference的意思,表示引用另外一个bean。
                下面看一段简单的测试代码:
                代码片段8:

              10. public static void main(String[] args) 
              11. {
              12.         ApplicationContext context = 
              13.             New ClassPathXmlApplicationContext("applicationContext.xml");
              14.         Greeting greeting = (Greeting)context.getBean("Greeting");
              15.         greeting.greet();
              16. }

                1. 这段代码很简单,如果你上文都看懂了,那么这里应该没有问题。值得注意的是Spring有两种方式来创建容器(我们不再用上文我们自己编写的Container),一种是ApplicationContext,另外一种是BeanFactory。ApplicationContext更强大一些,而且使用上两者没有太大区别,所以一般说来都用ApplicationContext。Spring容器帮助我们维护我们在配置文件中声明的Bean以及它们之间的依赖关系,我们的Bean只需要关注自己的核心业务。

                  四、    面向接口的编程
                  看了这么多,也许你并没有觉得Spring给开发带来了很多便利。那是因为我举的例子还不能突出Spring的优越之处,接下来我将通过接口编程来体现Spring的强大。
                  假如现在要求扩展Greeting的功能,要让Speaker用不同的语言来问候,也就是说有不同的Speaker,比如ChineseSpeaker, EnglishSpeaker。那么对上文提到的三种编码方式(代码片段2、3、4)分别加以修改,你会发现很麻烦。假如下次又要加入一个西班牙语,又得重复劳动。很自然的会考虑到使用一个ISpeaker接口来简化工作,,更改后的代码如下(这里没有列出接口的相关代码,我想你应该明白怎么写):         

                  代码片段9:
                2. public void greet()
                3. {
                4. ISpeaker s = new ChineseSpeaker();
                5. s.sayHello();
                6. }

                  1. 代码片段10:
                  2. public void greet()
                  3. {
                  4. ISpeaker s = (ISpeaker)context.lookup("ejb/ChineseSpeaker");
                  5. s.sayHello();
                  6. }

                    1. 代码片段11:
                    2. public class Greeting 
                    3. {
                    4.     public ISpeaker s;
                    5.     public Greet(ISpeaker s)
                    6.     {
                    7.         this.s = s;
                    8.     }
                    9.     public void greet()
                    10.     {
                    11.         s.sayHello();
                    12.     }
                    13. }
                      1. 对比三段代码,你会发现,第一种方法还是把具体的Speaker硬编码到代码中了,第二中方法稍微好一点,但是没有本质改变,而第三种方法就不一样了,代码中并没有关于具体Speaker的信息。也就是说,如果下次还有什么改动的话,第三种方法的Greeting类是不需要修改,编译的。根据上文Spring的使用介绍,只需要改动xml文件就能给Greeting注入不同的Speaker了,这样代码的扩展性是不是提高了很多?
                        关于Spring的接口编程还有很多东西可以去挖掘,后文还会提到有关Spring Proxy的接口编程,我这里先介绍这么多,有兴趣话可以去google更多的资料。

                        五、    应用Spring中的切面
                        Spring生来支持AOP,首先来看几个概念:
                        1、    切面(Aspect):切面是系统中抽象出来的的某一个功能模块,上文已经有过介绍,这里不再多说。
                        2、    通知(Advice):通知是切面的具体实现。也就是说你的切面要完成什么功能,具体怎么做就是在通知里面完成的。这个名称似乎有点让人费解,等后面看了代码就明白了。
                        3、    切入点(Pointcut):切入点定义了通知应该应用到系统的哪些地方。Spring只能控制到方法(有的AOP框架可以控制到属性),也就是说你能在方法调用之前或者之后选择切入,执行额外的操作。
                        4、    目标对象(Target):目标对象是被通知的对象。它可以是任何类,包括你自己编写的或者第三方类。有了AOP以后,目标对象就只需要关注自己的核心业务,其他的功能,比如日志,就由AOP框架支持完成。
                        5、    代理(Proxy):简单的讲,代理就是将通知应用到目标对象后产生的对象。Spring在运行时会给每个目标对象生成一个代理对象,以后所有对目标对象的操作都会通过代理对象来完成。只有这样通知才可能切入目标对象。对系统的其他部分来说,这个过程是透明的,也就是看起来跟没用代理一样。
                        我为了简化,只介绍这5个概念。通过这几个概念应该能够理解Spring的切面编程了。如果需要深入了解Spring AOP的话再去学习其他概念也很快的。
                        下面通过一个实际的例子来说明Spring的切面编程。继续上文Greeting的例子,我们想在Speaker每次说话之前记录Speaker被调用了。
                        首先创建一个LogAdvice类:
                        代码片段12:
                      2. public class LogAdvice implements MethodBeforeAdvice 
                      3. {
                      4.     public void before(Method arg0, Object[] arg1, Object arg2)throws Throwable 
                      5.     {
                      6.         System.out.println("Speaker called!");
                      7.     }
                      8. }

                        这里涉及到一个类,MethodBeforeAdvice,这个类是Spring类库提供的,类似的还有AfterReturningAdvice等等,从字面就能理解它们的含义。先不急着理解这个类,我稍后解释。我们继续看如何把这个类应用到我们的系统中去。
                        代码片段13:

                      9.     "Speaker" class="Speaker"/>
                      10.     "Greeting" class="Greeting">
                      11.          "speaker">
                      12.             "SpeakerProxy"/>
                      13.         
                      14.     
                      15.     "LogAdvice" class="LogAdvice"/>
                      16.     "SpeakerProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
                      17.          "proxyInterfaces">
                      18.             ISpeaker
                      19.         
                      20.          "interceptorNames">
                      21.             
                      22.                 LogAdvice
                      23.             
                      24.         
                      25.          "target">
                      26.             "Speaker"/>
                      27.         
                      28.     

                        1. 可以看到我们的配置文件中多了两个bean,一个LogAdvice,另外一个SpeakerProxy。LogAdvice很简单。我着重分析一下SpeakerProxy。这个Bean实际上是由Spring提供的ProxyFactoryBean实现。下面定义了三个依赖注入的属性。
                          1、    proxyInterfactes:这个属性定义了这个Proxy要实现哪些接口,可以是一个,也可以是多个(多个的话,要用list标签)。我前面讲过Proxy是在运行是动态创建的,那么这个属性就告诉Spring创建这个Proxy的时候实现哪些接口。
                          2、    interceptorNames:这个属性定义了Proxy被切入了哪些通知,这里只有一个LogAdvice。
                          3、    target:这个属性定义了被代理的对象。在这个例子中target是Speaker。
                          这样的定义实际上约束了被代理的对象必须实现一个接口,这与上文讲的面向接口的编程有点类似。其实可以这样理解,接口的定义可以让系统的其他部分不受影响,以前用ISpeaker接口来调用,现在加入了Proxy还是一样的。但实际上内容已经不一样了,以前是Speaker,现在是一个Proxy。而target属性让proxy知道具体的方法实现在哪里。Proxy可以看作是target的一个包装。当然Spring并没有强制要求用接口,通过CGLIB(一个高效的代码生成开源类库)也可以直接根据目标对象生成子类,但这种方式并不推荐。
                          我们还像以前一样的测试我们的Greeting系统,测试代码和代码片段8是一样的。运行结果如下:
                          Speaker called!
                          Hello!

                          看到效果了吧!而且你可以发现,我们加入Log功能并没有改变以前的代码,甚至测试代码都没有改变,这就是AOP的魅力所在!我们更改的只是配置文件。
                          下面解释一下刚才落下的MethodBeforeAdvice。关于这个类我并不详细介绍,因为这涉及到Spring中的另外一个概念“连接点(Jointpoint)”,我详细介绍一个before这个方法。这个方法有三个参数arg0表示目标对象在哪个点被切入了,既然是MethodBeforeAdvice,那当然是在Method之前被切入了。那么arg0就是表示的那个Method。第二个参数arg1是Method的参数,所以类型是Object[]。第三个参数就是目标对象了,在Greeting例子中arg2的类型实际上是Speaker。
                          在Greeting例子中,我们并没有指定目标对象的哪些方法要被切入,而是默认切入所有方法调用(虽然Speaker只有一个方法)。通过自定义Pointcut,可以控制切入点,我这里不再介绍了,因为这并不影响理解Spring AOP,有兴趣的话去google一下就知道了。
                            1. 冒泡程序

                              2010-03-08 16:56:46

                              冒泡

                              public class maopao{
                              public static void main(String args[])
                              {
                               
                              int a[]={32,46,78,21,56,89,61};
                              int temp;
                              int i,j;

                              for (i=0;i<6;i++)
                              {
                              for(j=i+1;j<7;j++)
                              if(a[i]>a[j])
                              {
                              temp=a[i];
                              a[i]=a[j];
                              a[j]=temp;
                              }
                              }


                              for(i=0;i<7;i++)
                              {
                              System.out.println(a[i]);

                              }
                              }
                              }

                               

                               

                               

                              执行结果:
                              21
                              32
                              46
                              56
                              61
                              78
                              89

                            2. 2010.2.21java源程序结构

                              2010-02-21 11:20:09

                                一个完整的java源程序应该包括下列部分:
                                package语句; //该部分至多只有一句,必须放在源程序的第一句
                                import语句; /*该部分可以有若干import语句或者没有,必须放在所有的
                                        类定义之前*/

                                public classDefinition; //公共类定义部分,至多只有一个公共类的定义
                                     //java语言规定该java源程序的文件名必须与该公共类名完全一致
                                classDefinition; //类定义部分,可以有0个或者多个类定义
                                interfaceDefinition; //接口定义部分,可以有0个或者多个接口定义

                                例如一个java源程序可以是如下结构,该源程序命名为HelloWorldApp.java:
                                 package javawork.helloworld; /*把编译生成的所有.class文件放到包
                                                 javawork.helloworld中*/

                                 import java.awt.*;  //告诉编译器本程序中用到系统的AWT包
                                 import javawork.newcentury; /*告诉编译器本程序中用到用户自定义
                                                的包javawork.newcentury*/

                                 public class HelloWorldApp{......} /*公共类HelloWorldApp的定义,
                                                    名字与文件名相同*/

                                 class TheFirstClass{......} //第一个普通类TheFirstClass的定义
                                 class TheSecondClass{......} //第二个普通类TheSecondClass的定义
                                            ...... //其它普通类的定义
                                 interface TheFirstInterface{......} /*第一个接口
                                                    TheFirstInterface的定义*/

                                               ...... //其它接口定义

                                
                              package语句:由于java编译器为每个类生成一个字节码文件,且文件名与类名相同,因此同名的类有可能发生冲突。为了解决这一问题,java提供包来管理类名空间,包实际提供了一种命名机制和可见性限制机制。而在java的系统类库中,把功能相似的类放到一个包(package)中,例如所有的图形界面的类都放在java.awt这个包中,与网络功能有关的类都放到java.net这个包中。用户自己编写的类(指.class文件)也应该按照功能放在由程序员自己命名的相应的包中,例如上例中的javawork.helloworld就是一个包。包在实际的实现过程中是与文件系统相对应的,例如javawork.helloworld所对应的目录是path\javawork\helloworld,而path是在编译该源程序时指定的。比如在命令行中编译上述HelloWorldApp.java文件时,可以在命令行中敲入"javac -d f:\javaproject HelloWorldApp.java",则编译生成的HelloWorldApp.class文件将放在目录f:\javaproject\javawork\helloworld\目录下面,此时f:\javaprojcet相当于path。但是如果在编译时不指定path,则生成的.class文件将放在编译时命令行所在的当前目录下面。比如在命令行目录f:\javaproject下敲入编译命令"javac HelloWorldApp.java",则生成的HelloWorldApp.class文件将放在目录f:\javaproject下面,此时的package语句相当于没起作用。

                                但是,如果程序中包含了package语句,则在运行时就必须包含包名。例如,HelloWorldApp.java程序的第一行语句是:package p1.p2;编译的时候在命令行下输入"javac -d path HelloWorldApp.java",则HelloWorldApp.class将放在目录path\p1\p2的下面,这时候运行该程序时有两种方式:
                                第一种:在命令行下的path目录下输入字符"java p1.p2.HelloWorldApp"。
                                第二种:在环境变量classpath中加入目录path,则运行时在任何目录下输入"java p1.p2.HelloWorldApp"即可。

                                
                              import语句:如果在源程序中用到了除java.lang这个包以外的类,无论是系统的类还是自己定义的包中的类,都必须用import语句标识,以通知编译器在编译时找到相应的类文件。例如上例中的java.awt是系统的包,而javawork.newcentury是用户自定义的包。比如程序中用到了类Button,而Button是属于包java.awt的,在编译时编译器将从目录classpath\java\awt中去寻找类Button,classpath是事先设定的环境变量,比如可以设为:classpath=.;d:\jdk1.3\lib\。 classpath也可以称为类路径,需要提醒大家注意的是,在classpath中往往包含多个路径,用分号隔开。例如classpath=.;d:\jdk1.3\lib\中的第一个分号之前的路径是一个点,表示当前目录,分号后面的路径是d:\jdk1.3\lib\,表示系统的标准类库目录。在编译过程中寻找类时,先从环境变量classpath的第一个目录开始往下找,比如先从当前目录往下找java.awt中的类Button时,编译器找不着,然后从环境变量classpath的第二个目录开始往下找,就是从系统的标准类库目录d:\jdk1.3\lib开始往下找java.awt的Button这个类,最后就找到了。如果要从一个包中引入多个类则在包名后加上".*"表示。

                                如果程序中用到了用户自己定义的包中的类,假如在上面程序中要用到javawork.newcentury包中的类HelloWorldApp,而包javawork.newcentury所对应的目录是f:\javaproject\javawork\newcentury,classpath仍旧是classpath=.;d:\jdk1.3\lib\,则编译器在编译时将首先从当前目录寻找包javawork.newcentury,结果是没有找到;然后又从环境变量classpath的第二个目录d:\jdk1.3\lib\开始往下找,但是仍然没有找到。原因在于包javawork.newcentury是放在目录f:\javaproject下面。因此,需要重新设定环境变量classpath,设为classpath=.;d:\jdk1.3\lib\;f:\javaproject\ 。所以编译器从f:\javaproject开始找包javawork.newcentury就可以找到。

                                
                              源文件的命名规则:如果在源程序中包含有公共类的定义,则该源文件名必须与该公共类的名字完全一致,字母的大小写都必须一样。这是java语言的一个严格的规定,如果不遵守,在编译时就会出错。因此,在一个java源程序中至多只能有一个公共类的定义。如果源程序中不包含公共类的定义,则该文件名可以任意取名。如果在一个源程序中有多个类定义,则在编译时将为每个类生成一个.class文件

                            3. 2010.02.20java数据类型学习

                              2010-02-20 15:03:56

                              public class hello
                              {
                               public static void main(String[] args)
                               {
                                //System.out.println("hello,");
                                byte b;
                                b=3;//-128到+127
                                b=(byte)(b*3);//运算时自动数据类型转换为Int类型,会报错,对运算结果用byte做强制类型转换
                                System.out.println(b);//print自动根据输入类型打印
                                
                                
                                /*
                                short s;//-32768到32767
                                
                                int i;//4个字节
                                long l;//8个字节
                                char ch;//2个字节,无符号0-65535
                                ch='a';//字符存储的是ASCII码,以整数形式存储,同ch=97
                                System.out.paintln(ch);
                                float f=1.3f;//4个字节,加f表明1.3是浮点数,不会报错
                                double d;//8个字节,
                                boolean bool;
                                bool=true|false;
                                
                                /*if(true)
                                {
                                }*/
                                
                                //java数组在定义时不能分配空间
                                int num[];
                                num=new int[3]; //直接定义int num[]=new int[3];
                                num[0]=1;
                                num[1]=12;
                                num[2]=32;
                                System.out.println(num[0]);
                                int[] num;//java建议采用此方法,从定义上一目了然
                                int [] num={1,2,3};//只能在定义时对其进行分配空间
                                int [] num=new int[]{1,2,3}//OK
                                
                                //java二维数组
                                int num[][]=
                                int [][] num;
                                num=new num[3][4];
                                num[0][1]=12;//第一行第二个元素赋值
                                
                                //
                                int i=3;
                                System.out.println(i++);
                                
                                if()
                                {
                                }
                                while(true)
                                {
                                }
                                do
                                {
                                }while{true};
                                 
                                 for(int i=0;i<10;i++)
                                 {
                                 }
                                //在for语句外不能引用i
                               }
                              }

                               

                            4. HTML总结

                              2010-01-29 17:34:58

                              标签 描述 DTD
                              <!--...--> 定义注释。 STF
                              <!DOCTYPE>  定义文档类型。 STF
                              <a> 定义锚。 STF
                              <abbr> 定义缩写。 STF
                              <acronym> 定义只取首字母的缩写。 STF
                              <address> 定义文档作者或拥有者的联系信息。 STF
                              <applet> 不赞成使用。定义嵌入的 applet。 TF
                              <area> 定义图像映射内部的区域。 STF
                              <b> 定义粗体字。 STF
                              <base> 定义页面中所有链接的默认地址或默认目标。 STF
                              <basefont> 不赞成使用。定义页面中文本的默认字体、颜色或尺寸。 TF
                              <bdo> 定义文字方向。 STF
                              <big> 定义大号文本。 STF
                              <blockquote> 定义长的引用。 STF
                              <body> 定义文档的主体。 STF
                              <br> 定义简单的折行。 STF
                              <button> 定义按钮 (push button)。 STF
                              <caption> 定义表格标题。 STF
                              <center> 不赞成使用。定义居中文本。 TF
                              <cite> 定义引用(citation)。 STF
                              <code> 定义计算机代码文本。 STF
                              <col> 定义表格中一个或多个列的属性值。 STF
                              <colgroup> 定义表格中供格式化的列组。 STF
                              <dd> 定义定义列表中项目的描述。 STF
                              <del> 定义被删除文本。 STF
                              <dir> 不赞成使用。定义目录列表。 TF
                              <div> 定义文档中的节。 STF
                              <dfn> 定义定义项目。 STF
                              <dl> 定义定义列表。 STF
                              <dt> 定义定义列表中的项目。 STF
                              <em> 定义强调文本。 STF
                              <fieldset> 定义围绕表单中元素的边框。 STF
                              <font> 不赞成使用。定义文字的字体、尺寸和颜色。 TF
                              <form> 定义供用户输入的 HTML 表单。 STF
                              <frame> 定义框架集的窗口或框架。 F
                              <frameset> 定义框架集。 F
                              <h1> to <h6> 定义 HTML 标题。 STF
                              <head> 定义关于文档的信息。 STF
                              <hr> 定义水平线。 STF
                              <html> 定义 HTML 文档。 STF
                              <i> 定义斜体字。 STF
                              <iframe> 定义内联框架。 TF
                              <img> 定义图像。 STF
                              <input> 定义输入控件。 STF
                              <ins> 定义被插入文本。 STF
                              <isindex> 不赞成使用。定义与文档相关的可搜索索引。 TF
                              <kbd> 定义键盘文本。 STF
                              <label> 定义 input 元素的标注。 STF
                              <legend> 定义 fieldset 元素的标题。 STF
                              <li> 定义列表的项目。 STF
                              <link> 定义文档与外部资源的关系。 STF
                              <map> 定义图像映射。 STF
                              <menu> 不赞成使用。定义菜单列表。 TF
                              <meta> 定义关于 HTML 文档的元信息。 STF
                              <noframes> 定义针对不支持框架的用户的替代内容。 TF
                              <noscript> 定义针对不支持客户端脚本的用户的替代内容。 STF
                              <object> 定义内嵌对象。 STF
                              <ol> 定义有序列表。 STF
                              <optgroup> 定义选择列表中相关选项的组合。 STF
                              <option> 定义选择列表中的选项。 STF
                              <p> 定义段落。 STF
                              <param> 定义对象的参数。 STF
                              <pre> 定义预格式文本。 STF
                              <q> 定义短的引用。 STF
                              <s> 不赞成使用。定义加删除线的文本。 TF
                              <samp> 定义计算机代码样本。 STF
                              <script> 定义客户端脚本。 STF
                              <select> 定义选择列表(下拉列表)。 STF
                              <small> 定义小号文本。 STF
                              <span> 定义文档中的节。 STF
                              <strike> 不赞成使用。定义加删除线文本。 TF
                              <strong> 定义强调文本。 STF
                              <style> 定义文档的样式信息。 STF
                              <sub> 定义下标文本。 STF
                              <sup> 定义上标文本。 STF
                              <table> 定义表格。 STF
                              <tbody> 定义表格中的主体内容。 STF
                              <td> 定义表格中的单元。 STF
                              <textarea> 定义多行的文本输入控件。 STF
                              <tfoot> 定义表格中的表注内容(脚注)。 STF
                              <th> 定义表格中的表头单元格。 STF
                              <thead> 定义表格中的表头内容。 STF
                              <title> 定义文档的标题。 STF
                              <tr> 定义表格中的行。 STF
                              <tt> 定义打字机文本。 STF
                              <u> 不赞成使用。定义下划线文本。 TF
                              <ul> 定义无序列表。 STF
                              <var> 定义文本的变量部分。 STF
                              <xmp> 不赞成使用。定义预格式文本。  
                            5. HTML学习

                              2010-01-29 14:05:03

                              p  段落 paragraph[pærəɡrɑ:f]

                              div 层

                              a 链接标签

                              ul 列表

                              li 列表内容

                              tr 表格行

                              td 表格列

                              table 表格

                              <br>换行            <!--This is a comment-->注释

                              基本的 HTML 标签

                              标签 描述
                              <html> 定义 HTML 文档。
                              <body> 定义文档的主体。
                              <h1> to <h6> 定义标题 1 至标题 6。
                              <p> 定义段落。
                              <br> 插入折行。
                              <hr> 定义水平线。
                              <!--> 定义注释。

                              如何查看 HTML 源码

                              您是否有过这样的经历,当你看到一个很棒的站点,你会很想知道开发人员是如何将它实现的?

                              你有没有看过一些网页,并且想知道它是如何做出来的呢?

                              要揭示一个网站的技术秘密,其实很简单。单击浏览器的“查看”菜单,选择“查看源文件”即可。随后你会看到一个弹出的窗口,窗口内就是实际的 HTML 代码。

                              文本格式化标签

                              标签 描述
                              <b> 定义粗体文本。
                              <big> 定义大号字。
                              <em> 定义着重文字。
                              <i> 定义斜体字。
                              <small> 定义小号字。
                              <strong> 定义加重语气。
                              <sub> 定义下标字。
                              <sup> 定义上标字。
                              <ins> 定义插入字。
                              <del> 定义删除字。
                              <s> 不赞成使用。使用 <del> 代替。
                              <strike> 不赞成使用。使用 <del> 代替。
                              <u> 不赞成使用。使用样式(style)代替。

                              “计算机输出”标签

                              标签 描述
                              <code> 定义计算机代码。
                              <kbd> 定义键盘码。
                              <samp> 定义计算机代码样本。
                              <tt> 定义打字机代码。
                              <var> 定义变量。
                              <pre> 定义预格式文本。
                              <listing> 不赞成使用。使用 <pre> 代替。
                              <plaintext> 不赞成使用。使用 <pre> 代替。
                              <xmp> 不赞成使用。使用 <pre> 代替。

                              引用、引用和术语定义

                              标签 描述
                              <abbr> 定义缩写。
                              <acronym> 定义首字母缩写。
                              <address> 定义地址。
                              <bdo> 定义文字方向。
                              <blockquote> 定义长的引用。
                              <q> 定义短的引用语。
                              <cite> 定义引用、引证。
                              <dfn> 定义一个定义项目。

                              通常情况下,HTML 会裁掉文档中的空格。假如你在文档中连续输入 10 个空格,那么 HTML 会去掉其中的9个。如果使用 &nbsp;,就可以在文档中增加空格。

                              最常用的字符实体

                              显示结果 描述 实体名称 实体编号
                                空格 &nbsp; &#160;
                              < 小于号 &lt; &#60;
                              > 大于号 &gt; &#62;
                              & 和号 &amp; &#38;
                              " 引号 &quot; &#34;
                              ' 撇号  &apos; (IE不支持) &#39;

                              其他一些常用的字符实体

                              显示结果 描述 实体名称 实体编号
                              &cent; &#162;
                              £ &pound; &#163;
                              ¥ 日圆 &yen; &#165;
                              § &sect; &#167;
                              © 版权 &copy; &#169;
                              ® 注册商标 &reg; &#174;
                              × 乘号 &times; &#215;
                              ÷ 除号 &divide; &#247;

                              锚标签和 Href 属性

                              HTML 使用 <a> (锚)标签来创建连接另一个文档的链接。

                              锚可以指向网络上的任何资源:一张 HTML 页面,一幅图像,一个声音或视频文件等等。

                              创建锚的语法:

                              <a href="url">Text to be displayed</a>

                              <a> 用来创建锚。href 属性用于定位需要链接的文档,锚的开始标签和结束标签之间的文字被作为超级链接来显示。

                              这个锚定义了指向 w3school 的链接:

                              <a href="http://www.w3school.com.cn/">Visit W3School!</a>

                              上面的这行在浏览器中显示为这样:Visit W3School!

                              Target 属性

                              使用 Target 属性,你可以定义被链接的文档在何处显示。

                              下面的这行会在新窗口打开文档:

                              <a href="http://www.w3school.com.cn/" target="_blank">Visit W3School!</a>

                              锚标签和 Name 属性

                              Name 属性用于创建被命名的锚(named anchors)。当使用命名锚(named anchors)时,我们可以创建直接跳至页面中某个节的链接,这样使用者就无需不停的滚动页面来寻找他们需要的信息。

                              以下是命名锚的语法:

                              <a name="label">Text to be displayed</a>

                              name 属性用于创建命名锚。锚的名称可以是任何你喜欢的名字。

                              下面这行定义了命名锚:

                              <a name="tips">Useful Tips Section</a>

                              你会注意到,命名锚会以特殊的方式来显示。

                              将 # 符号和锚名称添加到 URL 的末端,就可以直接链接到 tips 这个节,就像这样:

                              <a href="http://www.w3school.com.cn/html/html_links.asp#tips">
                              Jump to the Useful Tips Section
                              </a>

                              框架

                              通过使用框架,你可以在同一个浏览器窗口中显示不止一个页面。每份HTML文档称为一个框架,并且每个框架都独立于其他的框架。

                              使用框架的坏处:

                              • 开发人员必须同时跟踪更多的HTML文档
                              • 很难打印整张页面
                              框架结构标签(<frameset>)
                              • 框架结构标签(<frameset>)定义如何将窗口分割为框架
                              • 每个 frameset 定义了一系列行
                              • rows/columns 的值规定了每行或每列占据屏幕的面积

                              编者注:frameset 标签也被某些文章和书籍译为框架集。

                              框架标签(Frame)

                              Frame. 标签定义了放置在每个框架中的 HTML 文档。

                              在下面的这个例子中,我们设置了一个两列的框架集。第一列被设置为占据浏览器窗口的 25%。第二列被设置为占据浏览器窗口的 75%。HTML 文档 "frame_a.htm" 被置于第一个列中,而 HTML 文档 "frame_b.htm" 被置于第二个列中:

                              <frameset cols="25%,75%">
                                 <frame. src="frame_a.htm">
                                 <frame. src="frame_b.htm">
                              </frameset>

                              基本的注意事项 - 有用的提示:

                              假如一个框架有可见边框,用户可以拖动边框来改变它的大小。为了避免这种情况发生,可以在 <frame> 标签中加入:noresize="noresize"。

                              为不支持框架的浏览器添加 <noframes> 标签。

                              重要提示:不能将 <body></body> 标签与 <frameset></frameset> 标签同时使用!不过,假如你添加包含一段文本的 <noframes> 标签,就必须将这段文字嵌套于 <body></body> 标签内。(在下面的第一个实例中,可以查看它是如何实现的。)

                            6. 743/4<1234>