blogjava-凯发k8网页登录

blogjava-凯发k8网页登录http://www.blogjava.net/zhyiwww/category/8510.html用平实的笔,记录编程路上的点点滴滴………zh-cnthu, 07 apr 2011 08:51:27 gmtthu, 07 apr 2011 08:51:27 gmt60eclipse上显示代码打印边线http://www.blogjava.net/zhyiwww/archive/2011/04/07/347805.htmlzhyiwwwzhyiwwwthu, 07 apr 2011 08:30:00 gmthttp://www.blogjava.net/zhyiwww/archive/2011/04/07/347805.htmlhttp://www.blogjava.net/zhyiwww/comments/347805.htmlhttp://www.blogjava.net/zhyiwww/archive/2011/04/07/347805.html#feedback0http://www.blogjava.net/zhyiwww/comments/commentrss/347805.htmlhttp://www.blogjava.net/zhyiwww/services/trackbacks/347805.html


zhyiwww 2011-04-07 16:30
]]>
java中什么时候使用finalize()方法http://www.blogjava.net/zhyiwww/archive/2010/11/26/339105.htmlzhyiwwwzhyiwwwfri, 26 nov 2010 02:12:00 gmthttp://www.blogjava.net/zhyiwww/archive/2010/11/26/339105.htmlhttp://www.blogjava.net/zhyiwww/comments/339105.htmlhttp://www.blogjava.net/zhyiwww/archive/2010/11/26/339105.html#feedback0http://www.blogjava.net/zhyiwww/comments/commentrss/339105.htmlhttp://www.blogjava.net/zhyiwww/services/trackbacks/339105.html 这一点给了我们发开发人员省了不少心,但是finalize()方法一直是个困惑。
虚拟机在执行垃圾回收之前都会执行对象的finalize(),那么finalize()到底有什么用呢?
其实finalize()主要是给其他调用而创建的空间在对象回收时页同步回收而设置的。
比如,你调用了c语言,使用了mallow()开辟了一段内存空间。在你释放java对象的时候,虚拟机只能释放java对象占用的空间,而不能释放c开辟的内存空间,所你你在释放此对象之前要先回收你在c语言中开辟的空间。
这各时候才用到finalize()方法。
平时的时候不要随便使用finalize()方法。

以上理解是《java编程思想中的理论》,详细深入的理解请参考此书 。




zhyiwww 2010-11-26 10:12
]]>
在linux上安装jdkhttp://www.blogjava.net/zhyiwww/archive/2009/06/24/283938.htmlzhyiwwwzhyiwwwwed, 24 jun 2009 06:53:00 gmthttp://www.blogjava.net/zhyiwww/archive/2009/06/24/283938.htmlhttp://www.blogjava.net/zhyiwww/comments/283938.htmlhttp://www.blogjava.net/zhyiwww/archive/2009/06/24/283938.html#feedback0http://www.blogjava.net/zhyiwww/comments/commentrss/283938.htmlhttp://www.blogjava.net/zhyiwww/services/trackbacks/283938.htmljdk-6u14-linux-x64.bin

[2]添加执行权限
chmod a x jdk-6u14-linux-x64.bin

[3]执行安装
./jdk-6u14-linux-x64.bin
默认的安装路径是/usr/java/jdk-1.6.0_14

[4]最关键的一步,配置环境变量
vim /etc/profile
添加如下内容:
设置path

path=$path:/usr/java/jdk-1.6.0_14/bin
export path

设置java_home
export java_home=/usr/java/jdk-1.6.0_14

[5]让你的设置生效
source /etc/profile

[6]检查你的设置效果
[xxx java]$ echo $path
/usr/kerberos/bin:/usr/local/bin:/bin:/usr/bin:/home/zhangyi/bin:/usr/java/jdk1.6.0_14/bin
[xxx java]$

[xxx java]$ echo $java_home
/usr/java/jdk1.6.0_14
[xxx java]$

[xxx java]$ java
usage: java [-options] class [args...]
           (to execute a class)
   or  java [-options] -jar jarfile [args...]
           (to execute a jar file)

where options include:
    -d32          use a 32-bit data model if available

    -d64          use a 64-bit data model if available
    -server      to select the "server" vm
                  the default vm is server.
                 
    -cp
。。。。。。。。。。。。


[xxx java]$ javac
用法:javac <选项> <源文件>
其中,可能的选项包括:
  -g                         生成所有调试信息
  -g:none                    不生成任何调试信息
  -g:{lines,vars,source}     只生成某些调试信息
  -nowarn                    不生成任何警告
  -verbose                   输出有关编译器正在执行的操作的消息
  -deprecation               输出使用已过时的 api 的源位置
  -classpath <路径>            指定查找用户类文件和注释处理程序的位置
  -cp <路径>                   指定查找用户类文件和注释处理程序的位置
  -sourcepath <路径>           指定查找输入源文件的位置
  -bootclasspath <路径>        覆盖引导类文件的位置
  -extdirs <目录>              覆盖安装的扩展目录的位置
。。。。。。。。。。。。。。。。

如果你能看到上面的额内容,那么你的jdk就安装和配置成功了。









zhyiwww 2009-06-24 14:53
]]>
如何取得resultset的行数http://www.blogjava.net/zhyiwww/archive/2009/06/19/283265.htmlzhyiwwwzhyiwwwfri, 19 jun 2009 09:25:00 gmthttp://www.blogjava.net/zhyiwww/archive/2009/06/19/283265.htmlhttp://www.blogjava.net/zhyiwww/comments/283265.htmlhttp://www.blogjava.net/zhyiwww/archive/2009/06/19/283265.html#feedback2http://www.blogjava.net/zhyiwww/comments/commentrss/283265.htmlhttp://www.blogjava.net/zhyiwww/services/trackbacks/283265.html在resultset对象里面,我们找不到取得结果行数的办法。
其实我们通常的解决方法无非有一下几种:

[1]
connection con=....
statement stmt = con.createstatement();
   
 string sqlstr = "count(*) as total ";
 resultset rst = stmt.executequery(sqlstr);
 
 rst.next();
int total =  rst.getint("total");

缺点:如果想要遍历结果集,你不得不在执行一次查询,取得结果集。

[2]

            string accqrysql = "select * from accounts";
            connection con = dbutils.getconnection();
            statement stmt = con.createstatement(resultset.type_scroll_sensitive,resultset.concur_updatable);
            
                    resultset rst = stmt.executequery(accqrysql);

                       你可以通过下面的方法来取得结果集的记录数目
                       rst.last();
                       int total = rst.getrow();

                       这时,你可以取得记录数目。

                       如果
while(rst.next()){
........
}      

int total = rst.getrow();
你将得到的total是0

因为,getrow是在遍历结果集的时候的指针,也是在结果集内移动的指针,也就是说,指向了当前的记录索引号,所以,在进行结果集的遍历前和后都被重置成0。
所以,想取得记录的条数,可以把指针移到最后一条记录,然后取得当前记录的编号就是记录的条数。
所以,必须用
rst.last();
之后才能用 rst.getrow()来取得,才能取到值。

注意:想要用这种方法来取得结果集的行数,必须用 可滚动结果集      
    statement stmt = con.createstatement(resultset.type_scroll_sensitive,resultset.concur_updatable);
否则,你就不能执行
rst.last()
也就不能取得结果集的条数。



zhyiwww 2009-06-19 17:25
]]>
hibernate多对多删除和更新中间表http://www.blogjava.net/zhyiwww/archive/2009/02/16/254872.htmlzhyiwwwzhyiwwwmon, 16 feb 2009 05:14:00 gmthttp://www.blogjava.net/zhyiwww/archive/2009/02/16/254872.htmlhttp://www.blogjava.net/zhyiwww/comments/254872.htmlhttp://www.blogjava.net/zhyiwww/archive/2009/02/16/254872.html#feedback7http://www.blogjava.net/zhyiwww/comments/commentrss/254872.htmlhttp://www.blogjava.net/zhyiwww/services/trackbacks/254872.html这几天,在多队多的中间表的操作上遇到了点麻烦,总是不能删除和更新中间表,因为,我使用的是一队多的关联,
映射的是中间表,所以,我虽然操作了set,但是总是不能反映到中间表上去。

后来使用如下的方法来解决,看如下的例子:

(1)三个表

create table `poi` (
  `poi_id` integer(10) unsigned not null auto_increment,
  `poi_name` varchar(45) collate latin1_swedish_ci not null default '',
  primary key (`poi_id`),
  unique key `poi_name` (`poi_name`)

)engine=innodb
auto_increment=15 character set 'latin1' collate 'latin1_swedish_ci'
comment='innodb free: 3072 kb';


create table `user` (
  `user_id` integer(10) unsigned not null auto_increment,
  `username` varchar(45) collate latin1_swedish_ci not null default '',
  `password` varchar(45) collate latin1_swedish_ci not null default '',
  primary key (`user_id`),
  unique key `username` (`username`)

)engine=innodb
auto_increment=16 character set 'latin1' collate 'latin1_swedish_ci'
comment='innodb free: 3072 kb';


关联表

create table `user_poi` (
  `user_id` integer(10) unsigned not null auto_increment,
  `poi_id` integer(10) unsigned not null,
  key `fk_user_pois_poiid` (`poi_id`),
  key `fk_user_pois_userid` (`user_id`),
  constraint `fk_user_pois_poiid` foreign key (`poi_id`) references `poi` (`poi_id`) on delete cascade on update cascade,
  constraint `fk_user_pois_userid` foreign key (`user_id`) references `user` (`user_id`) on delete cascade on update cascade

)engine=innodb
auto_increment=3 character set 'latin1' collate 'latin1_swedish_ci'
comment='innodb free: 3072 kb; (`poi_id`) refer `demo/poi`(`poi_id`) on update cascade; (';


(2)pojo


/**
 * @hibernate.class table="user"
 */
public class user implements java.io.serializable {

    // fields

    private integer userid;
    private string username;
    private string password;

    /**
     * poi set
     */
    private set pois = new hashset();
   
   
   
    // constructors

    /**
     * @hibernate.set table="user_poi" cascade="all"
     * @hibernate.collection-key column="user_id"
     * @hibernate.collection-many-to-many column="poi_id" class="org.zy.pro.pd.dao.poi"
     */
    public set getpois() {
        return pois;
    }

    public void setpois(set pois) {
        this.pois = pois;
    }

    public user() {
    }

    /** full constructor */
    public user(string username, string password) {
        this.username = username;
        this.password = password;
    }

    // property accessors


    /**
     * @hibernate.id column="user_id" generator-class="increment"
     */
    public integer getuserid() {
        return this.userid;
    }

    public void setuserid(integer userid) {
        this.userid = userid;
    }

    /**
     * @hibernate.property column="username"
     * @return
     */
    public string getusername() {
        return this.username;
    }

    public void setusername(string username) {
        this.username = username;
    }

    /**
     * @hibernate.property column="password"
     * @return
     */
    public string getpassword() {
        return this.password;
    }

    public void setpassword(string password) {
        this.password = password;
    }

}


/**
 * @hibernate.class table="poi"
 */
public class poi  implements java.io.serializable {


    // fields   

     private integer poiid;
     private string poiname;


    // constructors

    /** default constructor */
    public poi() {
    }

    /** minimal constructor */
    public poi(string poiname) {
        this.poiname = poiname;
    }


    /**
     * @hibernate.id column="poi_id" generator-class="increment"
     */
    public integer getpoiid() {
        return this.poiid;
    }
   
    public void setpoiid(integer poiid) {
        this.poiid = poiid;
    }

    /**
     * @hibernate.property column="poi_name"
     * @return
     */
    public string getpoiname() {
        return this.poiname;
    }
   
    public void setpoiname(string poiname) {
        this.poiname = poiname;
    }
}



(3)hibernate mapping

利用xdolect根据bean生成映射

poi.hbm.xml



    "-//hibernate/hibernate mapping dtd 3.0//en"
    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

>
            name="org.zy.pro.pd.dao.poi"
        table="poi"
    >

                    name="poiid"
            column="poi_id"
            type="java.lang.integer"
        >
           
    
           

       

                    name="poiname"
            type="java.lang.string"
            update="true"
            insert="true"
            column="poi_name"
        />

   



user.hbm.xml



    "-//hibernate/hibernate mapping dtd 3.0//en"
    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

>
            name="org.zy.pro.pd.dao.user"
        table="user"
    >

                    name="userid"
            column="user_id"
            type="java.lang.integer"
        >
           

           

       

                    name="pois"
            table="user_poi"
            lazy="false"
            cascade="all"
            sort="unsorted"
        >

                            column="user_id"
            >
           

                            class="org.zy.pro.pd.dao.poi"
                column="poi_id"
                outer-join="auto"
             />

       

                    name="username"
            type="java.lang.string"
            update="true"
            insert="true"
            column="username"
        />

                    name="password"
            type="java.lang.string"
            update="true"
            insert="true"
            column="password"
        />



   



(4)关联添加
        userdao ud = new userdao();
        list l = ud.findall();
        assertnotnull(l);
       
        user u = ud.findbyid(2);
        assertnotnull(u);
       
        set pois = u.getpois();
       
        poi p = new poi("moc" new java.util.random().nextint(1000000));
        system.out.print(p.getpoiid());
       
       
        pois.add(p);

//关联删除
//        u.setpois(null);
       
        poi pp = pd.findbyid(12);
        pois.remove(pp);
       
       
        ud.begin();
        ud.merge(u);
        ud.commit();


// 关联更新也可以,只要改变set就可以了。



使用总结
[1]使用多对多关系
    在映射的是时候要使用many-to-many
    所以,在user的set集合里面直接存放的是poi的对象,而不是user_poi表的对象
[2]reverse : false
    允许反转操作
[3]casecade : all
    只要允许级联操作才可以实现级联的删除和更新

如果使用一对多,就只能更新中间表的普通字段,不能更新主键字段,也不能删除中间表记录
所以只能维护中间表的关联,但是不能更新中间表的信息。





zhyiwww 2009-02-16 13:14
]]>
ant运行java不能输出log4j日志问题的解决http://www.blogjava.net/zhyiwww/archive/2008/12/19/247297.htmlzhyiwwwzhyiwwwfri, 19 dec 2008 03:41:00 gmthttp://www.blogjava.net/zhyiwww/archive/2008/12/19/247297.htmlhttp://www.blogjava.net/zhyiwww/comments/247297.htmlhttp://www.blogjava.net/zhyiwww/archive/2008/12/19/247297.html#feedback0http://www.blogjava.net/zhyiwww/comments/commentrss/247297.htmlhttp://www.blogjava.net/zhyiwww/services/trackbacks/247297.html 程序在eclipse下运行,日志输出正常。我的build.xml文件如下:


   
   
   
   
       
                       
           
           
               
       

           
   

   
       
   

   
       
           
       

   

   
       
           
       

   



我的第一次分析,就觉得可能是,ant系统在运行的时候没有找到配置文件log4j.properties.
所以,我就把src\log4j.properties 复制到 工程的根目录,然后再运行,发现还是不行。

所以,我就想到是src下的配置文件,在编译之后应该复制到了和classes目录下相对应的路径。
所以,我就到bin目录下找,果然没有。
因为我在build.xml文件中,compile的时候,并没有把配置文件log4j.properties复制到其对应目录。
所以,复制src\log4j.properties到bin\log4j.properties。
再运行,ok了。

凯发天生赢家一触即发官网的解决方案:
把src目录的所有配置文件(此处是log4j.properties配置文件)复制到classes目录的对应目录。

修改build.xml如下:


   
   
   
   
       
                       
           
           
               
       

           
   

   
       
   

   
       
           
       

   

   
       
           
       

   




   
   
   
   
       
                       
           
           
               
       

           
   

   
       
   

   
       
           
       

       
           
                   
               
           

       

   

   
       
           
       

   



上面的深蓝色的部分是新添加的部分。这样,在编译的时候就把所有的配置文件也一同复制到了class文件夹下面了。

再ant run ,就在文件中有日志了。









zhyiwww 2008-12-19 11:41
]]>
我自己写的一个ant通用模板build.xmlhttp://www.blogjava.net/zhyiwww/archive/2008/10/28/237200.htmlzhyiwwwzhyiwwwtue, 28 oct 2008 12:12:00 gmthttp://www.blogjava.net/zhyiwww/archive/2008/10/28/237200.htmlhttp://www.blogjava.net/zhyiwww/comments/237200.htmlhttp://www.blogjava.net/zhyiwww/archive/2008/10/28/237200.html#feedback0http://www.blogjava.net/zhyiwww/comments/commentrss/237200.htmlhttp://www.blogjava.net/zhyiwww/services/trackbacks/237200.html

 
 
    
    

 
    
    
 

 
    
    
    
    
    
 
 
    
        
            
        

        
            
        

    

 
 
    
        
    

 
 
    
        
    

 
    
        
        
    

 
 
    
        compiling the java code
                    debug="on">
            
        

    

    
        
            
                
                
            

        

    

    
        
            
                
            

        

    

    
    
    
    
    
    
    


zhyiwww 2008-10-28 20:12
]]>
mysql hibernate jsp中文乱码问题的解决http://www.blogjava.net/zhyiwww/archive/2008/09/09/227986.htmlzhyiwwwzhyiwwwtue, 09 sep 2008 08:40:00 gmthttp://www.blogjava.net/zhyiwww/archive/2008/09/09/227986.htmlhttp://www.blogjava.net/zhyiwww/comments/227986.htmlhttp://www.blogjava.net/zhyiwww/archive/2008/09/09/227986.html#feedback0http://www.blogjava.net/zhyiwww/comments/commentrss/227986.htmlhttp://www.blogjava.net/zhyiwww/services/trackbacks/227986.html
1:检查mysql安装目录下的配置文件my.ini,

[mysql]
默认的default-character-set=latin1
改为default-character-set=utf8(不是utf-8)

(注意,如果需要导数据,请先修改完编码,再进行数据导入,同时,注意你的源数据的格式,需要是utf8的编码)

2:检查你的连接:
jdbc:mysql://localhost:3306/mydb?useunicode=true&characterencoding=utf8(不是utf-8)
连接数据库的编码也要设置为utf8

3: 检查你的页面
<%@ page language="java" import="java.util.*" pageencoding="utf-8"%>
设置文件的编码


设置内容编码

如果这几个地方都统一了,应该就没有什么问题了。

中文检索的实现:
在保证上面编码问题正确的情况下进行。

首先,如果jsp页面到action,需要进行编码的转换
因为,jsp的页面form提交到action时,默认的是iso-8859-1的编码,需要转换成utf-8编码
代码如下:
string keystr = request.getparameter("key");
       
        string pagestr = request.getparameter("page");
        string pagesizestr = request.getparameter("pagesize");
       
       
        string key="";
        try {
            key = (keystr==null?"":new string(keystr.getbytes("iso-8859-1"),"utf-8"));
        } catch (unsupportedencodingexception e2) {
            // todo auto-generated catch block
            e2.printstacktrace();
        }
       
这样,能保证,在jsp到action的编码不会出现乱码。
然后,在dao端,通过hql进行中文模糊匹配检索,代码如下:
    public list findlikekey(string key) {
        log.debug("finding all pois instances");
        try {
            //'%" key "%'
            string querystring = "from pois as poi where poi.poiname like '%" key "%'";
            query queryobject = getsession().createquery(querystring);
           
//            queryobject.setstring(0, "'%" key "'");
           
            log.info("query string is : " queryobject.getquerystring());
           
            return queryobject.list();
        } catch (runtimeexception re) {
            log.error("find all failed", re);
            throw re;
        }
    }

这样就可以实现检索的模糊匹配。
这样就ok了。






zhyiwww 2008-09-09 16:40
]]>
string和stringbuffer的区别http://www.blogjava.net/zhyiwww/archive/2008/04/25/195993.htmlzhyiwwwzhyiwwwfri, 25 apr 2008 07:37:00 gmthttp://www.blogjava.net/zhyiwww/archive/2008/04/25/195993.htmlhttp://www.blogjava.net/zhyiwww/comments/195993.htmlhttp://www.blogjava.net/zhyiwww/archive/2008/04/25/195993.html#feedback1http://www.blogjava.net/zhyiwww/comments/commentrss/195993.htmlhttp://www.blogjava.net/zhyiwww/services/trackbacks/195993.html从对象实现上来说,都是通过char[]来实现的。
如果new string(),那么数组的长度为0,如果new string("string"),那么char[]数组的长度就是你创建的字符串的长度。
这个char[]在字符串创建以后是不会改变的。
如果你只对这个串本身进行查找等对字符串无改变的操作的话,对于此数组本身是没有影响的。但是如果,你要执行的是一个对此字符串本身有改变的操作的话,那么,是不可以的。
但是strin对象为我们提供了此类操作的方法,比如concat()方法,源代码如下:
    public string concat(string s) {
        int i = s.length();
        if (i == 0) {
            return this;
        } else {
            char ac[] = new char[count i];
            getchars(0, count, ac, 0);
            s.getchars(0, i, ac, count);
            return new string(0, count i, ac);
        }
    }
由此,我们可以知道,其实,此方法给我们返回的已经不是当前的字符串了,而是又创建了一个新的字符串,然后返回。
其他的方法也类似。

stringbuffer的实现,也是通过char[]来实现的。但是,默认的情况下,其自己创建了一个缓存数组,长度是16,这一点,我们可以通过stringbuffer的构造器来知道:
    public stringbuffer() {
    super(16);
    }
这个方法初始化了,char[]数组的长度是16。
其父类构造器如下:
    abstractstringbuilder(int capacity) {
        value = new char[capacity];
    }
也就是说,默认的数组长度是16。
很多的时候,容量16对于我们需要的串来说,可能远远不够。怎么办呢?
在进行串的append的时候,stringbuffer会检测剩余容量,并会重新扩充至当前容量的2倍。
    public abstractstringbuilder append(string str) {
    if (str == null) str = "null";
        int len = str.length();
    if (len == 0) return this;
    int newcount = count len;
    if (newcount > value.length)
        expandcapacity(newcount);
    str.getchars(0, len, value, count);
    count = newcount;
    return this;
    }

而扩容的同时,会创建一个新的数组,并将原来的数组内容复制到新的数组里面。
由此可见,如果容量不足的话,那么每一次扩容,都会耗掉大量的资源,尽管,你可能扩充的容量也很小。如果,数组的长度很大,耗掉的资源就会更多。
所以,我们在使用stringbuffer的时候,要一次在创建对象的时候给与足够多的空间,这样会提高性能。
有利必有弊,这个性能是以空间为代价。但是相对于性能的丧失来说,应该还是值得的。

如果不需要扩容的话,那么所有的操作都是基于同一个数组,那么像对于string的操作来说,不需要每一次都创建对象了,省去了创建对象的时间,性能是要好很多的,同时,string的串操作,会用去很多的空间,对于虚拟机来说,也增加了很大的压力。





zhyiwww 2008-04-25 15:37
]]>
对hashcode的一点简单认识http://www.blogjava.net/zhyiwww/archive/2008/04/22/194845.htmlzhyiwwwzhyiwwwtue, 22 apr 2008 10:03:00 gmthttp://www.blogjava.net/zhyiwww/archive/2008/04/22/194845.htmlhttp://www.blogjava.net/zhyiwww/comments/194845.htmlhttp://www.blogjava.net/zhyiwww/archive/2008/04/22/194845.html#feedback1http://www.blogjava.net/zhyiwww/comments/commentrss/194845.htmlhttp://www.blogjava.net/zhyiwww/services/trackbacks/194845.htmljava给我们提供了两种判断对象对等的方式。如果我们判断两个对象是否相等,那么直接用“==”运算就可以了。然而,判断两个对象对等,就没有那么简单了。
在java中,我们常常通过equals()方法来判断两个对象的对等。其实,我么还可以通过hashcode()来判断两个对象的对等。

看下面的例子:

import java.util.list;

public class mybag{
    float money;
    list books;  
}
我们如何判断两个mybag对象是对等的呢?也就是说,如果有两个mybag的对象bag1和bag2,通过什么的办法能说明这个两个对象是相同的呢?
先声名两个概念:
两个对象相等,指的是,两个引用指向了同一个对象,也就是说,指向了内存中的同一个地址。
两个对象相同(对等),指得是两个对象的任何属性都相等,但是,不是一个对象。

所以,对于上面的mybag的对象对等,那么,两个对象的money要一样,同时,books要对等。那么如何去判断呢?我们通常会自己去实现equals()方法去判断,方法如下:

    public boolean equals(object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getclass() != obj.getclass())
            return false;
        final mybag other = (mybag) obj;
        if (books == null) {
            if (other.books != null)
                return false;
        } else if (!books.equals(other.books))
            return false;
        if (float.floattointbits(money) != float.floattointbits(other.money))
            return false;
        return true;
    }

我们也可以通过实现hashcode()来实现:
    public int hashcode() {
        final int prime = 31;
        int result = 1;
        result = prime * result ((books == null) ? 0 : books.hashcode());
        result = prime * result float.floattointbits(money);
        return result;
    }

那么我们判断两个对象对等时,就可以这样来实现了:
if(bag1.equals(bag2)){
    // 对等
}

或者
if(bag1.hasecode()==bag2.hashcode()){
    // 对等
}

为什么这种方式也能判断两个对象对等呢?
因为,任何一个对象的hashcode是唯一的,并且和气对象属性按照一定的规则相关的。

比如,一个integer的hashcode值就是其整数值,因为integer的hasecode()是这样实现的:
    public int hashcode() {
        return value;
    }
    public boolean equals(object obj) {
        if (obj instanceof integer)
            return value == ((integer) obj).intvalue();
        else
            return false;
    }

由此可以看到,也对象的hashcode是和其属性有一定的联系,规则和属性的值有一定的联系,这个规则决定了有相同的hashcode,就有两个对象的属性对等。



zhyiwww 2008-04-22 18:03
]]>
从类的改造小谈内部类http://www.blogjava.net/zhyiwww/archive/2007/10/25/155806.htmlzhyiwwwzhyiwwwthu, 25 oct 2007 03:19:00 gmthttp://www.blogjava.net/zhyiwww/archive/2007/10/25/155806.htmlhttp://www.blogjava.net/zhyiwww/comments/155806.htmlhttp://www.blogjava.net/zhyiwww/archive/2007/10/25/155806.html#feedback1http://www.blogjava.net/zhyiwww/comments/commentrss/155806.htmlhttp://www.blogjava.net/zhyiwww/services/trackbacks/155806.html
中关于内部类的介绍和分析的时候,就想到了我刚写的那个,是不是也可以改用内部类来实现呢?
所以就做了一个简单的改进,代码如下:
package org.zy.demo;

import java.io.bufferedreader;
import java.io.ioexception;
import java.io.inputstreamreader;
import java.net.malformedurlexception;
import java.net.url;
import java.util.timer;
import java.util.timertask;
import java.util.regex.matcher;
import java.util.regex.pattern;

public class parseurlusinginnerclass {
   
   
   
    public static void main(string[] args){
        timer t = new timer();
        t.schedule(new parsetask(),0,5*60*60);           
    }
   
   
    class parsetask extends timertask{

        public void run(){
            system.out.println("runing");
            try {
                // create url object
                url url = new ;
                // get the input stream reader from the url
                inputstreamreader isr = new inputstreamreader(url.openstream());
                // buffered the reader
                bufferedreader br = new bufferedreader(isr);
               
                // store the temp string
                stringbuffer sb = new stringbuffer(10000);
                // temporary variable for each read
                string tmp="";
               
                // read the content from reader
                while((tmp=br.readline())!=null){
                    sb.append(tmp);
                }
                system.out.println(sb.tostring());
                // match from the orginal string using  reglex express
                pattern p = pattern.compile("<<.*异人.*>>");
                matcher m = p.matcher(sb.tostring());               
               
               
            } catch (malformedurlexception e) {
                // todo auto-generated catch block
                e.printstacktrace();
            } catch (ioexception e) {
                // todo auto-generated catch block
                e.printstacktrace();
            }
        }
    }
}

看蓝色代码部分,很显然,我直接作了一个最简单的修改,就是直接把外面定义的拿给类拿到了public类的里面,其他的代码都没有改变。
但是代码却出现了问题。
    public static void main(string[] args){
        timer t = new timer();
        t.schedule(new parsetask(),0,5*60*60);           
    }
上面的这段代码就出现了问题,为什么呢?
我们知道,一个static的方法,只能使用static属性和方法和static类,那么
new parsetask()能行吗?
问题就出在这,此处不能创建一个非静态类的对象。
所以,我们就只能在类的定义前面添加一个static,让其成为一个静态类就可以了。
修改后的代码如下:
static class parsetask extends timertask{
一般情况下,我们不创建static类,这个地方是因为我们在static main 方法里面直接使用,所以就只能创建静态类。
我们的代码还可以改变:
可以把调用部分封装成一个方法,然后在此方法里面调用内部类,就可以不用定义静态类了,代码如下:

package org.zy.demo;

import java.io.bufferedreader;
import java.io.ioexception;
import java.io.inputstreamreader;
import java.net.malformedurlexception;
import java.net.url;
import java.util.timer;
import java.util.timertask;
import java.util.regex.matcher;
import java.util.regex.pattern;

public class parseurlusinginnerclass1 {
   
    public void parse{
        timer t = new timer();
        t.schedule(new parsetask(),0,5*60*60);       
    }
   
    public static void main(string[] args){
        parseurlusinginnerclass1 puic = new parseurlusinginnerclass1();
        puic.parse;
    }
   
   
    class parsetask extends timertask{

        public void run(){
            system.out.println("runing");
            try {
                // create url object
                url url = new ;
                // get the input stream reader from the url
                inputstreamreader isr = new inputstreamreader(url.openstream());
                // buffered the reader
                bufferedreader br = new bufferedreader(isr);
               
                // store the temp string
                stringbuffer sb = new stringbuffer(10000);
                // temporary variable for each read
                string tmp="";
               
                // read the content from reader
                while((tmp=br.readline())!=null){
                    sb.append(tmp);
                }
                system.out.println(sb.tostring());
                // match from the orginal string using  reglex express
                pattern p = pattern.compile("<<.*异人.*>>");
                matcher m = p.matcher(sb.tostring());               
               
               
            } catch (malformedurlexception e) {
                // todo auto-generated catch block
                e.printstacktrace();
            } catch (ioexception e) {
                // todo auto-generated catch block
                e.printstacktrace();
            }
        }
    }
}
看绿色代码部分就可以知道了。
对于方法的改进,我们可以给parseurl加上一个参数url,那么,其他的相对应的部分也要做一些简单的修改,代码如下:
package org.zy.demo;

import java.io.bufferedreader;
import java.io.ioexception;
import java.io.inputstreamreader;
import java.net.malformedurlexception;
import java.net.url;
import java.util.timer;
import java.util.timertask;
import java.util.regex.matcher;
import java.util.regex.pattern;

public class parseurlusinginnerclass2 {
   
    public void parse{
        timer t = new timer();
        t.schedule(new parsetask(url),0,5*60*60);       
    }

   
    public static void main(string[] args){
        parseurlusinginnerclass2 puic = new parseurlusinginnerclass2();
       
        try {
          
url url = new ;
            puic.parse;

        } catch (malformedurlexception e) {
            // todo auto-generated catch block
            e.printstacktrace();
        }
   
    }
   
   
    class parsetask extends timertask{
        url url;
        public parsetask(url url){
            this.url = url;
        }

        public void run(){
            system.out.println("runing");
            try {
                // create url object
                //url url = new ;
                // get the input stream reader from the url
                inputstreamreader isr = new inputstreamreader(this.url.openstream());
                // buffered the reader
                bufferedreader br = new bufferedreader(isr);
               
                // store the temp string
                stringbuffer sb = new stringbuffer(10000);
                // temporary variable for each read
                string tmp="";
               
                // read the content from reader
                while((tmp=br.readline())!=null){
                    sb.append(tmp);
                }
                system.out.println(sb.tostring());
                // match from the orginal string using  reglex express
                pattern p = pattern.compile("<<.*异人.*>>");
                matcher m = p.matcher(sb.tostring());               
               
               
            } catch (malformedurlexception e) {
                // todo auto-generated catch block
                e.printstacktrace();
            } catch (ioexception e) {
                // todo auto-generated catch block
                e.printstacktrace();
            }
        }
    }
}

上面在用到此url的地方和参数传递的地方都要做相应的修改,比如说
parsetask类的构造器,都要做些修改。
上面的类的定义和方法的定义,已经可以实现减少部分耦合了。其实在run方法里面,如果从代码重用的角度来看的话,那么我们还可以进行代码改进和重构。
就上面的一个demo,我们也可以简单的看到在类的设计中,我们还是有很多的问题要考虑,还是有很多的细节可以注意,来提高我们的代码质量。
以上仅是一点简单的理解。






zhyiwww 2007-10-25 11:19
]]>
就一个面试题做的一个小小demohttp://www.blogjava.net/zhyiwww/archive/2007/10/24/155590.htmlzhyiwwwzhyiwwwwed, 24 oct 2007 06:34:00 gmthttp://www.blogjava.net/zhyiwww/archive/2007/10/24/155590.htmlhttp://www.blogjava.net/zhyiwww/comments/155590.htmlhttp://www.blogjava.net/zhyiwww/archive/2007/10/24/155590.html#feedback1http://www.blogjava.net/zhyiwww/comments/commentrss/155590.htmlhttp://www.blogjava.net/zhyiwww/services/trackbacks/155590.html
每5分钟遍历一下页面(), 
请统计页面中"《"和"》"之间有多少个"异人"这两个字,将这数值弹出一个alert并且发信给指定的邮件地址 
获取页面内所有地方的以"<< >>"为标示的这个符号代表书名号,获取之中的内容 
<<使用正则表达式>>
功能点: 
1)url抓取页面 
2)正则表达式匹配 
3)邮件系统调用 
请注意设计思路和代码规范

就这个问题我写了一个demo,代码如下:
package org.zy.demo;

import java.io.bufferedinputstream;
import java.io.bufferedreader;
import java.io.ioexception;
import java.io.inputstreamreader;
import java.io.reader;
import java.net.malformedurlexception;
import java.net.url;
import java.util.date;
import java.util.timer;
import java.util.timertask;
import java.util.regex.matcher;
import java.util.regex.pattern;

/**
 *
 * @author zhangyi
 * zhyiwww@163.com
 *
 * 从url里面读取内容,然后分析,用正则表达式匹配,返回结果
 */

/*
     每5分钟遍历一下页面(http://post.baidu.com/f?kw=���˰���¼),
    请统计页面中"《"和"》"之间有多少个"异人"这两个字,将这数值弹出一个alert并且发信给指定的邮件地址
    获取页面内所有地方的以"<< >>"为标示的这个符号代表书名号,获取之中的内容
    <<使用正则表达式>>
    功能点:
    1)url抓取页面
    2)正则表达式匹配
    3)邮件系统调用
 */
public class parseurlcontent {
   
   
    public static void main(string[] args){
        timer t = new timer();
        t.schedule(new parsetask(),0,5*60*60);       
    }
   
   
}

class parsetask extends timertask{
    public void run(){
        system.out.println("runing");
        try {
            // create url object
            url url = new ;
            // get the input stream reader from the url
            inputstreamreader isr = new inputstreamreader(url.openstream());
            // buffered the reader
            bufferedreader br = new bufferedreader(isr);
           
            // store the temp string
            stringbuffer sb = new stringbuffer(10000);
            // temporary variable for each read
            string tmp="";
           
            // read the content from reader
            while((tmp=br.readline())!=null){
                sb.append(tmp);
            }
            system.out.println(sb.tostring());
            // match from the orginal string using  reglex express
            pattern p = pattern.compile("<<.*异人.*>>");
            matcher m = p.matcher(sb.tostring());        
            // 此处可以做进一步的处理
           
           
           
        } catch (malformedurlexception e) {
            // todo auto-generated catch block
            e.printstacktrace();
        } catch (ioexception e) {
            // todo auto-generated catch block
            e.printstacktrace();
        }
    }
}
实现思路:
1 从url读取内容流
2 解析流,用正则表达式来匹配取出想要查找的内容

我没有详细的实现匹配的部分,其实,如果是要迭代的去遍历内容里面所有的url,然后再解析也是可以实现的,就把上面的代码封装成一个方法parse,然后,解析,迭代,就可以了。
这就是我的实现思路。



zhyiwww 2007-10-24 14:34
]]>
回复两个朋友的图片裁剪问题http://www.blogjava.net/zhyiwww/archive/2007/10/18/153967.htmlzhyiwwwzhyiwwwthu, 18 oct 2007 09:54:00 gmthttp://www.blogjava.net/zhyiwww/archive/2007/10/18/153967.htmlhttp://www.blogjava.net/zhyiwww/comments/153967.htmlhttp://www.blogjava.net/zhyiwww/archive/2007/10/18/153967.html#feedback4http://www.blogjava.net/zhyiwww/comments/commentrss/153967.htmlhttp://www.blogjava.net/zhyiwww/services/trackbacks/153967.html(zhyiwww@163.com  转载请注明出处 作者:zhyiwww )
最近,有两个朋友在问我关于图片裁剪的问题,不过以前的代码找不到了,所以,就把完整的例子又整理了一下。可以实现在一个完整的图片上,根据需要,定位想要截取的图片的左上角的坐标和图片的大小,就可以取得该图片。
完整的实现代码如下:
package org.zy.app;

import java.io.file;
import java.io.inputstream;
import java.io.ioexception;
import java.util.iterator;
import java.awt.rectangle;
import java.awt.image.bufferedimage;
import javax.imageio.imagereader;
import javax.imageio.imagereadparam;
import javax.imageio.imageio;
import javax.imageio.stream.imageinputstream;

/**
 * @author zhangyi
 * date : 2007-10-18
 */
public class splitimage {

    /**
     * ��ȡͼ���ļ� �� imagereader
     *
     * @param imgpath
     * @throws ioexception
     */

    public void readimage() throws ioexception {
        // get jpeg image reader iterator
        iterator readers = imageio.getimagereadersbyformatname("jpg");
        system.out.println(readers);
       
        // get image reader
        imagereader reader = (imagereader) readers.next();
        system.out.println(reader);

        // get original image input stream
        inputstream source = this.getclass().getresourceasstream("img01.jpg");
        system.out.println("image input source is : " source);
       
        // get imageinputstream of the image to split
        imageinputstream iis = imageio.createimageinputstream(source);
        reader.setinput(iis, true);
       
        // the image param
        imagereadparam param = reader.getdefaultreadparam();
        int imageindex = 0;
//       
//        int half_width = reader.getwidth(imageindex) / 2;
//        int half_height = reader.getheight(imageindex) / 2;

        // the coordinate and the size on the image that you want to split on
        rectangle rect = new rectangle(300, 490, 200, 100);
        param.setsourceregion(rect);
       
        bufferedimage bi = reader.read(0, param);
       
        // write the split picture
        imageio.write(bi, "jpg", this.initdestfile());
    }

    public file initdestfile() throws ioexception {
        file f = new file("c:\\img02.jpg");

        if (f.exists()) {
            f.delete();
        }
        f.createnewfile();
        return f;
    }

    public static void main(string[] args) {
        splitimage si = new splitimage();
        try {
            si.readimage();
        } catch (ioexception e) {
            system.out.println("exception");
        }
    }
}

代码下载
这只是一个简单的实现。当然,也可以在servlet端来实现此功能。


zhyiwww 2007-10-18 17:54
]]>
properties文件的写操作http://www.blogjava.net/zhyiwww/archive/2007/08/02/133960.htmlzhyiwwwzhyiwwwthu, 02 aug 2007 03:26:00 gmthttp://www.blogjava.net/zhyiwww/archive/2007/08/02/133960.htmlhttp://www.blogjava.net/zhyiwww/comments/133960.htmlhttp://www.blogjava.net/zhyiwww/archive/2007/08/02/133960.html#feedback0http://www.blogjava.net/zhyiwww/comments/commentrss/133960.htmlhttp://www.blogjava.net/zhyiwww/services/trackbacks/133960.html但是,有的时候,我们可能也需要动态的更新配置,那么怎么来实现对properties配置文件的更新操作呢.
这个问题其实很简单,我们先看读操作:
properties p;
        try {
            p = propertiesreader
                    .readproperties("org/zy/common/parse/util/config.properties");
先载入配置文件,
string javahome = p.getproperty("java_home"));
通过getproperty()方法和关键字来实现属性的检索和返回.
那么,如何写?
多的时候我们知道,我们首先要读我们的配置文件流,那么写的时候,我们也要先得到一个写文件流.
由于是文本文件,所以我们使用filewriter.
string path =p.getclass().getresource("/org/zy/common/parse/util/config.properties").getpath();
writer w=new filewriter(path);
此时,我们已经准备好了,要把更新的属性写到哪里,那么,如何写?
有的时候,可能你是要更新某个属性,有的时候,可能你要添加一个属性.
可能你会使用w.write()方法来实现写操作,没有问题,但是,你以前的配置就完全没有了,如果想保留的话,就只有完全写一个新的文件.这中方法,对于更新某个属性的值来说就稍微的麻烦一点.当然,可以用正则表达式来实现.
其实properties本身也给我们提供了方法.

p.setproperty("bb", "bb update string");
            p.store(w,"bb");       
            w.close();
我们可以读属性,就可以设置属性.
setproperty()方法就可以实现.
但是此时的更新只是在内存中,并没有写如文件.要写入文件的话,就要调用store()方法.此时,我们关闭输出流的话,数据已经持久化到了文件.
setproperty()中,如果你的属性是文件里面没有的属性,那么,系统会进行追加操行,如果你的属性,在系统中已经存在,那么系统就会进行更新操作.
例如:
你的配置文件是:
a=a
b=b
c=c
那么,如果你
p.setproperty("d","d");
那么,结果就是:
a=a
b=b
c=c
d=d
如果你执行
p.setproperty("a","d");
那么,结果就是:
a=d
b=b
c=c



zhyiwww 2007-08-02 11:26
]]>
java中实现图片裁剪http://www.blogjava.net/zhyiwww/archive/2007/01/30/96767.htmlzhyiwwwzhyiwwwtue, 30 jan 2007 09:41:00 gmthttp://www.blogjava.net/zhyiwww/archive/2007/01/30/96767.htmlhttp://www.blogjava.net/zhyiwww/comments/96767.htmlhttp://www.blogjava.net/zhyiwww/archive/2007/01/30/96767.html#feedback7http://www.blogjava.net/zhyiwww/comments/commentrss/96767.htmlhttp://www.blogjava.net/zhyiwww/services/trackbacks/96767.html阅读全文

zhyiwww 2007-01-30 17:41
]]>
xpath study(转载)http://www.blogjava.net/zhyiwww/archive/2006/10/24/77040.htmlzhyiwwwzhyiwwwtue, 24 oct 2006 09:57:00 gmthttp://www.blogjava.net/zhyiwww/archive/2006/10/24/77040.htmlhttp://www.blogjava.net/zhyiwww/comments/77040.htmlhttp://www.blogjava.net/zhyiwww/archive/2006/10/24/77040.html#feedback0http://www.blogjava.net/zhyiwww/comments/commentrss/77040.htmlhttp://www.blogjava.net/zhyiwww/services/trackbacks/77040.html

xpath is a language for finding information in an xml document. xpath is used to navigate through elements and attributes in an xml document.
what you should already know
before you continue you should have a basic understanding of the following:
  • html / xhtml
  • xml / xml namespaces

if you want to study these subjects first, find the tutorials on our home page.
what is xpath?
  • xpath is a syntax for defining parts of an xml document
  • xpath uses path expressions to navigate in xml documents
  • xpath contains a library of standard functions
  • xpath is a major element in xslt
  • xpath is a w3c standard
xpath path expressions
xpath uses path expressions to select nodes or node-sets in an xml document. these path expressions look very much like the expressions you see when you work with a traditional computer file system.
xpath standard functions
xpath includes over 100 built-in functions. there are functions for string values, numeric values, date and time comparison, node and qname manipulation, sequence manipulation, boolean values, and more.
xpath is used in xslt
xpath is a major element in the xslt standard. without xpath knowledge you will not be able to create xslt documents.
you can read more about xslt in our xslt tutorial.
xquery and xpointer are both built on xpath expressions. xquery 1.0 and xpath 2.0 share the same data model and support the same functions and operators.
you can read more about xquery in our xquery tutorial.
xpath is a w3c standard
xpath became a w3c recommendation 16. november 1999.
xpath was designed to be used by xslt, xpointer and other xml parsing software.
you can read more about the xpath standard in our w3c tutorial. xpath nodes

in xpath, there are seven kinds of nodes: element, attribute, text, namespace, processing-instruction, comment, and document (root) nodes.
xpath terminology nodes
in xpath, there are seven kinds of nodes: element, attribute, text, namespace, processing-instruction, comment, and document (root) nodes. xml documents are treated as trees of nodes. the root of the tree is called the document node (or root node).
look at the following xml document:




  <br />  <author>j k. rowling</author> <pre></pre><br />  <year>2005</year><pre></pre><br />  <price>29.99</price><pre></pre><br /></book><pre></pre><br /></bookstore><pre></pre></td></tr></tbody></table><br />example of nodes in the xml document above: <br /><table class="msonormaltable" border="1"><tbody><tr><td><br /><bookstore>  (document node)<pre></pre><br /><author>j k. rowling</author>  (element node)<pre></pre><br />></td></tr></tbody></table>atomic values <br />atomic values are nodes with no children or parent. <br />example of atomic values: <br /><table class="msonormaltable" border="1"><tbody><tr><td><br />j k. rowling<pre></pre><br />"en"<pre></pre></td></tr></tbody></table>items <br />items are atomic values or nodes. <div class="msonormal" align="center"></div>relationship of nodes parent <br />each element and attribute has one parent. <br />in the following example; the book element is the parent of the title, author, year, and price: <br /><table class="msonormaltable" border="1"><tbody><tr><td><br /><book><pre></pre><br />  <title>harry potter

  j k. rowling

  2005

  29.99

children
element nodes may have zero, one or more children.
in the following example; the title, author, year, and price elements are all children of the book element:


  harry potter

  j k. rowling

  2005

  29.99

siblings
nodes that have the same parent.
in the following example; the title, author, year, and price elements are all siblings:


  harry potter

  j k. rowling

  2005

  29.99

ancestors
a node's parent, parent's parent, etc.
in the following example; the ancestors of the title element are the book element and the bookstore element:



  harry potter

  j k. rowling

  2005

  29.99


descendants
a node's children, children's children, etc.
in the following example; descendants of the bookstore element are the book, title, author, year, and price elements:



  harry potter

  j k. rowling

  2005

  29.99


xpath syntax

xpath uses path expressions to select nodes or node-sets in an xml document. the node is selected by following a path or steps.
the xml example document
we will use the following xml document in the examples below.




  <br />  <price>29.99</price><pre></pre><br /></book><pre></pre><br /><book><pre></pre><br />  <title ><br />  <price>39.95</price><pre></pre><br /></book><pre></pre><br /></bookstore><pre></pre></td></tr></tbody></table><br />  <div class="msonormal" align="center"></div>selecting nodes <br />xpath uses path expressions to select nodes in an xml document. the node is selected by following a path or steps. the most useful path expressions are listed below: <br /><table class="msonormaltable" border="1"><tbody><tr><td><br /><b>expression</b></td><td valign="top"><br /><b>description</b></td></tr><tr><td valign="top"><br /><em>nodename</em></td><td valign="top"><br />selects all child nodes of the node</td></tr><tr><td valign="top"><br />/</td><td valign="top"><br />selects from the root node</td></tr><tr><td valign="top"><br />//</td><td valign="top"><br />selects nodes in the document from the current node that match the selection no matter where they are </td></tr><tr><td valign="top"><br />.</td><td valign="top"><br />selects the current node</td></tr><tr><td valign="top"><br />..</td><td valign="top"><br />selects the parent of the current node</td></tr><tr><td valign="top"><br />@</td><td valign="top"><br />selects attributes</td></tr></tbody></table>examples <br />in the table below we have listed some path expressions and the result of the expressions: <br /><table class="msonormaltable" border="1"><tbody><tr><td><br /><b>path expression</b></td><td valign="top"><br /><b>result</b></td></tr><tr><td valign="top"><br />bookstore</td><td valign="top"><br />selects all the child nodes of the bookstore element</td></tr><tr><td valign="top"><br />/bookstore</td><td valign="top"><br />selects the root element bookstore <br /><b>note:</b> if the path starts with a slash ( / ) it always represents an absolute path to an element!</td></tr><tr><td valign="top"><br />bookstore/book</td><td valign="top"><br />selects all book elements that are children of bookstore</td></tr><tr><td valign="top"><br />//book</td><td valign="top"><br />selects all book elements no matter where they are in the document</td></tr><tr><td valign="top"><br />bookstore//book</td><td valign="top"><br />selects all book elements that are descendant of the bookstore element, no matter where they are under the bookstore element</td></tr><tr><td valign="top"><br />//@lang</td><td valign="top"><br />selects all attributes that are named lang</td></tr></tbody></table><br />  <div class="msonormal" align="center"></div>predicates <br />predicates are used to find a specific node or a node that contains a specific value. <br />predicates are always embedded in square brackets. examples <br />in the table below we have listed some path expressions with predicates and the result of the expressions: <br /><table class="msonormaltable" border="1"><tbody><tr><td><br /><b>path expression</b></td><td valign="top"><br /><b>result</b></td></tr><tr><td valign="top"><br />/bookstore/book[1] </td><td valign="top"><br />selects the first book element that is the child of the bookstore element</td></tr><tr><td valign="top"><br />/bookstore/book[last()]</td><td valign="top"><br />selects the last book element that is the child of the bookstore element</td></tr><tr><td valign="top"><br />/bookstore/book[last()-1]</td><td valign="top"><br />selects the last but one book element that is the child of the bookstore element</td></tr><tr><td valign="top"><br />/bookstore/book[position()<3]</td><td valign="top"><br />selects the first two book elements that are children of the bookstore element</td></tr><tr><td valign="top"><br />//title[@lang]</td><td valign="top"><br />selects all the title elements that have an attribute named lang</td></tr><tr><td valign="top"><br />//title[@> </td><td valign="top"><br />selects all the title elements that have an attribute named lang with a value of 'eng'</td></tr><tr><td valign="top"><br />/bookstore/book[price>35.00]</td><td valign="top"><br />selects all the book elements of the bookstore element that have a price element with a value greater than 35.00</td></tr><tr><td valign="top"><br />/bookstore/book[price>35.00]/title</td><td valign="top"><br />selects all the title elements of the book elements of the bookstore element that have a price element with a value greater than 35.00</td></tr></tbody></table><br />  <div class="msonormal" align="center"></div>selecting unknown nodes <br />xpath wildcards can be used to select unknown xml elements. <br /><table class="msonormaltable" border="1"><tbody><tr><td><br /><b>wildcard</b></td><td valign="top"><br /><b>description</b></td></tr><tr><td valign="top"><br />*</td><td valign="top"><br />matches any element node</td></tr><tr><td valign="top"><br />@*</td><td valign="top"><br />matches any attribute node</td></tr><tr><td valign="top"><br />node()</td><td valign="top"><br />matches any node of any kind</td></tr></tbody></table>examples <br />in the table below we have listed some path expressions and the result of the expressions: <br /><table class="msonormaltable" border="1"><tbody><tr><td><br /><b>path expression</b></td><td valign="top"><br /><b>result</b></td></tr><tr><td valign="top"><br />/bookstore/*</td><td valign="top"><br />selects all the child nodes of the bookstore element</td></tr><tr><td valign="top"><br />//*</td><td valign="top"><br />selects all elements in the document</td></tr><tr><td valign="top"><br />//title[@*]</td><td valign="top"><br />selects all title elements which have any attribute</td></tr></tbody></table><br />  <div class="msonormal" align="center"></div>selecting several paths <br />by using the | operator in an xpath expression you can select several paths. examples <br />in the table below we have listed some path expressions and the result of the expressions: <br /><table class="msonormaltable" border="1"><tbody><tr><td><br /><b>path expression</b></td><td valign="top"><br /><b>result</b></td></tr><tr><td valign="top"><br />//book/title | //book/price</td><td valign="top"><br />selects all the title and price elements of all book elements</td></tr><tr><td valign="top"><br />//title | //price</td><td valign="top"><br />selects all the title and price elements in the document</td></tr><tr><td valign="top"><br />/bookstore/book/title | //price</td><td valign="top"><br />selects all the title elements of the book element of the bookstore element and all the price elements in the document</td></tr></tbody></table>xpath axes <br /><v:shape id="_x0000_i1060"><v:imagedata o:href="http://www.w3schools.com/images/btn_previous.gif" src="file:///c:\docume~1\zhangy~1.cgo\locals~1\temp\msohtml1\04\clip_image001.gif"></v:imagedata></v:shape><v:shape id="_x0000_i1061"><v:imagedata o:href="http://www.w3schools.com/images/btn_next.gif" src="file:///c:\docume~1\zhangy~1.cgo\locals~1\temp\msohtml1\04\clip_image002.gif"></v:imagedata></v:shape><div class="msonormal" align="center"></div>the xml example document <br />we will use the following xml document in the examples below. <br /><table class="msonormaltable" border="1"><tbody><tr><td><br /><?xml version="1.0" encoding="iso-8859-1"?><pre></pre><br /><bookstore><pre></pre><br /><book><pre></pre><br />  <title ><br />  <price>29.99</price><pre></pre><br /></book><pre></pre><br /><book><pre></pre><br />  <title ><br />  <price>39.95</price><pre></pre><br /></book><pre></pre><br /></bookstore><pre></pre></td></tr></tbody></table><br />  <div class="msonormal" align="center"></div>xpath axes <br />an axis defines a node-set relative to the current node. <br /><table class="msonormaltable" border="1"><tbody><tr><td><br /><b>axisname</b></td><td><br /><b>result</b></td></tr><tr><td valign="top"><br />ancestor</td><td valign="top"><br />selects all ancestors (parent, grandparent, etc.) of the current node</td></tr><tr><td valign="top"><br />ancestor-or-self</td><td valign="top"><br />selects all ancestors (parent, grandparent, etc.) of the current node and the current node itself</td></tr><tr><td valign="top"><br />attribute</td><td valign="top"><br />selects all attributes of the current node</td></tr><tr><td valign="top"><br />child</td><td valign="top"><br />selects all children of the current node</td></tr><tr><td valign="top"><br />descendant</td><td valign="top"><br />selects all descendants (children, grandchildren, etc.) of the current node</td></tr><tr><td valign="top"><br />descendant-or-self</td><td valign="top"><br />selects all descendants (children, grandchildren, etc.) of the current node and the current node itself</td></tr><tr><td valign="top"><br />following</td><td valign="top"><br />selects everything in the document after the closing tag of the current node</td></tr><tr><td valign="top"><br />following-sibling</td><td valign="top"><br />selects all siblings after the current node</td></tr><tr><td valign="top"><br />namespace</td><td valign="top"><br />selects all namespace nodes of the current node</td></tr><tr><td valign="top"><br />parent</td><td valign="top"><br />selects the parent of the current node</td></tr><tr><td valign="top"><br />preceding</td><td valign="top"><br />selects everything in the document that is before the start tag of the current node</td></tr><tr><td valign="top"><br />preceding-sibling</td><td valign="top"><br />selects all siblings before the current node</td></tr><tr><td valign="top"><br />self</td><td valign="top"><br />selects the current node</td></tr></tbody></table><br />  <div class="msonormal" align="center"></div>location path expression <br />a location path can be absolute or relative. <br />an absolute location path starts with a slash ( / ) and a relative location path does not. in both cases the location path consists of one or more steps, each separated by a slash: <br /><table class="msonormaltable" border="1"><tbody><tr><td valign="top"><br />an absolute location path:<pre></pre><br />/step/step/...<pre></pre><br />a relative location path:<pre></pre><br />step/step/...<pre></pre></td></tr></tbody></table><br />each step is evaluated against the nodes in the current node-set. <br />a step consists of: <ul><li>an axis (defines the tree-relationship between the selected nodes and the current node) </li><li>a node-test (identifies a node within an axis) </li><li>zero or more predicates (to further refine the selected node-set) </li></ul><br />the syntax for a location step is: <br /><table class="msonormaltable" border="1"><tbody><tr><td valign="top"><br />axisname::nodetest[predicate]<pre></pre></td></tr></tbody></table>examples <br /><table class="msonormaltable" border="1"><tbody><tr><td><br /><b>example</b></td><td><br /><b>result</b></td></tr><tr><td valign="top"><br />child::book</td><td valign="top"><br />selects all book nodes that are children of the current node</td></tr><tr><td valign="top"><br />attribute::lang</td><td valign="top"><br />selects the lang attribute of the current node</td></tr><tr><td valign="top"><br />child::*</td><td valign="top"><br />selects all children of the current node</td></tr><tr><td valign="top"><br />attribute::*</td><td valign="top"><br />selects all attributes of the current node</td></tr><tr><td valign="top"><br />child::text()</td><td valign="top"><br />selects all text child nodes of the current node</td></tr><tr><td valign="top"><br />child::node()</td><td valign="top"><br />selects all child nodes of the current node</td></tr><tr><td valign="top"><br />descendant::book</td><td valign="top"><br />selects all book descendants of the current node</td></tr><tr><td valign="top"><br />ancestor::book</td><td valign="top"><br />selects all book ancestors of the current node</td></tr><tr><td valign="top"><br />ancestor-or-self::book</td><td valign="top"><br />selects all book ancestors of the current node - and the current as well if it is a book node</td></tr><tr><td valign="top"><br />child::*/child::price</td><td valign="top"><br />selects all price grandchildren of the current node</td></tr></tbody></table>xpath operators <br /><v:shape id="_x0000_i1062"><v:imagedata o:href="http://www.w3schools.com/images/btn_previous.gif" src="file:///c:\docume~1\zhangy~1.cgo\locals~1\temp\msohtml1\04\clip_image001.gif"></v:imagedata></v:shape><v:shape id="_x0000_i1063"><v:imagedata o:href="http://www.w3schools.com/images/btn_next.gif" src="file:///c:\docume~1\zhangy~1.cgo\locals~1\temp\msohtml1\04\clip_image002.gif"></v:imagedata></v:shape><div class="msonormal" align="center"></div><br /><b>an xpath expression returns either a node-set, a string, a boolean, or a number.</b><div class="msonormal" align="center"><b></b></div>xpath operators <br />below is a list of the operators that can be used in xpath expressions: <br /><table class="msonormaltable" border="1"><tbody><tr><td><br /><b>operator</b></td><td><br /><b>description</b></td><td><br /><b>example</b></td><td><br /><b>return value</b></td></tr><tr><td valign="top"><br />|</td><td valign="top"><br />computes two node-sets</td><td valign="top"><br />//book | //cd</td><td valign="top"><br />returns a node-set with all book and cd elements</td></tr><tr><td valign="top"><br /> </td><td valign="top"><br />addition</td><td valign="top"><br />6 4</td><td valign="top"><br />10</td></tr><tr><td valign="top"><br />-</td><td valign="top"><br />subtraction</td><td valign="top"><br />6 - 4</td><td valign="top"><br />2</td></tr><tr><td valign="top"><br />*</td><td valign="top"><br />multiplication</td><td valign="top"><br />6 * 4</td><td valign="top"><br />24</td></tr><tr><td valign="top"><br />div</td><td valign="top"><br />division</td><td valign="top"><br />8 div 4</td><td valign="top"><br />2</td></tr><tr><td valign="top"><br />=</td><td valign="top"><br />equal</td><td valign="top"><br />price=9.80</td><td valign="top"><br />true if price is 9.80<b>false if price is 9.90</b></td></tr><tr><td valign="top"><br />!=</td><td valign="top"><br />not equal</td><td valign="top"><br />price!=9.80</td><td valign="top"><br />true if price is 9.90<b>false if price is 9.80</b></td></tr><tr><td valign="top"><br />< </td><td valign="top"><br />less than</td><td valign="top"><br />price<9.80</td><td valign="top"><br />true if price is 9.00<b>false if price is 9.80</b></td></tr><tr><td valign="top"><br /><=</td><td valign="top"><br />less than or equal to</td><td valign="top"><br />price<=9.80</td><td valign="top"><br />true if price is 9.00<b>false if price is 9.90</b></td></tr><tr><td valign="top"><br />> </td><td valign="top"><br />greater than</td><td valign="top"><br />price>9.80</td><td valign="top"><br />true if price is 9.90<b>false if price is 9.80</b></td></tr><tr><td valign="top"><br />>=</td><td valign="top"><br />greater than or equal to</td><td valign="top"><br />price>=9.80</td><td valign="top"><br />true if price is 9.90<b>false if price is 9.70</b></td></tr><tr><td valign="top"><br />or</td><td valign="top"><br />or</td><td valign="top"><br />price=9.80 or price=9.70</td><td valign="top"><br />true if price is 9.80<b>false if price is 9.50</b></td></tr><tr><td valign="top"><br />and</td><td valign="top"><br />and </td><td valign="top"><br />price>9.00 and price<9.90</td><td valign="top"><br />true if price is 9.80<b>false if price is 8.50</b></td></tr><tr><td valign="top"><br />mod</td><td valign="top"><br />modulus (division remainder)</td><td valign="top"><br />5 mod 2</td><td valign="top"><br />1</td></tr></tbody></table>xpath examples <br /><v:shape id="_x0000_i1064"><v:imagedata o:href="http://www.w3schools.com/images/btn_previous.gif" src="file:///c:\docume~1\zhangy~1.cgo\locals~1\temp\msohtml1\04\clip_image001.gif"></v:imagedata></v:shape><v:shape id="_x0000_i1065"><v:imagedata o:href="http://www.w3schools.com/images/btn_next.gif" src="file:///c:\docume~1\zhangy~1.cgo\locals~1\temp\msohtml1\04\clip_image002.gif"></v:imagedata></v:shape><div class="msonormal" align="center"></div><br /><b>let's try to learn some basic xpath syntax by looking at some examples.</b><div class="msonormal" align="center"><b></b></div>the xml example document <br />we will use the following xml document in the examples below. <br />"books.xml": <br /><table class="msonormaltable" border="1"><tbody><tr><td><br /><?xml version="1.0" encoding="iso-8859-1"?><pre></pre><br /><bookstore><pre></pre><br /><book category="cooking"><pre></pre><br />  <title ><br />  <author>giada de laurentiis</author><pre></pre><br />  <year>2005</year><pre></pre><br />  <price>30.00</price><pre></pre><br /></book><pre></pre><br /><book category="children"><pre></pre><br />  <title ><br />  <author>j k. rowling</author><pre></pre><br />  <year>2005</year><pre></pre><br />  <price>29.99</price><pre></pre><br /></book><pre></pre><br /><book category="web"><pre></pre><br />  <title ><br />  <author>james mcgovern</author><pre></pre><br />  <author>per bothner</author><pre></pre><br />  <author>kurt cagle</author><pre></pre><br />  <author>james linn</author><pre></pre><br />  <author>vaidyanathan nagarajan</author><pre></pre><br />  <year>2003</year><pre></pre><br />  <price>49.99</price><pre></pre><br /></book><pre></pre><br /><book category="web"><pre></pre><br />  <title ><br />  <author>erik t. ray</author><pre></pre><br />  <year>2003</year><pre></pre><br />  <price>39.95</price><pre></pre><br /></book><pre></pre><br /></bookstore><pre></pre></td></tr></tbody></table><br />view the "books.xml" file in your browser. <div class="msonormal" align="center"></div>selecting nodes <br />we will use the microsoft xmldom object to load the xml document and the selectnodes() function to select nodes from the xml document: <br /><table class="msonormaltable" border="1"><tbody><tr><td><br />set xmldoc=createobject("microsoft.xmldom")<pre></pre><br />xmldoc.async="false"<pre></pre><br />xmldoc.load("books.xml")<pre></pre><br />xmldoc.selectnodes(<em>path expression</em>)<pre></pre></td></tr></tbody></table><br />  <div class="msonormal" align="center"></div>select all book nodes <br />the following example selects all the book nodes under the bookstore element: <br /><table class="msonormaltable" border="1"><tbody><tr><td><br />xmldoc.selectnodes("/bookstore/book")<pre></pre></td></tr></tbody></table><br />if you have ie 5 or higher you can try it yourself. <div class="msonormal" align="center"></div>select the first book node <br />the following example selects only the first book node under the bookstore element: <br /><table class="msonormaltable" border="1"><tbody><tr><td><br />xmldoc.selectnodes("/bookstore/book[0]")<pre></pre></td></tr></tbody></table><br />if you have ie 5 or higher you can try it yourself. <br /><b>note:</b> ie 5 and 6 has implemented that [0] should be the first node, but according to the w3c standard it should have been [1]!! <br /><b>note:</b> this is corrected in ie 6 sp2! <div class="msonormal" align="center"></div>select the prices <br />the following example selects the text from all the price nodes: <br /><table class="msonormaltable" border="1"><tbody><tr><td><br />xmldoc.selectnodes("/bookstore/book/price/text()") <pre></pre></td></tr></tbody></table><br />if you have ie 5 or higher you can try it yourself. <div class="msonormal" align="center"></div>selecting price nodes with price>35 <br />the following example selects all the price nodes with a price higher than 35: <br /><table class="msonormaltable" border="1"><tbody><tr><td><br />xmldoc.selectnodes("/bookstore/book[price>35]/price") <pre></pre></td></tr></tbody></table><br />if you have ie 5 or higher you can try it yourself. <div class="msonormal" align="center"></div>selecting title nodes with price>35 <br />the following example selects all the title nodes with a price higher than 35: <br /><table class="msonormaltable" border="1"><tbody><tr><td><br />xmldoc.selectnodes("/bookstore/book[price>35]/title") <pre></pre></td></tr></tbody></table><br />if you have ie 5 or higher you can try it yourself. <br />  <br />  <br />  <br />  <br /> <img src ="http://www.blogjava.net/zhyiwww/aggbug/77040.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/zhyiwww/" target="_blank">zhyiwww</a> 2006-10-24 17:57 <a href="http://www.blogjava.net/zhyiwww/archive/2006/10/24/77040.html#feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>classloader分析(转载)http://www.blogjava.net/zhyiwww/archive/2006/10/20/76406.htmlzhyiwwwzhyiwwwfri, 20 oct 2006 08:23:00 gmthttp://www.blogjava.net/zhyiwww/archive/2006/10/20/76406.htmlhttp://www.blogjava.net/zhyiwww/comments/76406.htmlhttp://www.blogjava.net/zhyiwww/archive/2006/10/20/76406.html#feedback0http://www.blogjava.net/zhyiwww/comments/commentrss/76406.htmlhttp://www.blogjava.net/zhyiwww/services/trackbacks/76406.html阅读全文

zhyiwww 2006-10-20 16:23
]]>
如何将字符串转换成unicode编码http://www.blogjava.net/zhyiwww/archive/2006/07/11/57686.htmlzhyiwwwzhyiwwwtue, 11 jul 2006 09:35:00 gmthttp://www.blogjava.net/zhyiwww/archive/2006/07/11/57686.htmlhttp://www.blogjava.net/zhyiwww/comments/57686.htmlhttp://www.blogjava.net/zhyiwww/archive/2006/07/11/57686.html#feedback2http://www.blogjava.net/zhyiwww/comments/commentrss/57686.htmlhttp://www.blogjava.net/zhyiwww/services/trackbacks/57686.html阅读全文

zhyiwww 2006-07-11 17:35
]]>
system.getproperty()参数大全http://www.blogjava.net/zhyiwww/archive/2006/06/02/50024.htmlzhyiwwwzhyiwwwfri, 02 jun 2006 10:39:00 gmthttp://www.blogjava.net/zhyiwww/archive/2006/06/02/50024.htmlhttp://www.blogjava.net/zhyiwww/comments/50024.htmlhttp://www.blogjava.net/zhyiwww/archive/2006/06/02/50024.html#feedback0http://www.blogjava.net/zhyiwww/comments/commentrss/50024.htmlhttp://www.blogjava.net/zhyiwww/services/trackbacks/50024.html system.getproperty()参数大全

java.version            java runtime environment version
java.vendor            java runtime environment vendor
java.vendor.url            java vendor url
java.home            java installation directory
java.vm.specification.version                    java virtual machine specification version
java.vm.specification.vendor                    java virtual machine specification vendor
java.vm.specification.name                    java virtual machine specification name
java.vm.version            java virtual machine implementation version
java.vm.vendor            java virtual machine implementation vendor
java.vm.name            java virtual machine implementation name
java.specification.version                java runtime environment specification version
java.specification.vendor             java runtime environment specification vendor
java.specification.name        java runtime environment specification name
java.class.version                        java class format version number
java.class.path                  java class path
java.library.path                        list of paths to search when loading libraries
java.io.tmpdir                default temp file path
java.compiler            name of jit compiler to use
java.ext.dirs            path of extension directory or directories
os.name                operating system name
os.arch                operating system architecture
os.version            operating system version
file.separator            file separator ("/" on unix)
path.separator            path separator (":" on unix)
line.separator            line separator ("\n" on unix)
user.name            user's account name
user.home            user's home directory
user.dir                user's current working directory


zhyiwww 2006-06-02 18:39
]]>
去掉一个字符串数组中的重复项http://www.blogjava.net/zhyiwww/archive/2006/04/13/40810.htmlzhyiwwwzhyiwwwthu, 13 apr 2006 01:38:00 gmthttp://www.blogjava.net/zhyiwww/archive/2006/04/13/40810.htmlhttp://www.blogjava.net/zhyiwww/comments/40810.htmlhttp://www.blogjava.net/zhyiwww/archive/2006/04/13/40810.html#feedback2http://www.blogjava.net/zhyiwww/comments/commentrss/40810.htmlhttp://www.blogjava.net/zhyiwww/services/trackbacks/40810.html转载 自


1、去掉一个字符串数组中的重复项:(2006.04.11.)
原来采用的方法:
 1 string[] rid = request.getparametervalues("noattrid");
 2 //需要用一个临时的变量把过滤后的结果这个存起来
 3 string[] ridfiltered = new string[rid.length];
 4         int index = 0;
 5         for (int i = 0; i < rid.length; i) {
 6             if (!this.isexiststring(ridfiltered, rid[i])&&!rid[i].equals("")) {
 7                 ridfiltered[index= rid[i];
 8             }
 9         }
10 
11 //还需要用一个方法来判断在结果中是否存在此项,如下
12  /**
13      * 用于查找某个字符串是否在一个字符串数组中
14      * @param dest string[]
15      * @param str string
16      * return boolean
17      */
18 
19     public boolean isexiststring(string[] dest, string str) {
20         boolean flag = false;
21         for (int i = 0; i < dest.length; i) {
22             if (str.equals(dest[i])) {
23                 flag = true;
24             }
25         }
26         return flag;
27     }

看看,要多麻烦有多麻烦,来看看新方法:
1 string[] s = request.getparametervalues("noattrid");
2 list list = arrays.aslist(s);
3 set set = new hashset(list);
4 rid=(string [])set.toarray();
简简单单的三行代码即可搞定,无论是从程序的可读性、优雅性还是效率方面都有很好的提升。
扩展:你同时还可以运用上面的方法还判断三个字符串是否相等(可进一步扩展至多个,但是似乎不太有实际意义),例程如下:
1 string[] s = {"one""two""two"};
2 list list = arrays.aslist(s);
3 set set = new hashset(list);
4 system.out.println(list.size() == set.size()); // false


zhyiwww 2006-04-13 09:38
]]>
vector和arraylist的区别http://www.blogjava.net/zhyiwww/archive/2006/04/12/40554.htmlzhyiwwwzhyiwwwwed, 12 apr 2006 01:09:00 gmthttp://www.blogjava.net/zhyiwww/archive/2006/04/12/40554.htmlhttp://www.blogjava.net/zhyiwww/comments/40554.htmlhttp://www.blogjava.net/zhyiwww/archive/2006/04/12/40554.html#feedback0http://www.blogjava.net/zhyiwww/comments/commentrss/40554.htmlhttp://www.blogjava.net/zhyiwww/services/trackbacks/40554.html vector arraylist 的区别

       (这篇文章是从网上摘录,地址忘了,如涉及凯发k8网页登录的版权请和我联系zhyiwww@163.com)

1.        vector 是线程同步的,所以它也是线程安全的,而 arraylist 是线程异步的,是不安全的。如果不考虑到线程的安全因素,一般用 arraylist 效率比较高。

 

2.        如果集合中的元素的数目大于目前集合数组的长度时, vector 增长率为目前数组长度的 100%, arraylist 增长率为目前数组长度的 50%. 如过在集合中使用数据量比较大的数据,用 vector 有一定的优势。

 

3.         如果查找一个指定位置的数据, vector arraylist 使用的时间是相同的,都是 0(1), 这个时候使用 vector arraylist 都可以。而如果移动一个指定位置的数据花费的时间为 0(n-i)n 为总长度,这个时候就应该考虑到使用 linklist, 因为它移动一个指定位置的数据所花费的时间为 0(1), 而查询一个指定位置的数据时花费的时间为 0(i)

 

 

另:

如果你注意到对vector和list的所开始支持的java版本你就应该可以找到答案了。java对vector的支持since 1.0;对list则是since 1.2。这两个版本之间,sun对于java api做了很多的改动,其中的一个refactoring就是提出了所谓的collection framework,list就是在那个时候被introduced,它完全符合1.2版本的collection framework,而vector则是在colleciton framework出现之前就已经存在了,但java api并没有将vector变成deprecated,主要是backward compatiable的问题,最终jcp将vector做了refactoring的处理,让它符合所定制的collection framework了事。另外,hashtable和hashmap的区别是同样的道理。

 

结论:

尽量采用 list hashmap rather than vector&hashtable

 

 



zhyiwww 2006-04-12 09:09
]]>
深入理解abstract class和interfacehttp://www.blogjava.net/zhyiwww/archive/2006/04/05/39444.htmlzhyiwwwzhyiwwwwed, 05 apr 2006 10:03:00 gmthttp://www.blogjava.net/zhyiwww/archive/2006/04/05/39444.htmlhttp://www.blogjava.net/zhyiwww/comments/39444.htmlhttp://www.blogjava.net/zhyiwww/archive/2006/04/05/39444.html#feedback1http://www.blogjava.net/zhyiwww/comments/commentrss/39444.htmlhttp://www.blogjava.net/zhyiwww/services/trackbacks/39444.html转载自

abstract class和interface是java语言中对于抽象类定义进行支持的两种机制,正是由于这两种机制的存在,才赋予了java强大的面向对象能力。abstract class和interface之间在对于抽象类定义的支持方面具有很大的相似性,甚至可以相互替换,因此很多开发者在进行抽象类定义时对于abstract class和interface的选择显得比较随意。其实,两者之间还是有很大的区别的,对于它们的选择甚至反映出对于问题领域本质的理解、对于设计意图的理解是否正确、合理。本文将对它们之间的区别进行一番剖析,试图给开发者提供一个在二者之间进行选择的依据。

理解抽象类

abstract class和interface在java语言中都是用来进行抽象类(本文中的抽象类并非从abstract class翻译而来,它表示的是一个抽象体,而abstract class为java语言中用于定义抽象类的一种方法,请读者注意区分)定义的,那么什么是抽象类,使用抽象类能为我们带来什么好处呢?

在面向对象的概念中,我们知道所有的对象都是通过类来描绘的,但是反过来却不是这样。并不是所有的类都是用来描绘对象的,如果一个类中没有包含足够的信息来描绘一个具体的对象,这样的类就是抽象类。抽象类往往用来表征我们在对问题领域进行分析、设计中得出的抽象概念,是对一系列看上去不同,但是本质上相同的具体概念的抽象。比如:如果我们进行一个图形编辑软件的开发,就会发现问题领域存在着圆、三角形这样一些具体概念,它们是不同的,但是它们又都属于形状这样一个概念,形状这个概念在问题领域是不存在的,它就是一个抽象概念。正是因为抽象的概念在问题领域没有对应的具体概念,所以用以表征抽象概念的抽象类是不能够实例化的。

在面向对象领域,抽象类主要用来进行类型隐藏。我们可以构造出一个固定的一组行为的抽象描述,但是这组行为却能够有任意个可能的具体实现方式。这个抽象描述就是抽象类,而这一组任意个可能的具体实现则表现为所有可能的派生类。模块可以操作一个抽象体。由于模块依赖于一个固定的抽象体,因此它可以是不允许修改的;同时,通过从这个抽象体派生,也可扩展此模块的行为功能。熟悉ocp的读者一定知道,为了能够实现面向对象设计的一个最核心的原则ocp(open-closed principle),抽象类是其中的关键所在。

从语法定义层面看abstract class和interface

在语法层面,java语言对于abstract class和interface给出了不同的定义方式,下面以定义一个名为demo的抽象类为例来说明这种不同。
使用abstract class的方式定义demo抽象类的方式如下:

abstract class demo {
abstract void method1();
abstract void method2();
…
}

使用interface的方式定义demo抽象类的方式如下:

interface demo {
void method1();
void method2();
…
}

在abstract class方式中,demo可以有自己的数据成员,也可以有非abstarct的成员方法,而在interface方式的实现中,demo只能够有静态的不能被修改的数据成员(也就是必须是static final的,不过在interface中一般不定义数据成员),所有的成员方法都是abstract的。从某种意义上说,interface是一种特殊形式的abstract class。

从编程的角度来看,abstract class和interface都可以用来实现"design by contract"的思想。但是在具体的使用上面还是有一些区别的。

首先,abstract class在java语言中表示的是一种继承关系,一个类只能使用一次继承关系。但是,一个类却可以实现多个interface。也许,这是java语言的设计者在考虑java对于多重继承的支持方面的一种折中考虑吧。

其次,在abstract class的定义中,我们可以赋予方法的默认行为。但是在interface的定义中,方法却不能拥有默认行为,为了绕过这个限制,必须使用委托,但是这会 增加一些复杂性,有时会造成很大的麻烦。

在抽象类中不能定义默认行为还存在另一个比较严重的问题,那就是可能会造成维护上的麻烦。因为如果后来想修改类的界面(一般通过abstract class或者interface来表示)以适应新的情况(比如,添加新的方法或者给已用的方法中添加新的参数)时,就会非常的麻烦,可能要花费很多的时间(对于派生类很多的情况,尤为如此)。但是如果界面是通过abstract class来实现的,那么可能就只需要修改定义在abstract class中的默认行为就可以了。

同样,如果不能在抽象类中定义默认行为,就会导致同样的方法实现出现在该抽象类的每一个派生类中,违反了"one rule,one place"原则,造成代码重复,同样不利于以后的维护。因此,在abstract class和interface间进行选择时要非常的小心。

从设计理念层面看abstract class和interface

上面主要从语法定义和编程的角度论述了abstract class和interface的区别,这些层面的区别是比较低层次的、非本质的。本小节将从另一个层面:abstract class和interface所反映出的设计理念,来分析一下二者的区别。作者认为,从这个层面进行分析才能理解二者概念的本质所在。

前面已经提到过,abstarct class在java语言中体现了一种继承关系,要想使得继承关系合理,父类和派生类之间必须存在"is a"关系,即父类和派生类在概念本质上应该是相同的(参考文献〔3〕中有关于"is a"关系的大篇幅深入的论述,有兴趣的读者可以参考)。对于interface 来说则不然,并不要求interface的实现者和interface定义在概念本质上是一致的,仅仅是实现了interface定义的契约而已。为了使论述便于理解,下面将通过一个简单的实例进行说明。

考虑这样一个例子,假设在我们的问题领域中有一个关于door的抽象概念,该door具有执行两个动作open和close,此时我们可以通过abstract class或者interface来定义一个表示该抽象概念的类型,定义方式分别如下所示:

使用abstract class方式定义door:

abstract class door {
abstract void open();
abstract void close();
}

使用interface方式定义door:

interface door {
void open();
void close();
}

其他具体的door类型可以extends使用abstract class方式定义的door或者implements使用interface方式定义的door。看起来好像使用abstract class和interface没有大的区别。

如果现在要求door还要具有报警的功能。我们该如何设计针对该例子的类结构呢(在本例中,主要是为了展示abstract class和interface反映在设计理念上的区别,其他方面无关的问题都做了简化或者忽略)?下面将罗列出可能的凯发天生赢家一触即发官网的解决方案,并从设计理念层面对这些不同的方案进行分析。

凯发天生赢家一触即发官网的解决方案一:

简单的在door的定义中增加一个alarm方法,如下:

abstract class door {
abstract void open();
abstract void close();
abstract void alarm();
}

或者

interface door {
void open();
void close();
void alarm();
}

那么具有报警功能的alarmdoor的定义方式如下:

class alarmdoor extends door {
void open() { … }
void close() { … }
void alarm() { … }
}

或者

class alarmdoor implements door {
void open() { … }
void close() { … }
void alarm() { … }
}

这种方法违反了面向对象设计中的一个核心原则isp(interface segregation priciple),在door的定义中把door概念本身固有的行为方法和另外一个概念"报警器"的行为方法混在了一起。这样引起的一个问题是那些仅仅依赖于door这个概念的模块会因为"报警器"这个概念的改变(比如:修改alarm方法的参数)而改变,反之依然。

凯发天生赢家一触即发官网的解决方案二:

既然open、close和alarm属于两个不同的概念,根据isp原则应该把它们分别定义在代表这两个概念的抽象类中。定义方式有:这两个概念都使用abstract class方式定义;两个概念都使用interface方式定义;一个概念使用abstract class方式定义,另一个概念使用interface方式定义。

显然,由于java语言不支持多重继承,所以两个概念都使用abstract class方式定义是不可行的。后面两种方式都是可行的,但是对于它们的选择却反映出对于问题领域中的概念本质的理解、对于设计意图的反映是否正确、合理。我们一一来分析、说明。

如果两个概念都使用interface方式来定义,那么就反映出两个问题:1、我们可能没有理解清楚问题领域,alarmdoor在概念本质上到底是door还是报警器?2、如果我们对于问题领域的理解没有问题,比如:我们通过对于问题领域的分析发现alarmdoor在概念本质上和door是一致的,那么我们在实现时就没有能够正确的揭示我们的设计意图,因为在这两个概念的定义上(均使用interface方式定义)反映不出上述含义。

如果我们对于问题领域的理解是:alarmdoor在概念本质上是door,同时它有具有报警的功能。我们该如何来设计、实现来明确的反映出我们的意思呢?前面已经说过,abstract class在java语言中表示一种继承关系,而继承关系在本质上是"is a"关系。所以对于door这个概念,我们应该使用abstarct class方式来定义。另外,alarmdoor又具有报警功能,说明它又能够完成报警概念中定义的行为,所以报警概念可以通过interface方式定义。如下所示:

abstract class door {
abstract void open();
abstract void close();
}
interface alarm {
void alarm();
}
class alarmdoor extends door implements alarm {
void open() { … }
void close() { … }
void alarm() { … }
}

这种实现方式基本上能够明确的反映出我们对于问题领域的理解,正确的揭示我们的设计意图。其实abstract class表示的是"is a"关系,interface表示的是"like a"关系,大家在选择时可以作为一个依据,当然这是建立在对问题领域的理解上的,比如:如果我们认为alarmdoor在概念本质上是报警器,同时又具有door的功能,那么上述的定义方式就要反过来了。

结论

abstract class和interface是java语言中的两种定义抽象类的方式,它们之间有很大的相似性。但是对于它们的选择却又往往反映出对于问题领域中的概念本质的理解、对于设计意图的反映是否正确、合理,因为它们表现了概念间的不同的关系(虽然都能够实现需求的功能)。这其实也是语言的一种的惯用法,希望读者朋友能够细细体会。



zhyiwww 2006-04-05 18:03
]]>
set中的元素为什么不允许重复http://www.blogjava.net/zhyiwww/archive/2006/03/30/38193.htmlzhyiwwwzhyiwwwthu, 30 mar 2006 01:41:00 gmthttp://www.blogjava.net/zhyiwww/archive/2006/03/30/38193.htmlhttp://www.blogjava.net/zhyiwww/comments/38193.htmlhttp://www.blogjava.net/zhyiwww/archive/2006/03/30/38193.html#feedback0http://www.blogjava.net/zhyiwww/comments/commentrss/38193.htmlhttp://www.blogjava.net/zhyiwww/services/trackbacks/38193.html set 中的元素为什么不允许重复

       凯发k8网页登录的版权所有,转载请声明出处 zhyiwww@163.com

 

为了弄清楚这个问题 , 我又看了一遍 collection 部分 , 并且看了些其中的源码 , 觉得对其中的实现又明白了一点 , 现在说出来和大家共享 .

我们先看一下 set 类的关系图:

hashset.png
现在我们就从
set 说起。

set 接口为我们提供了一个 add() 方法,以让我们添加元素。所以我们看一下在其实现类 hashset 中是如何实现的呢?

我们看 hashset 中的 add() 方法实现;

    public boolean add( e o ) {

              return  map.put(o, present)==null;

}

你可能回问怎么回出来 map 了呢?

map 又是一个什么变量呢?

我们来看 map 是在在哪定义的。原来,在 hashset 中定义了这样的两个变量:

    private transient hashmap map;

    private static final object present = new object();

我们再看一下上面的 add() 方法。

map.put(o, present)==null

实际执行的是 map 的方法,并且我们添加的对象是 map 中的 key,value 是执行的同一个对象 present.

因为map中的key是不允许重复的,所以set中的元素不能重复。

 

下面我们再看一下, map 又是如何保证其 key 不重复的呢?

 hashmap.png

现在我们看一下 map 中的 put() 方法的实现:

hashmap 实现了 map ,在 hashmap 中是这样实现的:

    public v put(k key, v value) {

      k k = masknull(key);

        int hash = hash(k);

        int i = indexfor(hash, table.length);

        for (entry e = table[i]; e != null; e = e.next) {

            if (e.hash == hash && eq(k, e.key)) {

                v oldvalue = e.value;

                e.value = value;

                e.recordaccess(this);

                return oldvalue;

            }

        }

 

        modcount ;

        addentry(hash, k, value, i);

        return null;

    }

我们我们按照方法的执行一步一步的来看一下,其实现的过程。

k k = masknull(key);

这一步是要判断当前的要添加的对象的 key 是否为空,如果为空的话,那么就生成一个新的对象作为其 key 。实现如下:

    static final object null_key = new object();

     * returns internal representation for key. use null_key if key is null.

    static t masknull(t key) {

        return key == null ? (t)null_key : key;

    }

之后

int hash = hash(k);

我们看一下 hash() 方法的实现:

    static int hash(object x) {

        int h = x.hashcode();

        h = ~(h << 9);

        h ^=  (h >>> 14);

        h =  (h << 4);

        h ^=  (h >>> 10);

        return h;

    }

这一步其实是要得到当前要添加对象的 hashcode, 方法中,首先通过 int h = x.hashcode() 取得了当前的要添加对象的 hashcode, 然后

        h = ~(h << 9);

        h ^=  (h >>> 14);

        h =  (h << 4);

        h ^=  (h >>> 10);

生成一个新的 hashcode.

接着执行的是

(从此处开始,我理解的比较肤浅,请看到此出的朋友多多指点)

int i = indexfor(hash, table.length);

这个方法是要 returns index for hash code h.

    static int indexfor(int h, int length) {

        return h & (length-1);

    }

      下面就要根据 hashmap 中的元素逐个的比较,看是否相同,如果不同就回添加一个新的元素。是通过循环判断来实现的。

        for (entry e = table[i]; e != null; e = e.next) {

            if (e.hash == hash && eq(k, e.key)) {

                v oldvalue = e.value;

                e.value = value;

                e.recordaccess(this);

这句我的理解是:在内存中的可以访问元素又多了一个。也就是说,添加之后,可以通过hashmap来访问此元素了。

                return oldvalue;

            }

        }

通过循环判断是否有完全相同的对象,包括 hashcode value 值。如果已经存在就返回其值,如果不存在就执行一下操作。

        modcount ;

        addentry(hash, k, value, i);

        return null;

对象不存在,首先修改 hashmap 的修改次数,即 modcount 1. 然后将对象添加到数组中。

    void addentry(int hash, k key, v value, int bucketindex) {

      entry e = table[bucketindex];

        table[bucketindex] = new entry(hash, key, value, e);

        if (size >= threshold)

            resize(2 * table.length);

}

仍然是数组,我们来看一下 , hashmap 中用来存放对象的数组的定义:

    transient entry[] table;

至此,我想大家也许应该明白了,为什么在 set 中是不允许存放重复值的。

通过才的分析,我们可以看到, map 的一些特征:

1.       map 中也是不能存放完全相同的元素的

2.       如果你存入的对象的 key 值已经存在的话,那么新的 value 将会取代老的 value 值,但是并不会添加新的元素进去。

我们可以通过一个测试程序来证明这一点:

  public void maptest() {

    map m = new hashmap();

    /**

     * we  can  put  the  int  1 and the  value  1  into  the  map

     * but  we  cannot  get  the  1 as  int  from the map

     * why ?

     * we  only  get  the  1  as  integer  from  the map,

     * so  we  only  get the object  from the map,if we  put the  value  into

     * the map,we  will get one  instance of  the wrapper  of  that

     */

    m.put(1, 1);

    //int i = m.get(1);

    integer i = (integer) m.get(1);

    system.out.println(i);

 

    m.put(1, 1);

    m.put(1, 1);

    system.out.println("map   :    " m);

    system.out.println("map  size    :   " m.size());

    m.put(1, 2);

    system.out.println("map   :    " m);

    system.out.println("map  size    :   " m.size());

  }

运行的结果是:

map   :    {1=1}

map  size    :   1

map   :    {1=2}

map  size    :   1

希望此文能大家有所帮助。



zhyiwww 2006-03-30 09:41
]]>
程序设计的主要目标:将变动的事物和不变的事物隔离开来http://www.blogjava.net/zhyiwww/archive/2006/03/29/38010.htmlzhyiwwwzhyiwwwwed, 29 mar 2006 03:51:00 gmthttp://www.blogjava.net/zhyiwww/archive/2006/03/29/38010.htmlhttp://www.blogjava.net/zhyiwww/comments/38010.htmlhttp://www.blogjava.net/zhyiwww/archive/2006/03/29/38010.html#feedback0http://www.blogjava.net/zhyiwww/comments/commentrss/38010.htmlhttp://www.blogjava.net/zhyiwww/services/trackbacks/38010.html将变动的事物和不变的事物隔离开来

zhyiwww 2006-03-29 11:51
]]>
一个小错误--在方法中定义static 变量http://www.blogjava.net/zhyiwww/archive/2006/03/29/37996.htmlzhyiwwwzhyiwwwwed, 29 mar 2006 02:50:00 gmthttp://www.blogjava.net/zhyiwww/archive/2006/03/29/37996.htmlhttp://www.blogjava.net/zhyiwww/comments/37996.htmlhttp://www.blogjava.net/zhyiwww/archive/2006/03/29/37996.html#feedback0http://www.blogjava.net/zhyiwww/comments/commentrss/37996.htmlhttp://www.blogjava.net/zhyiwww/services/trackbacks/37996.html是在方法中定义一个static变量,问程序运行会出现什么问题?
public void amethod() {
    static int i=10;
    system.out.println(i);
  }
如果你曾实验过的话,就知道,如果你使用eclipse或jbuilder的话,那么,你的程序不用编译就回出现错误
errors:  illegal  start of expression  at  line  69 .



zhyiwww 2006-03-29 10:50
]]>
网站地图