??xml version="1.0" encoding="utf-8" standalone="yes"?>亚洲婷婷天堂在线综合,亚洲成人午夜在线,亚洲精品无码久久久久http://m.tkk7.com/onejavaer/category/46184.html让我在热血沸腾中度此一?让我在醇酒般的梦里醉沉Q莫使我Dq惔塑的肉nQ终以空虚的w壳毁于泥尘zh-cnTue, 31 Aug 2010 16:11:32 GMTTue, 31 Aug 2010 16:11:32 GMT60全面文g操作java代码http://m.tkk7.com/onejavaer/articles/102307.html暗夜_暗夜_Wed, 07 Mar 2007 01:09:00 GMThttp://m.tkk7.com/onejavaer/articles/102307.htmlhttp://m.tkk7.com/onejavaer/comments/102307.htmlhttp://m.tkk7.com/onejavaer/articles/102307.html#Feedback0http://m.tkk7.com/onejavaer/comments/commentRss/102307.htmlhttp://m.tkk7.com/onejavaer/services/trackbacks/102307.htmlimport java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.StringTokenizer;
public class FileOperate {
    private String message;
    public FileOperate() {
    }

    /**
     * d文本文g内容
     * @param filePathAndName 带有完整l对路径的文件名
     * @param encoding 文本文g打开的编码方?br />     * @return q回文本文g的内?br />     */

    public String readTxt(String filePathAndName,String encoding) throws IOException{
     encoding = encoding.trim();
     StringBuffer str = new StringBuffer("");
     String st = "";
     try{
      FileInputStream fs = new FileInputStream(filePathAndName);
      InputStreamReader isr;
      if(encoding.equals("")){
       isr = new InputStreamReader(fs);
      }else{
       isr = new InputStreamReader(fs,encoding);
      }
      BufferedReader br = new BufferedReader(isr);
      try{
       String data = "";
       while((data = br.readLine())!=null){
         str.append(data+" ");
       }
      }catch(Exception e){
       str.append(e.toString());
      }
      st = str.toString();
     }catch(IOException es){
      st = "";
     }
     return st;     
    }

    /**
     * 新徏目录
     * @param folderPath 目录
     * @return q回目录创徏后的路径
     */

    public String createFolder(String folderPath) {
        String txt = folderPath;
        try {
            java.io.File myFilePath = new java.io.File(txt);
            txt = folderPath;
            if (!myFilePath.exists()) {
                myFilePath.mkdir();
            }
        }
        catch (Exception e) {
            message = "创徏目录操作出错";
        }
        return txt;
    }
   
    /**
     * 多目录创徏
     * @param folderPath 准备要在本目录下创建新目录的目录\?例如 c:myf
     * @param paths 无限U目录参敎ͼ各目录以单数线区分 例如 a|b|c
     * @return q回创徏文g后的路径 例如 c:myfac
     */

    public String createFolders(String folderPath, String paths){
        String txts = folderPath;
        try{
            String txt;
            txts = folderPath;
            StringTokenizer st = new StringTokenizer(paths,"|");
            for(int i=0; st.hasMoreTokens(); i++){
                    txt = st.nextToken().trim();
                    if(txts.lastIndexOf("/")!=-1){
                        txts = createFolder(txts+txt);
                    }else{
                        txts = createFolder(txts+txt+"/");   
                    }
            }
       }catch(Exception e){
           message = "创徏目录操作出错Q?;
       }
        return txts;
    }

   
    /**
     * 新徏文g
     * @param filePathAndName 文本文g完整l对路径及文件名
     * @param fileContent 文本文g内容
     * @return
     */

    public void createFile(String filePathAndName, String fileContent) {
     
        try {
            String filePath = filePathAndName;
            filePath = filePath.toString();
            File myFilePath = new File(filePath);
            if (!myFilePath.exists()) {
                myFilePath.createNewFile();
            }
            FileWriter resultFile = new FileWriter(myFilePath);
            PrintWriter myFile = new PrintWriter(resultFile);
            String strContent = fileContent;
            myFile.println(strContent);
            myFile.close();
            resultFile.close();
        }
        catch (Exception e) {
            message = "创徏文g操作出错";
        }
    }


    /**
     * 有编码方式的文g创徏
     * @param filePathAndName 文本文g完整l对路径及文件名
     * @param fileContent 文本文g内容
     * @param encoding ~码方式 例如 GBK 或?UTF-8
     * @return
     */

    public void createFile(String filePathAndName, String fileContent, String encoding) {
     
        try {
            String filePath = filePathAndName;
            filePath = filePath.toString();
            File myFilePath = new File(filePath);
            if (!myFilePath.exists()) {
                myFilePath.createNewFile();
            }
            PrintWriter myFile = new PrintWriter(myFilePath,encoding);
            String strContent = fileContent;
            myFile.println(strContent);
            myFile.close();
        }
        catch (Exception e) {
            message = "创徏文g操作出错";
        }
    }


    /**
     * 删除文g
     * @param filePathAndName 文本文g完整l对路径及文件名
     * @return Boolean 成功删除q回true遭遇异常q回false
     */

    public boolean delFile(String filePathAndName) {
     boolean bea = false;
        try {
            String filePath = filePathAndName;
            File myDelFile = new File(filePath);
            if(myDelFile.exists()){
             myDelFile.delete();
             bea = true;
            }else{
             bea = false;
             message = (filePathAndName+"
删除文g操作出错");
            }
        }
        catch (Exception e) {
            message = e.toString();
        }
        return bea;
    }
   


    /**
     * 删除文g?br />     * @param folderPath 文g夹完整绝对\?br />     * @return
     */

    public void delFolder(String folderPath) {
        try {
            delAllFile(folderPath); //删除完里面所有内?br />            String filePath = folderPath;
            filePath = filePath.toString();
            java.io.File myFilePath = new java.io.File(filePath);
            myFilePath.delete(); //删除I文件夹
        }
        catch (Exception e) {
            message = ("删除文gҎ作出?);
        }
    }
   
   
    /**
     * 删除指定文g夹下所有文?br />     * @param path 文g夹完整绝对\?br />     * @return
     * @return
     */

    public boolean delAllFile(String path) {
     boolean bea = false;
        File file = new File(path);
        if (!file.exists()) {
            return bea;
        }
        if (!file.isDirectory()) {
            return bea;
        }
        String[] tempList = file.list();
        File temp = null;
        for (int i = 0; i < tempList.length; i++) {
            if (path.endsWith(File.separator)) {
                temp = new File(path + tempList[i]);
            }else{
                temp = new File(path + File.separator + tempList[i]);
            }
            if (temp.isFile()) {
                temp.delete();
            }
            if (temp.isDirectory()) {
                delAllFile(path+"/"+ tempList[i]);//先删除文件夹里面的文?br />                delFolder(path+"/"+ tempList[i]);//再删除空文g?br />                bea = true;
            }
        }
        return bea;
    }


    /**
     * 复制单个文g
     * @param oldPathFile 准备复制的文件源
     * @param newPathFile 拯到新l对路径带文件名
     * @return
     */

    public void copyFile(String oldPathFile, String newPathFile) {
        try {
            int bytesum = 0;
            int byteread = 0;
            File oldfile = new File(oldPathFile);
            if (oldfile.exists()) { //文g存在?br />                InputStream inStream = new FileInputStream(oldPathFile); //d原文?br />                FileOutputStream fs = new FileOutputStream(newPathFile);
                byte[] buffer = new byte[1444];
                while((byteread = inStream.read(buffer)) != -1){
                    bytesum += byteread; //字节?文g大小
                    System.out.println(bytesum);
                    fs.write(buffer, 0, byteread);
                }
                inStream.close();
            }
        }catch (Exception e) {
            message = ("复制单个文g操作出错");
        }
    }
   

    /**
     * 复制整个文g夹的内容
     * @param oldPath 准备拯的目?br />     * @param newPath 指定l对路径的新目录
     * @return
     */

    public void copyFolder(String oldPath, String newPath) {
        try {
            new File(newPath).mkdirs(); //如果文g夹不存在 则徏立新文g?br />            File a=new File(oldPath);
            String[] file=a.list();
            File temp=null;
            for (int i = 0; i < file.length; i++) {
                if(oldPath.endsWith(File.separator)){
                    temp=new File(oldPath+file[i]);
                }else{
                    temp=new File(oldPath+File.separator+file[i]);
                }
                if(temp.isFile()){
                    FileInputStream input = new FileInputStream(temp);
                    FileOutputStream output = new FileOutputStream(newPath + "/" +
                    (temp.getName()).toString());
                    byte[] b = new byte[1024 * 5];
                    int len;
                    while ((len = input.read(b)) != -1) {
                        output.write(b, 0, len);
                    }
                    output.flush();
                    output.close();
                    input.close();
                }
                if(temp.isDirectory()){//如果是子文g?br />                    copyFolder(oldPath+"/"+file[i],newPath+"/"+file[i]);
                }
            }
        }catch (Exception e) {
            message = "复制整个文g夹内Ҏ作出?;
        }
    }


    /**
     * Ud文g
     * @param oldPath
     * @param newPath
     * @return
     */

    public void moveFile(String oldPath, String newPath) {
        copyFile(oldPath, newPath);
        delFile(oldPath);
    }
   

    /**
     * Ud目录
     * @param oldPath
     * @param newPath
     * @return
     */

    public void moveFolder(String oldPath, String newPath) {
        copyFolder(oldPath, newPath);
        delFolder(oldPath);
    }
    public String getMessage(){
        return this.message;
    }
}



暗夜_ 2007-03-07 09:09 发表评论
]]>
JAVA语言的反和内省http://m.tkk7.com/onejavaer/articles/101998.html暗夜_暗夜_Mon, 05 Mar 2007 13:41:00 GMThttp://m.tkk7.com/onejavaer/articles/101998.htmlhttp://m.tkk7.com/onejavaer/comments/101998.htmlhttp://m.tkk7.com/onejavaer/articles/101998.html#Feedback0http://m.tkk7.com/onejavaer/comments/commentRss/101998.htmlhttp://m.tkk7.com/onejavaer/services/trackbacks/101998.html

很多朋友在深入的接触 JAVA 语言后就会发现这样两个词Q反?/span> (Reflection) 和内?/span> (Introspector) Q经常搞不清楚这到底是怎么回事Q在什么场合下应用以及如何使用Q今天把q二者放在一起介l,因ؓ它们二者是相辅相成的?/span>

反射

相对而言Q反比内省更容易理解一炏V用一句比较白的话来概括,反射是让你可以通过名称来得到对?/span> ( c,属性,Ҏ ) 的技术。例如我们可以通过cd来生成一个类的实例;知道了方法名Q就可以调用q个ҎQ知道了属性名可以访问这个属性的倹{?/span>

q是写两个例子让大家更直观的了解反射的用方法:

// 通过cd来构造一个类的实?br /> Class cls_str = Class.forName( "java.lang.String" );
// 上面q句很眼熟,因ؓ使用q?/span> JDBC 讉K数据库的人都用过 J
Object str = cls_str.newInstance();
// 相当?/span> String str = new String();

// 通过Ҏ名来调用一个方?br /> String methodName = "length" ;
Method m = cls_str.getMethod(methodName, null );
System.out.println( "length is " + m.invoke(str, null ));
// 相当?/span> System.out.println(str.length());

上面的两个例子是比较常用Ҏ。看C面的例子有发问了:Z么要q么ȝ呢?本来一条语句就完成的事情干吗要整这么复杂?没错Q在上面的例子中实没有必要q么ȝ。不q你惛_q样一个应用程序,它支持动态的功能扩展Q也是说程序不重新启动但是可以自动加蝲新的功能Q这个功能用一个具体类来表C。首先我们必Mؓq些功能定义一个接口类Q然后我们要求所有扩展的功能cdd现我指定的接口,q个规定了应用程序和可扩展功能之间的接口规则Q但是怎么动态加载呢Q我们必让应用E序知道要扩展的功能cȝcdQ比如是 test.Func1 Q当我们把这个类?/span> ( 字符?/span> ) 告诉应用E序后,它就可以使用我们W一个例子的Ҏ来加载ƈ启用新的功能。这是cȝ反射Q请问你有别的选择吗?

       关于Ҏ的反徏议大家看我的另外一文章?/span> 利用 Turbine 的事件映来扩展 Struts 的功?/span> 》,地址是: http://www.javayou.com/article/CSDN/extend_struts.html 。这文章详l介l了如果通过反射来扩?/span> Struts 框架的功能?/span>

内省

内省?/span> Java 语言?/span> Bean cd性、事件的一U缺省处理方法。例如类 A 中有属?/span> name, 那我们可以通过 getName,setName 来得到其值或者设|新的倹{通过 getName/setName 来访?/span> name 属性,q就是默认的规则?/span> Java 中提供了一?/span> API 用来讉K某个属性的 getter/setter ҎQ通过q些 API 可以使你不需要了解这个规则(但你最好还是要搞清楚)Q这?/span> API 存放于包 java.beans 中?/span>

一般的做法是通过c?/span> Introspector 来获取某个对象的 BeanInfo 信息Q然后通过 BeanInfo 来获取属性的描述器( PropertyDescriptor Q,通过q个属性描q器可以获取某个属性对应的 getter/setter ҎQ然后我们就可以通过反射机制来调用这些方法。下面我们来看一个例子,q个例子把某个对象的所有属性名U和值都打印出来Q?/span>

/* 
 * Created on 2004-6-29
 */

package demo;

import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;

/**
  * 内省演示例子
  * @author liudong
  */

public class IntrospectorDemo {
    String name;
    public static void main(String[] args) throws Exception{
        IntrospectorDemo demo = new IntrospectorDemo();
        demo.setName( "Winter Lau" );        

        // 如果不想把父cȝ属性也列出来的话,
        // ?/span> getBeanInfo 的第二个参数填写父类的信?br />         BeanInfo bi = Introspector.getBeanInfo(demo.getClass(), Object. class );
        PropertyDescriptor[] props = bi.getPropertyDescriptors();
        for ( int i=0;i<props.length;i++){
            System.out.println(props[i].getName()+ "=" +
                    props[i].getReadMethod().invoke(demo, null ));
        }

    }    

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this .name = name;
    }
}

Web 开发框?/span> Struts 中的 FormBean 是通过内省机制来将表单中的数据映射到类的属性上Q因此要?/span> FormBean 的每个属性要?/span> getter/setter Ҏ。但也ƈ不Lq样Q什么意思呢Q就是说对一?/span> Bean cLԌ我可以没有属性,但是只要?/span> getter/setter Ҏ中的其中一个,那么 Java 的内省机制就会认为存在一个属性,比如cM有方?/span> setMobile Q那么就认ؓ存在一?/span> mobile 的属性,q样可以方便我们?/span> Bean c通过一个接口来定义而不用去兛_具体实现Q不用去兛_ Bean 中数据的存储。比如我们可以把所有的 getter/setter Ҏ攑ֈ接口里定义,但是真正数据的存取则是在具体cMd玎ͼq样可提高系l的扩展性?/span>

ȝ

?/span> Java 的反以及内省应用到E序设计中去可以大大的提供程序的化和可扩展性。有很多目都是采取q两U技术来实现其核心功能,例如我们前面提到?/span> Struts Q还有用于处?/span> XML 文g?/span> Digester 目Q其实应该说几乎所有的目都或多或的采用q两U技术。在实际应用q程中二者要怺l合方能发挥真正的智能化以及高度可扩展性?/span>



暗夜_ 2007-03-05 21:41 发表评论
]]>
字符串匹?/title><link>http://m.tkk7.com/onejavaer/articles/101992.html</link><dc:creator>暗夜_</dc:creator><author>暗夜_</author><pubDate>Mon, 05 Mar 2007 13:25:00 GMT</pubDate><guid>http://m.tkk7.com/onejavaer/articles/101992.html</guid><wfw:comment>http://m.tkk7.com/onejavaer/comments/101992.html</wfw:comment><comments>http://m.tkk7.com/onejavaer/articles/101992.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://m.tkk7.com/onejavaer/comments/commentRss/101992.html</wfw:commentRss><trackback:ping>http://m.tkk7.com/onejavaer/services/trackbacks/101992.html</trackback:ping><description><![CDATA[ <h1>1 术语定义</h1> <p>在字W串匚w问题中,我们期待察看串T中是否含有串P?br />其中串T被称为目标串Q串S被称为模式串?/p> <h1>2 朴素匚w法</h1> <p>q行字符串匹配,最单的一个想法是Q?/p> <div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"> <img id="Codehighlighter1_25_607_Open_Image" onclick="this.style.display='none'; Codehighlighter1_25_607_Open_Text.style.display='none'; Codehighlighter1_25_607_Closed_Image.style.display='inline'; Codehighlighter1_25_607_Closed_Text.style.display='inline';" src="http://m.tkk7.com/images/OutliningIndicators/ExpandedBlockStart.gif" align="top" /> <img id="Codehighlighter1_25_607_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_25_607_Closed_Text.style.display='none'; Codehighlighter1_25_607_Open_Image.style.display='inline'; Codehighlighter1_25_607_Open_Text.style.display='inline';" src="http://m.tkk7.com/images/OutliningIndicators/ContractedBlock.gif" align="top" /> <span style="COLOR: #0000ff">public</span> <span style="COLOR: #000000"> </span> <span style="COLOR: #0000ff">class</span> <span style="COLOR: #000000"> SimpleMatch </span> <span id="Codehighlighter1_25_607_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"> <img src="http://m.tkk7.com/images/dot.gif" /> </span> <span id="Codehighlighter1_25_607_Open_Text"> <span style="COLOR: #000000">{<br /><img id="Codehighlighter1_81_424_Open_Image" onclick="this.style.display='none'; Codehighlighter1_81_424_Open_Text.style.display='none'; Codehighlighter1_81_424_Closed_Image.style.display='inline'; Codehighlighter1_81_424_Closed_Text.style.display='inline';" src="http://m.tkk7.com/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_81_424_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_81_424_Closed_Text.style.display='none'; Codehighlighter1_81_424_Open_Image.style.display='inline'; Codehighlighter1_81_424_Open_Text.style.display='inline';" src="http://m.tkk7.com/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />  </span> <span style="COLOR: #0000ff">public</span> <span style="COLOR: #000000"> </span> <span style="COLOR: #0000ff">int</span> <span style="COLOR: #000000"> StringMatch(String target,String patten) </span> <span id="Codehighlighter1_81_424_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"> <img src="http://m.tkk7.com/images/dot.gif" /> </span> <span id="Codehighlighter1_81_424_Open_Text"> <span style="COLOR: #000000">{<br /><img src="http://m.tkk7.com/images/OutliningIndicators/InBlock.gif" align="top" />      </span> <span style="COLOR: #0000ff">int</span> <span style="COLOR: #000000"> tl </span> <span style="COLOR: #000000">=</span> <span style="COLOR: #000000"> target.length();<br /><img src="http://m.tkk7.com/images/OutliningIndicators/InBlock.gif" align="top" />      </span> <span style="COLOR: #0000ff">int</span> <span style="COLOR: #000000"> pl </span> <span style="COLOR: #000000">=</span> <span style="COLOR: #000000"> patten.length();<br /><img src="http://m.tkk7.com/images/OutliningIndicators/InBlock.gif" align="top" />      </span> <span style="COLOR: #0000ff">int</span> <span style="COLOR: #000000"> i </span> <span style="COLOR: #000000">=</span> <span style="COLOR: #000000"> </span> <span style="COLOR: #000000">0</span> <span style="COLOR: #000000">;<br /><img src="http://m.tkk7.com/images/OutliningIndicators/InBlock.gif" align="top" />      </span> <span style="COLOR: #0000ff">int</span> <span style="COLOR: #000000"> j </span> <span style="COLOR: #000000">=</span> <span style="COLOR: #000000"> </span> <span style="COLOR: #000000">0</span> <span style="COLOR: #000000">;<br /><img id="Codehighlighter1_216_365_Open_Image" onclick="this.style.display='none'; Codehighlighter1_216_365_Open_Text.style.display='none'; Codehighlighter1_216_365_Closed_Image.style.display='inline'; Codehighlighter1_216_365_Closed_Text.style.display='inline';" src="http://m.tkk7.com/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_216_365_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_216_365_Closed_Text.style.display='none'; Codehighlighter1_216_365_Open_Image.style.display='inline'; Codehighlighter1_216_365_Open_Text.style.display='inline';" src="http://m.tkk7.com/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />      </span> <span style="COLOR: #0000ff">while</span> <span style="COLOR: #000000">(i </span> <span style="COLOR: #000000"><</span> <span style="COLOR: #000000"> tl </span> <span style="COLOR: #000000">-</span> <span style="COLOR: #000000"> pl </span> <span style="COLOR: #000000">&&</span> <span style="COLOR: #000000"> j </span> <span style="COLOR: #000000"><</span> <span style="COLOR: #000000"> pl) </span> <span id="Codehighlighter1_216_365_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"> <img src="http://m.tkk7.com/images/dot.gif" /> </span> <span id="Codehighlighter1_216_365_Open_Text"> <span style="COLOR: #000000">{<br /><img src="http://m.tkk7.com/images/OutliningIndicators/InBlock.gif" align="top" />          </span> <span style="COLOR: #0000ff">if</span> <span style="COLOR: #000000">(patten.charAt(j) </span> <span style="COLOR: #000000">==</span> <span style="COLOR: #000000"> target.charAt(i</span> <span style="COLOR: #000000">+</span> <span style="COLOR: #000000">j))<br /><img src="http://m.tkk7.com/images/OutliningIndicators/InBlock.gif" align="top" />              j</span> <span style="COLOR: #000000">++</span> <span style="COLOR: #000000">;<br /><img id="Codehighlighter1_305_357_Open_Image" onclick="this.style.display='none'; Codehighlighter1_305_357_Open_Text.style.display='none'; Codehighlighter1_305_357_Closed_Image.style.display='inline'; Codehighlighter1_305_357_Closed_Text.style.display='inline';" src="http://m.tkk7.com/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_305_357_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_305_357_Closed_Text.style.display='none'; Codehighlighter1_305_357_Open_Image.style.display='inline'; Codehighlighter1_305_357_Open_Text.style.display='inline';" src="http://m.tkk7.com/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />          </span> <span style="COLOR: #0000ff">else</span> <span style="COLOR: #000000"> </span> <span id="Codehighlighter1_305_357_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"> <img src="http://m.tkk7.com/images/dot.gif" /> </span> <span id="Codehighlighter1_305_357_Open_Text"> <span style="COLOR: #000000">{<br /><img src="http://m.tkk7.com/images/OutliningIndicators/InBlock.gif" align="top" />              j </span> <span style="COLOR: #000000">=</span> <span style="COLOR: #000000"> </span> <span style="COLOR: #000000">0</span> <span style="COLOR: #000000">;<br /><img src="http://m.tkk7.com/images/OutliningIndicators/InBlock.gif" align="top" />              i</span> <span style="COLOR: #000000">++</span> <span style="COLOR: #000000">;<br /><img src="http://m.tkk7.com/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />          }</span> </span> <span style="COLOR: #000000"> <br /> <img src="http://m.tkk7.com/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />      }</span> </span> <span style="COLOR: #000000"> <br /> <img src="http://m.tkk7.com/images/OutliningIndicators/InBlock.gif" align="top" />      </span> <span style="COLOR: #0000ff">if</span> <span style="COLOR: #000000">(j </span> <span style="COLOR: #000000">==</span> <span style="COLOR: #000000"> pl)<br /><img src="http://m.tkk7.com/images/OutliningIndicators/InBlock.gif" align="top" />          </span> <span style="COLOR: #0000ff">return</span> <span style="COLOR: #000000"> i;<br /><img src="http://m.tkk7.com/images/OutliningIndicators/InBlock.gif" align="top" />      </span> <span style="COLOR: #0000ff">return</span> <span style="COLOR: #000000"> </span> <span style="COLOR: #000000">-</span> <span style="COLOR: #000000">1</span> <span style="COLOR: #000000">;<br /><img src="http://m.tkk7.com/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />  }</span> </span> <span style="COLOR: #000000"> <br /> <img src="http://m.tkk7.com/images/OutliningIndicators/InBlock.gif" align="top" />  <br /><img id="Codehighlighter1_469_605_Open_Image" onclick="this.style.display='none'; Codehighlighter1_469_605_Open_Text.style.display='none'; Codehighlighter1_469_605_Closed_Image.style.display='inline'; Codehighlighter1_469_605_Closed_Text.style.display='inline';" src="http://m.tkk7.com/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_469_605_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_469_605_Closed_Text.style.display='none'; Codehighlighter1_469_605_Open_Image.style.display='inline'; Codehighlighter1_469_605_Open_Text.style.display='inline';" src="http://m.tkk7.com/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />  </span> <span style="COLOR: #0000ff">public</span> <span style="COLOR: #000000"> </span> <span style="COLOR: #0000ff">static</span> <span style="COLOR: #000000"> </span> <span style="COLOR: #0000ff">void</span> <span style="COLOR: #000000"> main(String[] args)</span> <span id="Codehighlighter1_469_605_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"> <img src="http://m.tkk7.com/images/dot.gif" /> </span> <span id="Codehighlighter1_469_605_Open_Text"> <span style="COLOR: #000000">{<br /><img src="http://m.tkk7.com/images/OutliningIndicators/InBlock.gif" align="top" />      String t </span> <span style="COLOR: #000000">=</span> <span style="COLOR: #000000"> </span> <span style="COLOR: #000000">"</span> <span style="COLOR: #000000">123456789</span> <span style="COLOR: #000000">"</span> <span style="COLOR: #000000">;<br /><img src="http://m.tkk7.com/images/OutliningIndicators/InBlock.gif" align="top" />      String p </span> <span style="COLOR: #000000">=</span> <span style="COLOR: #000000"> </span> <span style="COLOR: #000000">"</span> <span style="COLOR: #000000">456</span> <span style="COLOR: #000000">"</span> <span style="COLOR: #000000">;<br /><img src="http://m.tkk7.com/images/OutliningIndicators/InBlock.gif" align="top" />      SimpleMatch sm </span> <span style="COLOR: #000000">=</span> <span style="COLOR: #000000"> </span> <span style="COLOR: #0000ff">new</span> <span style="COLOR: #000000"> SimpleMatch();<br /><img src="http://m.tkk7.com/images/OutliningIndicators/InBlock.gif" align="top" />      System.out.println(sm.StringMatch(t, p));<br /><img src="http://m.tkk7.com/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />  }</span> </span> <span style="COLOR: #000000"> <br /> <img src="http://m.tkk7.com/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />}</span> </span> </div> <p>可以看见Q这个算法(假定m>>nQ的复杂度是O(mn)Q其中m是T的长度,n是P的长度。这U算法的~陷是匹配过E中带有回溯——准地说是T串存在回溯,也就是当匚w不成功的时候,之前q行的匹配完全变为无用功Q所有的比较需要重新开始?/p> <h1>3 KMP法</h1> <p>KMP法是D.E.Knuth、J.H.Morris和V.R.Pratt提出的无回溯的字W串匚w法Q算法的核心思想是设法在匹配失败的时候,量利用之前的匹配结果,消除T串的回溯问题。那么如何消除回溯呢Q请看下面的例子Q?/p> <p>假设P=abacdQ如果T=abax...Q当从头开始匹配到字符cӞ若c=xQ显Ӟ匚wq程l箋Q当c≠xӞ按照朴素的匹配算法,T串会发生回溯Q之后T串会从第2个字Wb开始重新匹配,而不是从匚wp|的字Wx开始l。但是显Ӟ对于上述的匹配过E,T串不需要从b开始重新匹配,它只需要从x开始和P的b字符l箋匚w卛_。如下:<br />匚wq程Q?br />P=abacd<br />T=abax....<br />     ^----比较到此处时发生匚wp|<br />朴素匚w法Q?br />P= abacd<br />T=abax...<br />   ^----回溯到bQ重新开始和P的匹?br />KMP法Q?br />P=  abacd<br />T=abax...<br />     ^----T串不回溯Q从x处l匹?/p> <p>现在的问题是Q按照KMP法Q匹配失败的时候,P串需要重新调整位|,但是调整的依据是什么?Knuth{h发现QP调整位置的依据和P的构造有养I和T无关。具体来_定义失效函数Qf(j)=kQ其?<=k<=jQ且k是得p<sub>0</sub>p<sub>1</sub>...p<sub>k-1</sub> = p<sub>j-k+1</sub>p<sub>j-k+2</sub>...p<sub>j</sub>成立的最大整数。徏立失效函数的法如下Q?br />public void Build() {<br /> if(pattern == null)<br />  throw new Exception("KMP Exception : null pattern");<br /> array = new int[pattern.Length];<br /> int i = 0, s = pattern.Length;<br /> if(s > 1)<br />  array[0] = 0;<br /> for(i = 1; i < s; i++) {<br />  if(pattern[i] == pattern[array[i - 1]])<br />   array[i] = array[i - 1] + 1;<br />  else<br />   array[i] = 0;<br /> }<br />}</p> <p>匚wq程如下Q?br />public int Match(String target, int start) {<br /> if(array == null || pattern == null || target == null)<br />  return -1;<br /> int target_index = start;<br /> int pattern_index = 0;<br /> int token_length = target.Length;<br /> int pattern_length = pattern.Length;<br /> while(target_index < token_length && pattern_index < pattern_length) {<br />  if(target[target_index] == pattern[pattern_index]) {<br />   target_index++;<br />   pattern_index++;<br />  } else {<br />   if(pattern_index == begin)<br />    target_index++;<br />   else<br />    pattern_index = array[pattern_index - 1];<br />  }<br /> }<br /> if(pattern_index == pattern_length)<br />  return target_index - pattern_length;<br /> return -1;<br />}</p> <h1>4 支持通配W??的KMP法</h1> <p>KMP法虽然能够q行字符串匹配,但是Q在实践中字W串匚w往往q要支持通配W,MSpȝ中最常见的通配W是??。其中,?可以代表一个字W(不能没有Q,*可以代表L多个字符Q可以ؓI)。经典的KMP法针对通配W是无能为力的,但是l过单的攚w,KMP法也可以识别通配W?/p> <p>首先?Q根?的功能,?表示L字符Q也是说在匚wq程中,?永远匚w成功。因此对匚w函数的修改十分简单:<br />...<br /> while(target_index < token_length && pattern_index < pattern_length) {<br />  if(target[target_index] == pattern[pattern_index]|| pattern[pattern_index] == '?') {<br />   target_index++;<br />   pattern_index++;<br />  } else {<br />...<br />建立失效函数的过E和匚wq程cMQ修改如下:<br />...<br /> for(i = 1; i < s; i++) {<br />  if(pattern[i] == pattern[array[i - 1]]|| pattern[i] == '?' || pattern[array[i - 1]] == '?')<br />   array[i] = array[i - 1] + 1;<br />...</p> <p>本质上,?q没有修改算法,而仅仅修改了匚w规则——遇?则一定匹配。然?与此不同Q?的作用是匚wL多个字符Q显然我们不能简单的修改匚wq程而满求。如果我们重新思?的作用,我们会发?的另一个作用就是分割PԌ卛_果P=P<sub>1</sub>*P<sub>2</sub>Q那么与其说*代表匚wL多个字符Q不如说P的匹配条件是在匹配P<sub>1</sub>子串后再匚wP<sub>2</sub>子串?/p> <p>现在回顾失效函数的作用,如果当匹配到P的j+1位时匚wp|Q那么重新开始匹配的时候,P串的位置调整到f(j)位,直到P串的位置调整?Q则匚w重新开始。但当P=P<sub>1</sub>*P<sub>2</sub>Q假如P<sub>1</sub>已经匚w成功Q而在P<sub>2</sub>中发生匹配失败,那么P串要需要调整位|,但P串无论如何调_此时也不应该调整?Q最多调整到P<sub>2</sub>的开始处Q因为P<sub>1</sub>已经匚wQ只需匚wP<sub>2</sub>卛_。假如P=abcab*abcabQ失效函数应该是Q注意之前提?的作用)Q?br />a b c a b * a b c a b<br />0 0 0 1 2 - 6 6 6 7 8</p> <p>因此Q要惌KMP支持*Q那么关键是要重新设计失效函数的建立法Q如下:<br />public void Build() {<br /> if(pattern == null)<br />  throw new Exception("KMP Exception : null pattern");<br /> array = new int[pattern.Length];<br /> int i = 0, s = pattern.Length;<br /> if(s > 1)<br />  array[0] = 0;<br /> int begin = 0;<br /> for(i = 1; i < s; i++) {<br />  if(pattern[i] == '*') {<br />   array[i] = i;<br />   begin = i + 1;<br />  } else if(pattern[i] == pattern[array[i - 1]] || pattern[i] == '?' || pattern[array[i - 1]] == '?')<br />   array[i] = array[i - 1] + 1;<br />  else<br />   array[i] = begin;<br /> }<br />} </p> <p>法中begin表示每段字符串的开始位|。此外,匚wq程也应该进行相应的修改Q因为字W?对于匚w没有M帮助Q它属于占位W,因此需要蟩q,匚w法如下Q?br />public int Match(String target, int start) {<br /> if(array == null || pattern == null || target == null)<br />  return -1;<br /> int target_index = start;<br /> int pattern_index = 0;<br /> int token_length = target.Length;<br /> int pattern_length = pattern.Length;<br /> int begin = 0;<br /> while(target_index < token_length && pattern_index < pattern_length) {<br />  if(pattern[pattern_index] == '*') {<br />   begin = pattern_index + 1;<br />   pattern_index++;<br />  } else if(target[target_index] == pattern[pattern_index] || pattern[pattern_index] == '?') {<br />   target_index++;<br />   pattern_index++;<br />  } else {<br />   if(pattern_index == begin)<br />    target_index++;<br />   else<br />    pattern_index = array[pattern_index - 1];<br />  }<br /> }<br /> if(pattern_index == pattern_length)<br />  return target_index - pattern_length + begin;<br /> return -1;<br />}</p> <h1>5 正则语言和确定状态自动机</h1> <p>一个数字逻辑的问题:设计一个识?1011的电路,解这个问题的关键是设计个电路的DFAQ如下:<br /><img style="CURSOR: pointer" onclick="javascript:window.open(this.src);" src="http://www.blog.edu.cn/UploadFiles/2006-8/823915044.png" onload="javascript:if(this.width>500){this.resized=true;this.style.width=500;}" /></p> <p>仔细看看q个状态机Q是不是和KMP的算法有几分cM呢?qƈ不是巧合Q因为KMP法中的失效函数d以等L转化Z个DFA。当然KMP的DFAq比识别11011的DFA要复杂,原因在于KMP接受的输入是全体字符集合Q识?1011的DFA只接??q两个输入。我们知道,一个正则语a和一个DFA是等LQ而KMP计算失效函数的算法,实际上等价于求DFA的过E,f(j)的值实际上表明状态j+1接受C正确的字W时应该回溯到的状态(注意此时输入ƈ没有前进Q。普通的字符串都能看成是一个正则语aQ含有通配W??的字W串也可以等L转换Z个正则表辑ּ。但是,正则语言的集合远比KMP法所能支持的模式集合的更大,期间原因q是刚才提过的输入问题。试想P=p<sub>1</sub>p<sub>2</sub>...p<sub>n</sub>Q当匚w到p<sub>j</sub>的时候,如果下一个输入字W正是p<sub>j</sub>Q那么状态机q入下一个状态,如果不是p<sub>j</sub>Q那么状态机按照实效函数的指C{Ud状态f(j-1)Q也是说KMP状态机的每个状态只能根据输入是否ؓp<sub>j</sub>来进行{UR而正则表辑ּ所对应的状态机则有所不同Q如果正则语aL=l<sub>1</sub>l<sub>2</sub>...l<sub>n</sub>Q假设这些都是字母,当匹配到l<sub>j</sub>位的时候,如果下一个输入字W正是l<sub>j</sub>Q那么状态机q入下一个状态,否则它还可以Ҏ输入的D行{U,例如l<sub>j</sub>=c<sub>1</sub>时{换到状态xQl<sub>j</sub>=c<sub>2</sub>时状态{换到y{等?/p> <h1>6 l语</h1> <p>字符串匹配问题是老问题了Qƈ没有太多新意可言Q只不过虽然KMP法十分单,但它的内在含义还是十分深ȝ。横向比较KMP、DFA和正则语a、正则表辑ּ我们会发玎ͼ它们之间存在很多的关联,而这U比较也有利于我们更好的理解q些法Q或者改q这些算法。最后说一句,试图利用目前的框架得KMP法支持全部U类的通配W(对应于正则表辑ּ是x?、x*、x+、{m,n}{等Q是不可能,而我们也不需要这么做Q因为我们还有正则表辑ּ嘛?/p> <img src ="http://m.tkk7.com/onejavaer/aggbug/101992.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://m.tkk7.com/onejavaer/" target="_blank">暗夜_</a> 2007-03-05 21:25 <a href="http://m.tkk7.com/onejavaer/articles/101992.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>NoClassDefDoundErr与ClassNotFoundException区别 http://m.tkk7.com/onejavaer/articles/101651.html暗夜_暗夜_Sat, 03 Mar 2007 10:23:00 GMThttp://m.tkk7.com/onejavaer/articles/101651.htmlhttp://m.tkk7.com/onejavaer/comments/101651.htmlhttp://m.tkk7.com/onejavaer/articles/101651.html#Feedback0http://m.tkk7.com/onejavaer/comments/commentRss/101651.htmlhttp://m.tkk7.com/onejavaer/services/trackbacks/101651.html作?langm

版权声明Q本文可以自p{载,转蝲时请务必以超链接形式标明文章原始出处和作者信息及本声?
作?langm
原文:http://www.matrix.org.cn/resource/article/44/44056_NoClassDefDoundErr.html
关键?NoClassDefDoundErr ClassNotFoundException

在读q篇文章之前Q你最好了解一下Java的Exception机制?/p>

也许你在开发的q程中经常地见到ClassNotFoundException和NoClassDefFoundErrq两个异常,每每看到之后Q都会一概而论的是cL有找刎ͼ但有些时候见C们的时候又有些疑惑Q至我是这PQؓ什么Java要用两个异常来表C类定义没有扑ֈ那?他们之间有什么区别那Q?/p>

正y今天我又到了这个问题,Z的仔l研I了一下这两个异常的区别?
首先Q?
ClassNotFoundException直接l承与ExceptionQ它是一个checked的异常?
NoClassDefFoundErr l承自Error->LinkageError Q它是一个unchecked的异常?/p>

下面让我们看一下两个异常在API文中的说明

ClassNotFoundExceptionQ?
当应用尝试用字符串名U通过下面的方法装载一个类时这个类的定义却没有扑ֈ时会抛出的异常?
Class.forName
ClassLoader.findSystemClass
ClassLoader.loadClass

NoClassDefFoundErrQ?
当JVM或者ClassLoader实例试装蝲一个类的定义(q通常是一个方法调用或者new表达式创Z个实例过E的一部分Q而这个类定义q没有找时所抛出的错误?
当编译的时候可以找到这个类的定义,但是以后q个cM再存在?/p>

q比较显而易见了吧,d文是很重要的事情。这里我p一下我对这两个cȝ区别的理解?/p>

ClassNotFoundException异常只出现在你的应用E序d的装载类的过E中Q这个异常很多时候出现在我们的应用框架在初始化或者运行中动态装载已配置的类的过E中。这U情况下我们应该首先查我们的配置或者参数是否错误,是否企图装蝲一个ƈ不存在的c,如果配置没有错误Q我们就应该查看Classpath是否配置错误而导致ClassLoader无法扑ֈq个c,也应该检查要装蝲的类是否在一个jar包中而我们在引入q个jar包的q程中是否有遗漏或错误(q里jar包的版本也是一个需要格外注意的问题Q很多时候؜qjar包版本会造成太多的麻烦)?

NoClassDefFoundErr异常一般出现在我们~译环境和运行环境不一致的情况下,是说我们有可能在编译过后更改了Classpath或者jar包所以导致在q行的过E中JVM或者ClassLoader无法扑ֈq个cȝ定义Q我曄在编译后作了一ơjar包的清理Q然后应用就送给了我一个这LC物Q?/p>

我们l常用SDK开发应用,开发的q程中要引入很多jar包,有些SDK也会讑֮自己的Classpath。编译过E结束后在运行的q程中就要将已开发的应用和所有引入的jar包拷贝到应用服务器的相应目录下才可以q行Q而应用服务器使用的Classpath也很有可能与SDK的不同,在这个过E中有很大的几率造成双方环境不一致。所以很多开发者就会遇到在SDK中可以编译,q行也没有问题,但是同样的程序放到应用服务器上就出现NoClassDefFoundErrq个异常q种情况Q这是让初学者很挠头的一个问题?/p>

以上是我对q两个异常的一点个人理解,希望对各位开发者有所帮助Q可以让各位开发者在以后的开发过E中能够更快的找到问题所在。祝开发顺?/p>

暗夜_ 2007-03-03 18:23 发表评论
]]>
java异常处理http://m.tkk7.com/onejavaer/articles/101649.html暗夜_暗夜_Sat, 03 Mar 2007 10:14:00 GMThttp://m.tkk7.com/onejavaer/articles/101649.htmlhttp://m.tkk7.com/onejavaer/comments/101649.htmlhttp://m.tkk7.com/onejavaer/articles/101649.html#Feedback0http://m.tkk7.com/onejavaer/comments/commentRss/101649.htmlhttp://m.tkk7.com/onejavaer/services/trackbacks/101649.html 1 Java的异常控制机?/font>

捕获错误最理想的是在编译期Q最好在试图q行E序以前。然而,q所有错误都能在~译期间侦测到。有些问题必dq行期间解决。让错误的缔l者通过一定的Ҏ预先向接收者传递一些适当的信息,使其知道可能发生什么样的错误以及该如何处理遇到的问题,q就是Java的异常控制机制?br />“异常”QExceptionQ这个词表达的是一U正常情况之外的“异常”。在问题发生的时候,我们可能不知具体该如何解冻I但肯定知道已不能不顾一切地l箋下去。此Ӟ必须坚决地停下来Qƈ由某人、某地指出发生了什么事情,以及该采取何U对{。异常机制的另一好处就是能够简化错误控制代码。我们再也不用检查一个特定的错误Q然后在E序的多处地方对其进行控制。此外,也不需要在Ҏ调用的时候检查错误(因ؓ保证有h能捕莯里的错误Q。我们只需要在一个地方处理问题:“异常控制模块”或?#8220;异常控制?#8221;。这样可有效减少代码量,q将那些用于描述具体操作的代码与专门U正错误的代码分隔开。一般情况下Q用于读取、写入以及调试的代码会变得更富有条理?br />若某个方法生一个异常,必须保证该异常能被捕Pq获得正对待。Java的异常控制机制的一个好处就是允许我们在一个地方将_֊集中在要解决的问题上Q然后在另一个地方对待来自那个代码内部的错误。那个可能发生异常的地方叫做“警戒?#8221;Q它是一个语句块Q我们有必要zN警探日夜监视着。生成的异常必须在某个地方被捕获和进行处理,p警察抓到嫌疑犯后要带到警|去询问。这个地方便是异常控制模块?br />“警戒?#8221;是一个try关键字开头后面用花括hh的语句块Q我们把它叫?#8220;try?#8221;。当try块中有语句发生异常时掷出某U异常类的一个对象。异常被异常控制器捕获和处理Q异常控制器紧接在try块后面,且用catch关键字标讎ͼ因此叫做“catch?#8221;。catch块可以有多个Q每一个用来处理一个相应的异常Q因为在“警戒?#8221;内可能发生的异常U类不止一个。所以,异常处理语句的一般格式是Q?br />try {
  // 可能产生异常的代?br />  }
 catch (异常对象 e) {
   //异常 e的处理语?br /> }catch (异常对象 e1) {
   //异常 e的处理语?br /> }catch (异常对象 e2) {
   //异常 e的处理语?br /> }

即不用try-catchl构Q发生异常时Java的异常控制机制也会捕莯异常Q输出异常的名称q从异常发生的位|打C个堆栈跟t。然后立即终止程序的q行。下面的例子发生了一?#8220;雉”异常Q后面的hello没有被打印?/font>

? 没有作异常控制的E序?/font>

///
public
class Exception1 {
   
public static void
main(String args[]) {
   
int
b = 0;
   
int
a = 3 / b;
   
System.out.println( "Hello!"
);
 
}
}
///

输出l果Q?br />java.lang.ArithmeticException: / by zero
at Exception1.main(Exception1.java:5)
Exception in thread "main" Exit code: 1
There were errors

但是如果使用了try-catch来处理异常,那么在打印出异常信息后,E序q将l箋q行下去。下面是处理了的代码?/font>

///
// Exception2.java

public
class Exception2 {
 
public static void
main(String args[]) {
   try
 

   
int b = 0;  
    int
a = 3 / b;
    }
   catch(ArithmeticException e) {
     e.printStackTrace
    }

   
System.out.println( "Hello!" );
 
}
}
///

输出l果Q?br />Exception:
java.lang.ArithmeticException: / by zero
   at Exception2.main(Exception1.java:5)
Hello!

与前例不同的是,Hello!被输Z。这是try-catchl构的用处,它异常发生和处理后E序得以“恢复”而不?#8220;中断”?/font>

2 异常cR异常规范和throw语句

Z使异常控制机制更地发挥它的功效,Java设计者几乎所以可能发生的异常Q预制了各色各样的异常类和错误类。它们都是从“可掷?#8221;cThrowablel承而来的,它派生出两个cError和Exception。由Errorz的子cd名ؓXXXErrorQ其中词XXX是描q错误类型的词。由Exceptionz的子cd名ؓXXXExceptionQ其中词XXX是描q异常类型的词。Errorcd理的是运行ɾpȝ发生的内部错误,是不可恢复的Q唯一的办法只要终止运行运行程序。因此,客户E序员只要掌握和处理好Exceptioncd可以了?br />ExceptioncL一切异常的栏V现成的异常c非怹多,我们不可能也没有必要全部掌握它。好在异常类的命名规则大致描q出了该cȝ用途,而异常类的方法基本是一L。下面给出lang包中声明的部分异常类?/font>

RuntimeException            q行时异?br />NullPointerException        数据没有初始化就使用
IndexOutOfBoundsException   数组或字W串索引界
NoSuchFieldException        文g找不?br />NoSuchMethodException       Ҏ没有定义
ArithmeticException         非法术q行

在其他包中也有相关的异常c,例如io包中有IOEceptioncR利用异常的命名规则Q你可以使用下面的DOS命o在包所在的目录查看有什么异常类可用Q?br />    DIR *Eception.class 
对于q行时异常RuntimeExceptionQ我们没必要专门为它写一个异常控制器Q因为它们是׃~程不严谨而造成的逻辑错误。只要让出现l止Q它会自动得到处理。需要程序员q行异常处理的是那些非运行期异常?br />Throwable有三个基本方法:

  • String getMessage()   获得详细的消息?

  • String toString()     q回Ҏcȝ一D늮要说明,其中包括详细的消息(如果有的话)?

  • void printStackTrace()  ?#160; void printStackTrace(PrintStream)
    打印用堆栈\径。调用堆栈显C出我们带到异常发生地点的Ҏ调用的顺序?

因ؓExceptioncL一切异常的根,所以对M一个现有的异常c都可以使用上述Ҏ?

异常规范 ?/strong> throws

java库程序员Z使客L序员准确地知道要~写什么代码来捕获所有潜在的异常Q采用一U叫做throws的语法结构。它用来通知那些要调用方法的客户E序员,他们可能从自qҎ?#8220;?#8221;Z么样的异常。这便是所谓的“异常规范”Q它属于Ҏ声明的一部分Q即在自变量Q参敎ͼ列表的后面加上throws 异常cd表。例?br />    void f() throws tooBig, tooSmall, divZero { Ҏ体}
若用下qC码:
    void f() [ // ...
它意味着不会从方法里“?#8221;出异常(除类型ؓRuntimeException的异总外,它可能从M地方掷出Q?br />如果一个方法用了异常规范Q我们在调用它时必须使用try-catchl构来捕获和处理异常规范所指示的异常,否则~译E序会报错而不能通过~译。这正是Java的异常控制机制的杰出贡献Q它对可能发生的意外及早预防从而加Z代码的健壮性?br />在用了异常规范的方法声明中Q库E序员用throw语句来掷Z个异常。throw语句的格式ؓQ?br />    thrownew XXXException();
由此可见Qthrow语句掷出的是XXXcd的异常的对象Q隐式的句柄Q。而catch控制器捕获对象时要给Z个句?catch(XXXException e)?br />我们也可以采?#8220;ƺ骗手段”Q用throw语句“?#8221;Z个ƈ没有发生的异常。编译器能理解我们的要求Qƈ使用q个Ҏ的用户当作真的生了那个异常处理。在实际应用中,可将其作为那个异常的一?#8220;占位W?#8221;使用。这样一来,以后可以方便C生实际的异常Q毋需修改现有的代码。下面我们用“ƺ骗手段”l出一个捕获异常的CZE序?/font>

? 本例E演C异常类的常用方法?/font>

///
public
class ExceptionMethods {
  publicstaticvoid main(String[] args) {
    try {
      thrownew Exception("Here's my Exception");
    } catch(Exception e) {
      System.out.println("Caught Exception");
      System.out.println(
        "e.getMessage(): " + e.getMessage());
      System.out.println(
        "e.toString(): " + e.toString());
      System.out.println("e.printStackTrace():");
      e.printStackTrace();
    }
  }
}
///

该程序输出如下:
Caught Exception
e.getMessage(): Here's my Exception
e.toString(): java.lang.Exception: Here's my Exception
e.printStackTrace():
java.lang.Exception: Here's my Exception
        at ExceptionMethods.main

在一个tryZ潜在的异常可能是多种cd的,那时我们需要用多个catch块来捕获和处理这些异常。但异常发生时掷Z某类异常对象QJava依次逐个查这些异常控制器Q发C掷出的异常类型匹配时执行那以段处理代码Q而其余的不会被执行。ؓ了防止可能遗漏了某一cd常控制器Q可以放|一个捕获Exceptioncȝ控制器。Exception是可以从McL法中“?#8221;出的基本cd。但是它必须攑֜最后一个位|,因ؓ它能够截获Q何异常,从而后面具体的异常控制器不v作用。下面的CZ说明了这一炏V?/font>

? 本例E演C多个异常控制器的排列次序的作用?/font>

///
public
class MutilCatch {
  private staticvoid test(int
i) {
    try
{
   
int
x = i;
   
if
(x>0)
     
throw new ArithmeticException ( "this is a Arithmetic Exception!"
);
   
else if
(x<0)
     
throw new NullPointerException ( "this is a NullPointer Exception!"
);
   
else
   
   throw new Exception( "this is a Exception!" );

   
} catch (ArithmeticException e) {
   
    
System.out.println(e.toString());
   
} catch
(NullPointerException e) {
   
    
System.out.println(e.toString());
   
} catch
(Exception e) {
   
    
System.out.println(e.toString());
   
}

  
}
  public
static void main(String[] args) {
   
test(-1); test(0); test(1);
 
}
 
}
///

q行l果Q?br />java.lang.NullPointerException: this is a NullPointer Exception!
java.lang.Exception: this is a Exception!
java.lang.ArithmeticException: this is a Arithmetic Exception!
如果你把捕获Exception的catch攑֜前面Q编译就通不q?/font>


3 用finally清理

我们l常会遇到这L情况Q无Z个异常是否发生,必须执行某些特定的代码。比如文件已l打开Q关闭文件是必须的。但是,在try区内位于异常发生点以后的代码Q在发生异常后不会被执行。在catchZ的代码在异常没有发生的情况下不会被执行。ؓ了无论异常是否发生都要执行的代码Q可在所有异常控制器的末用一个finally从句Q在finally块中攄q些代码。(但在恢复内存时一般都不需要,因ؓ垃圾攉器会自动照料一切。)所以完整的异常控制l构象下面这个样子:

try { 警戒区域 }
catch (A a1) { 控制?A }
catch (B b1) { 控制?B }
catch (C c1) { 控制?C }
finally { 必须执行的代码}

? 演示finally从句的程序?

///
// FinallyWorks.java

// The finally clause is always executed
public class FinallyWorks {
  staticint count = 0;
  publicstaticvoid main(String[] args) {
    while(true) {
      try {
        // post-increment is zero first time:
        if(count++ == 0)
          thrownew Exception();
        System.out.println("No exception");
      } catch(Exception e) {
        System.out.println("Exception thrown");
      } finally {
        System.out.println("in finally clause");
        if(count == 2) break; // out of "while"
      }
    }
  }
}
///

q行l果Q?br />Exception thrown
in finally clause
No exception
in finally clause
一开始count=0发生异常Q然后进入finally块;q入循环W二轮没有异常,但又执行一ơfinally块,q在其中跛_循环?br />下面我们l出一个有的实用但较ؓ复杂一点的E序。我们创Z一个InputFile的类。它的作用是打开一个文Ӟ然后每次d它的一行内宏V?/font>

? L本文件ƈ昄到屏q上?/font>

///
//: Cleanup.java

// Paying attention to exceptions in constructors
import java.io.*;

class InputFile {
  private BufferedReader in;
  InputFile(String fname) throws Exception {
    try {
      in = new BufferedReader(new FileReader(fname));
      // Other code that might throw exceptions
    } catch(FileNotFoundException e) {
      System.out.println("Could not open " + fname);
      // Wasn't open, so don't close it
      throw e;
    } catch(Exception e) {
      // All other exceptions must close it
      try {
        in.close();
      } catch(IOException e2) {
        System.out.println("in.close() unsuccessful");
      }
      throw e;
    } finally {
      // Don't close it here!!!
    }
  }
  String getLine() {
    String s;
    try {
      s = in.readLine();
    } catch(IOException e) {
      System.out.println("readLine() unsuccessful");
      s = "failed";
    }
    return s;
  }
  void cleanup() {
    try {
      in.close();
    } catch(IOException e2) {
      System.out.println("in.close() unsuccessful");
    }
  }
}
publicclass Cleanup {
  publicstaticvoid main(String[] args) {
    try {
      InputFile in = new InputFile("Cleanup.java");
      String s;
      int i = 1;
      while((s = in.getLine()) != null)
        System.out.println(""+ i++ + ": " + s);
      in.cleanup();
    } catch(Exception e) {
      System.out.println( "Caught in main, e.printStackTrace()");
      e.printStackTrace();
    }
  }
}
///

q行后输出的?行是Q?br />1: //: Cleanup.java
2: // Paying attention to exceptions in constructors
3: import java.io.*;

要说?InputFile的类包含一个构建器和两个方法cleanup和getLine。构建器要打开一个文件fnameQ首先要捕获FileNotFoundExceptioncd常。在它的处理代码中再掷出q个异常(throw e;)。在更高的控制器中试囑օ闭文Ӟq捕捉关闭失败的异常IOException。cleanup()关闭文gQgetLine()L件的一行到字符Ԍ它们都用了异常处理机制。Cleanup是主c,在main()中首先创Z个InputFilecd象,因ؓ它的构徏器声明时用了异常规范Q所以必ȝtry-catchl构来捕获异常?/font>

4 创徏自己的异常类

虽然Javacd提供了十分丰富的异常cdQ能够满绝大多数编E需要。但是,在开发较大的E序Ӟ也有可能需要徏立自q异常cR要创徏自己的异常类Q必M一个现有的异常cdl承——最好在含义上与新异常近伹{创Z个异常相当简单,只要按如下格式写两个构徏器就行:

class MyException extends Exception {
    public MyException() {}
    public MyException(String msg) {
    super(msg);
  }
}
q里的关键是“extends Exception”Q它的意思是Q除包括一个Exception的全部含义以外,q有更多的含义。增加的代码数量非常——实际只d了两个构建器Q对MyException的创建方式进行了定义。请CQ假如我们不明确调用一个基cL建器Q编译器会自动调用基c默认构建器。在W二个构建器中,通过使用super关键字,明确调用了带有一个String参数的基cL建器?/font>

? 本例E演C徏立和应用自己的异常类?/font>

///
//: Inheriting.java

// Inheriting your own exceptions
class MyException extends Exception {
  public MyException() {}
  public MyException(String msg) {
    super(msg);
  }
}
publicclass Inheriting {
  publicstaticvoid f() throws MyException {
    System.out.println(
      "Throwing MyException from f()");
    thrownew MyException();
  }
  publicstaticvoid g() throws MyException {
    System.out.println(
      "Throwing MyException from g()");
    thrownew MyException("Originated in g()");
  }
  publicstaticvoid main(String[] args) {
    try {
      f();
    } catch(MyException e) {
      e.printStackTrace();
    }
    try {
      g();
    } catch(MyException e) {
      e.printStackTrace();
    }
  }
}
/// 

输出l果Q?br />Throwing MyException from f()
MyException
at Inheriting.f(Inheriting.java:14)
at Inheriting.main(Inheriting.java:22)
Throwing MyException from g()
MyException: Originated in g()
at Inheriting.g(Inheriting.java:18)
at Inheriting.main(Inheriting.java:27)

创徏自己的异常时Q还可以采取更多的操作。我们可d额外的构建器及成员:

class MyException2 extends Exception {
  public MyException2() {}
  public MyException2(String msg) {
    super(msg);
  }
  public MyException2(String msg, int x) {
    super(msg);
    i = x;
  }
  public int val() { return i; }
  private int i;
}

本章结Q?/font>

  1. 应用异常控制机制q行异常处理的格式是
    try{要监控的代码} 
    catch(XXXException e) {异常处理代码} 
    finally {必须执行的代码} 
  2. 不知道有什么异常类好用时可查阅相关包中有哪些XXXException.class文g。而用Exception可捕获Q何异常?#160;
  3. 在方法声明中使用了throws关键字的必须q行异常控制Q否则会报编译错误?#160;
  4. 也可以创q异常cR?/font>


暗夜_ 2007-03-03 18:14 发表评论
]]>
java.util.Propertiesc?/title><link>http://m.tkk7.com/onejavaer/articles/101628.html</link><dc:creator>暗夜_</dc:creator><author>暗夜_</author><pubDate>Sat, 03 Mar 2007 08:18:00 GMT</pubDate><guid>http://m.tkk7.com/onejavaer/articles/101628.html</guid><wfw:comment>http://m.tkk7.com/onejavaer/comments/101628.html</wfw:comment><comments>http://m.tkk7.com/onejavaer/articles/101628.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://m.tkk7.com/onejavaer/comments/commentRss/101628.html</wfw:commentRss><trackback:ping>http://m.tkk7.com/onejavaer/services/trackbacks/101628.html</trackback:ping><description><![CDATA[ <p>Properties cd不是C西了Q它?Java ~程的早期就有了Qƈ且几乎没有什么变化。J2SE ?Tiger 版本增强了这个类Q不仅可以用它在单独一行中指定用等号分隔的多个?值对Q还可以用XML 文g装蝲和保存这些键-值对。在 驯服 Tiger的这一期文章中QJohn Zukowski 展示了如何驾驭这Ҏ一代的“彚w”。请在本文对应的讨论论坛上与作者及其他读者分享您Ҏ文的xQ您也可以单L章顶部或底部?讨论来访问该论坛Q?</p> <p>      J2SE 1.5 以前的版本要求直接?XML 解析器来装蝲配置文gq存储设|。虽然这q是一件困隄事情Qƈ且解析器是^台的标准部分Q但是额外的工作L有点让h烦。最q更新的 java.util.Properties cȝ在提供了一UؓE序装蝲和存储设|的更容易的ҎQ?loadFromXML(InputStream is) ?storeToXML(OutputStream os, String comment) Ҏ?</p> <p>Properties 基本知识<br />如果不熟?java.util.Properties c,那么现在告诉您它是用来在一个文件中存储?值对的,其中键和值是用等号分隔的Q如清单 1 所C?</p> <p>清单 1. 一l属性示?/p> <p>foo=bar<br />fu=baz</p> <p> </p> <p> <br />清?1 装蝲?Properties 对象中后Q您可以找C个键Q?foo ?fu Q和两个| foo ?bar ?fu ?baz Q了。这个类支持?\u 的嵌?Unicode 字符Ԍ但是q里重要的是每一内定w当作 String ?</p> <p>清单 2 昄了如何装载属性文件ƈ列出它当前的一l键和倹{只需传递这个文件的 InputStream l?load() ҎQ就会将每一个键-值对d?Properties 实例中。然后用 list() 列出所有属性或者用 getProperty() 获取单独的属性?</p> <p>清单 2. 装蝲属?/p> <p>import java.util.*;<br />import java.io.*;</p> <p>public class LoadSample {<br />  public static void main(String args[]) throws Exception {<br />    Properties prop = new Properties();<br />    FileInputStream fis = <br />      new FileInputStream("sample.properties");<br />    prop.load(fis);<br />    prop.list(System.out);<br />    System.out.println("\nThe foo property: " +<br />        prop.getProperty("foo"));<br />  }<br />}</p> <p> </p> <p> <br />q行 LoadSample E序生成如清?3 所C的输出。注?list() Ҏ的输Z?值对的顺序与它们在输入文件中的顺序不一栗?Properties cd一个散列表QhashtableQ事实上是一?Hashtable 子类Q中储存一l键-值对Q所以不能保证顺序?</p> <p>清单 3. LoadSample 的输?/p> <p>-- listing properties --<br />fu=baz<br />foo=bar</p> <p>The foo property: bar</p> <p> </p> <p> <br />XML 属性文?br />q里没有什么新内容?Properties cLLq样工作的。不q,新的地方是从一?XML 文g中装载一l属性。它?DTD 如清?4 所C?</p> <p>清单 4. 属?DTD</p> <p><?xml version="1.0" encoding="UTF-8"?><br /><!-- DTD for properties --><br /><!ELEMENT properties ( comment?, entry* ) ><br /><!ATTLIST properties version CDATA #FIXED "1.0"><br /><!ELEMENT comment (#PCDATA) ><br /><!ELEMENT entry (#PCDATA) ><br /><!ATTLIST entry key CDATA #REQUIRED></p> <p> </p> <p> <br />如果不想l读 XML DTDQ那么可以告诉您它其实就是说在外?<properties> 标签中包装的是一?<comment> 标签Q后面是L数量?<entry> 标签。对每一?<entry> 标签Q有一个键属性,输入的内容就是它的倹{清?5 昄?清单 1中的属性文件的 XML 版本是什么样子的?</p> <p>清单 5. XML 版本的属性文?/p> <p><?xml version="1.0" encoding="UTF-8"?><br /><!DOCTYPE properties SYSTEM "<a ><br /><properties><br /><comment>Hi</comment><br /><entry key="foo">bar</entry><br /><entry key="fu">baz</entry><br /></properties></p> <p> </p> <p> <br />如果清单 6 所C,d XML 版本?Properties 文g与读取老格式的文g没什么不同?</p> <p>清单 6. d XML Properties 文g</p> <p>import java.util.*;<br />import java.io.*;</p> <p>public class LoadSampleXML {<br />  public static void main(String args[]) throws Exception {<br />    Properties prop = new Properties();<br />    FileInputStream fis =<br />      new FileInputStream("sampleprops.xml");<br />    prop.loadFromXML(fis);<br />    prop.list(System.out);<br />    System.out.println("\nThe foo property: " +<br />        prop.getProperty("foo"));<br />  }<br />}</p> <p> </p> <p> <br />关于资源l定的说?br />虽然 java.util.Properties cȝ在除了支持键-值对Q还支持属性文件作?XML 文gQ不q的是,没有内置的选项可以?ResourceBundle 作ؓ一?XML 文g处理。是的, PropertyResourceBundle 不?Properties 对象来装载绑定,不过装蝲Ҏ的用是编码到cM的,而不使用较新?loadFromXML() Ҏ?</p> <p> <br />q行清单 6 中的E序产生与原来的E序相同的输出,?清单 2所C?</p> <p>保存 XML 属?br />新的 Properties q有一个功能是属性存储到 XML 格式的文件中。虽?store() Ҏ仍然会创Z个类?清单 1 所C的文gQ但是现在可以用新的 storeToXML() Ҏ创徏?清单 5 所C的文g。只要传递一?OutputStream 和一个用于注释的 String 可以了。清?7 展示了新?storeToXML() Ҏ?</p> <p>清单 7. ?Properties 存储?XML 文g</p> <p>import java.util.*;<br />import java.io.*;</p> <p>public class StoreXML {<br />  public static void main(String args[]) throws Exception {<br />    Properties prop = new Properties();<br />    prop.setProperty("one-two", "buckle my shoe");<br />    prop.setProperty("three-four", "shut the door");<br />    prop.setProperty("five-six", "pick up sticks");<br />    prop.setProperty("seven-eight", "lay them straight");<br />    prop.setProperty("nine-ten", "a big, fat hen");<br />    FileOutputStream fos =<br />      new FileOutputStream("rhyme.xml");<br />    prop.storeToXML(fos, "Rhyme");<br />    fos.close();<br />  }<br />}</p> <p> </p> <p> <br />q行清单 7 中的E序产生的输出如清单 8 所C?/p> <p>清单 8. 存储?XML 文g</p> <p><?xml version="1.0" encoding="UTF-8"?><br /><!DOCTYPE properties SYSTEM "<a ><br /><properties><br /><comment>Rhyme</comment><br /><entry key="seven-eight">lay them straight</entry><br /><entry key="five-six">pick up sticks</entry><br /><entry key="nine-ten">a big, fat hen</entry><br /><entry key="three-four">shut the door</entry><br /><entry key="one-two">buckle my shoe</entry><br /></properties></p> <p> </p> <p> <br />l束?br />使用 XML 文gq是使用老式?a=b cd的文件完全取决于您自己。老式文g从内存的角度看肯定是轻量U的。不q,׃ XML 的普遍用,Z会期?XML 格式行hQ因为它已经被广泛用了Q只不过没有用到 Properties 对象。选择完全在您。分析Y件包 private XMLUtils cȝ源代码以获得关于所使用?XML 解析的更多信息?/p> <p> </p> <p> </p> <p> </p> <p>PTest.java<br />import java.io.FileInputStream;<br />import java.io.IOException;<br />import java.io.InputStream;<br />import java.util.Properties;<br />/**<br /> * 实现properties文g的读?br /> * @author bbflyerwww<br /> * @date 2006-08-02<br /> */<br />public class PTest {<br />    public static void main(String[] args) {<br />        try {<br />            long start = System.currentTimeMillis();<br />            InputStream is = new FileInputStream("conf.properties");<br />            Properties p = new Properties();<br />            p.load(is);<br />            is.close();<br />            System.out.println("SIZE : " + p.size());<br />            System.out.println("homepage : " + p.getProperty("homepage"));<br />            System.out.println("author : " + p.getProperty("author"));<br />            System.out.println("school : " + p.getProperty("school"));<br />            System.out.println("date : " + p.getProperty("date"));<br />            long end = System.currentTimeMillis(); <br />            System.out.println("Cost : " + (end - start));<br />        } catch (IOException ioe) {<br />            ioe.printStackTrace();<br />        }<br />    }<br />}</p> <img src ="http://m.tkk7.com/onejavaer/aggbug/101628.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://m.tkk7.com/onejavaer/" target="_blank">暗夜_</a> 2007-03-03 16:18 <a href="http://m.tkk7.com/onejavaer/articles/101628.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Hibernate二~存http://m.tkk7.com/onejavaer/articles/101587.html暗夜_暗夜_Sat, 03 Mar 2007 02:16:00 GMThttp://m.tkk7.com/onejavaer/articles/101587.htmlhttp://m.tkk7.com/onejavaer/comments/101587.htmlhttp://m.tkk7.com/onejavaer/articles/101587.html#Feedback0http://m.tkk7.com/onejavaer/comments/commentRss/101587.htmlhttp://m.tkk7.com/onejavaer/services/trackbacks/101587.html2。一U缓存持久化的是OID唯一的对象,所以不会存在ƈ发访问的问题。二U缓存存在ƈ发访问问题。所以二U缓存根据访问和修改的频率以及是否集分?个等U。M上说Q一U缓存保存在内存中,二可以保存在内存或盘中,为散列保存?br />3。一U缓存ؓ必须的,二为可插入的缓存,其功能ؓW三Ҏ供?br />4。二U缓存保存的为很修改的对象Q因Z存在q发讉K问题Q所以尽量减对兑现的修Ҏ作,减少写入的脏数据?br />5。一U缓存ؓsession全程存在Q二U缓存可以设定过期时间?br />6。需要在hibernate.cfg.xml中设定用二U缓存。还需要在指定的映文件中Q设定需要被~存的实体对象?br />7。假如映文件对象所对应的属性ؓsetcdQ还需要再ơ指明被~存Q这样只会setcd的属性也是getItems()取出的被~存。而其所对应的实体ƈ未被~存Q如需要,需要在xml中指明?

暗夜_ 2007-03-03 10:16 发表评论
]]>
Java性能的优?/title><link>http://m.tkk7.com/onejavaer/articles/101545.html</link><dc:creator>暗夜_</dc:creator><author>暗夜_</author><pubDate>Fri, 02 Mar 2007 13:46:00 GMT</pubDate><guid>http://m.tkk7.com/onejavaer/articles/101545.html</guid><wfw:comment>http://m.tkk7.com/onejavaer/comments/101545.html</wfw:comment><comments>http://m.tkk7.com/onejavaer/articles/101545.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://m.tkk7.com/onejavaer/comments/commentRss/101545.html</wfw:commentRss><trackback:ping>http://m.tkk7.com/onejavaer/services/trackbacks/101545.html</trackback:ping><description><![CDATA[ <p style="FONT-WEIGHT: bold; FONT-SIZE: 26px">Java性能的优化(上)</p> <hr style="COLOR: #000000; HEIGHT: 1px" /> <p> </p> <div style="FONT-SIZE: 12px">黄伟?<br /><br /><br /><br /><br />Java在九十年代中期出C后,在赢得赞叹的同时Q也引来了一些批评。赢得的赞叹主要是Java的跨q_的操作性,x谓的”Write Once,Run Anywhere”.但由于Java的性能和运行效率同C相比Q仍然有很大的差距,从而引来了很多的批评?<br />对于服务器端的应用程序,׃不大涉及到界面设计和E序的频J重启,Java的性能问题看似不大明显Q从而一些Java的技术,如JSP,Se rvlet,EJB{在服务器端~程斚w得到了很大的应用Q但实际上,Java的性能问题在服务器端依然存在。下面我分四个斚w来讨论Java的性能和执行效率以及提高J ava性能的一些方法?<br />一Q关于性能的基本知?<br />1Q性能的定?<br />在我们讨论怎样提高Java的性能之前Q我们需要明?#8220;性能“的真正含义。我们一般定义如下五个方面作判性能的标准?<br />1Q?q算的性能----哪一个算法的执行性能最?<br />2Q?内存的分?---E序需要分配多内存,q行时的效率和性能最高?<br />3Q?启动的时?---E序启动需要多时间?<br />4Q?E序的可伸羃?----E序在用戯载过重的情况下的表现?<br />5Q?性能的认?-----用户怎样才能认识到程序的性能?<br />对于不同的应用程序,Ҏ能的要求也不同。例如,大部分的应用E序在启动时需要较长的旉Q从而对启动旉的要求有所降低Q服务器端的应用E序通常都分配有较大的内存空_所以对内存的要求也有所降低。但是,qƈ不是所q两斚w的性能可以被忽略。其ơ,法的性能对于那些把商务逻辑q用C务性操作的应用E序来讲非常重要。ȝ来讲Q对应用E序的要求将军_对各个性能的优先?<br />2Q怎样才能提高JAVA的性能 <br />提高JAVA的性能Q一般考虑如下的四个主要方面: <br />Q?Q?E序设计的方法和模式 <br />一个良好的设计能提高程序的性能Q这一点不仅适用于JAVAQ也适用也Q何的~程语言。因为它充分利用了各U资源,如内存,CPU,高速缓存,对象~冲池及多线E,从而设计出高性能和可伸羃性强的系l?<br />当然Qؓ了提高程序的性能而改变原来的设计是比较困隄Q但是,E序性能的重要性常常要高于设计上带来的变化。因此,在编E开始之前就应该有一个好的设计模型和Ҏ?<br />Q?Q?JAVA布v的环境?<br />JAVA布v的环境就是指用来解释和执行JAVA字节码的技术,一般有如下五种。即解释指o技?Interpreter Technology)Q及时编译的技?Just In Time Compilier Technology), 适应性优化技术(Adaptive Optimization TechnologyQ? 动态优化,提前~译为机器码的技术(Dynamic Optimization,Ahead Of Time TechnologyQ和~译为机器码的技术(Translator TechnologyQ? <br />q些技术一般都通过优化U程模型Q调整堆和栈的大来优化JAVA的性能。在考虑提高JAVA的性能Ӟ首先要找到媄响JAVA性能的瓶颈(B ottleNecksQ,在确认了设计的合理性后Q应该调整JAVA布v的环境,通过改变一些参数来提高JAVA应用E序的性能。具体内容见W二节?<br />Q?Q?JAVA应用E序的实?<br />当讨论应用程序的性能问题Ӟ大多数的E序员都会考虑E序的代码,q当然是对的Q当更重要的是要扑ֈ影响E序性能的瓶颈代码。ؓ了找到这些瓶颈代码,我们一般会使用一些辅助的工具Q如J probe,Optimizit,Vtune以及一些分析的工具如TowerJ Performance{。这些辅助的工具能跟t应用程序中执行每个函数或方法所消耗掉的时_从而改善程序的性能?<br />(4) g和操作系l?<br />Z提高JAVA应用E序的性能Q而采用跟快的CPU和更多的内存Qƈ认ؓq是提高E序性能的唯一ҎQ但事实q如此。实늻验和事实证明Q只有遭C应用E序性能的瓶颈,从而采取适当得方法,如设计模式,布v的环境,操作pȝ的调_才是最有效的?<br />3Q程序中通常的性能瓉?<br />所有的应用E序都存在性能瓉Qؓ了提高应用程序的性能Q就要尽可能的减程序的瓉。以下是在JAVAE序中经常存在的性能瓉?<br /><br /><br />了解了这些瓶颈后Q就可以有针Ҏ的减少q些瓉Q从而提高JAVA应用E序的性能 <br />4. 提高JAVAE序性能的步?<br />Z提高JAVAE序的性能Q需要遵循如下的六个步骤?<br />a) 明确Ҏ能的具体要?<br />在实施一个项目之前,必须要明该目对于E序性能的具体要求,如:q个应用E序要支?000个ƈ发的用户Qƈ且响应时间要?U钟之内。但同时也要明白对于性能的要求不应该同对E序的其他要求冲H?<br />b) 了解当前E序的性能 <br />你应该了解你的应用程序的性能同项目所要求性能之间的差距。通常的指标是单位旉内的处理数和响应旉Q有时还会比较CPU和内存的利用率?<br />c) 扑ֈE序的性能瓉 <br />Z发现E序中的性能瓉Q通常会用一些分析工P如:TowerJ Application Performance Analyzer或VTune来察看和分析E序堆栈中各个元素的消耗时_从而正的扑ֈq改正引h能降低的瓶颈代码,从而提高程序的性能。这些工兯能发现诸如过多的异常处理Q垃圑֛收等潜在的问题?<br />d) 采取适当的措施来提高性能 <br />扑ֈ了引L序性能降低的瓶颈代码后Q我们就可以用前面介l过的提高性能的四个方面,卌计模式,JAVA代码的实玎ͼ布vJAVA的环境和操作pȝ来提高应用程序的性能。具体内容将在下面的内容中作详细说明?<br />e) 只进行某一斚w的修Ҏ提高性能 <br />一ơ只改变可能引v性能降低的某一斚wQ然后观察程序的性能是否有所提高Q而不应该一ơ改变多个方面,因ؓq样你将不知道到底哪个方面的改变提高了程序的性能Q哪个方面没有,即不能知道程序瓶颈在哪?<br />f) q回到步骤c,l箋作类似的工作Q一直达到要求的性能为止?<br /><br />二. JAVA布v的环境和~译技?<br /> 开发JAVA应用E序Ӟ首先把JAVA的源E序~译Zq_无关的字节码。这些字节码可以被各种ZJVM的技术所执行。这些技术主要分Z个大cR即Z解释的技术和Z提前~译为本地码的技术。其C意囑֦下: <br /><br /><br />具体可分为如下的五类Q   <br />a) 解释指o技?<br />其结构图和执行过E如下: <br /><br /><br /> JAVA的编译器首先把JAVA源文件编译ؓ字节码。这些字节码对于JAVA虚拟?JVM)来讲是机器的指令码。然后,JAVA的解释器不断的@环取出字节码q行解释q执行?<br /> q样做的优点是可以实现JAVA语言的跨q_Q同时生成的字节码也比较紧凑。JAVA的一些优点,如安全性,动态性都得保持;但缺Ҏ省生成的字节码没有经q什么优化,同全部编译好的本地码相比Q速度比较慢?<br />b) 及时~译技术(Just In TimeQ?<br />  及时~译技术是Z解决指o解释技术效率比较低Q速度比较慢的情况下提出的Q其l构囑֦下所C?<br /><br /><br />其主要变化是在JAVAE序执行之前Q又JIT~译器把JAVA的字节码~译为机器码。从而在E序q行时直接执行机器码Q而不用对字节码进行解释。同时对代码也进行了部分的优化?<br />q样做的优点是大大提高了JAVAE序的性能。同Ӟ׃~译的结果ƈ不在E序q行间保存,因此也节U了存储I间了加载程序的旉Q缺Ҏ׃J IT~译器对所有的代码都想优化Q因此也费了很多的旉?<br />IBM和SUN公司都提供了相关的JIT产品?<br />c) 适应性优化技术(Adaptive Optimization TechnologyQ?<br />同JIT技术相比,适应性优化技术ƈ不对所有的字节码进行优化。它会跟t程序运行的成个q程Q从而发现需要优化的代码Q对代码q行动态的优化。对优化的代码,采取8 0/20的策略。从理论上讲Q程序运行的旉长Q代码就优化。其l构囑֦下: <br /><br /><br />其优Ҏ适应性优化技术充分利用了E序执行时的信息Q发行程序的性能瓉Q从而提高程序的性能Q其~点是在q行优化时可能会选择不当Q发而降低了E序的性能?<br />其主要品又IBM,SUN的HotSpot. <br />d) 动态优化,提前~译为机器码的技术(Dynamic Optimization,Ahead Of TimeQ?<br />动态优化技术充分利用了JAVA源码~译Q字节码~译Q动态编译和静态编译的技术。其输入时JAVA的原码或字节码,而输出是l过高度优化的可执行代码和个来动态库的؜? Window中是DLL文gQUNIX中是׃n?a .so文g)。其l构如下Q?<br /><br /><br />其优Ҏ能大大提高程序的性能Q缺Ҏ破坏了JAVA的可UL性,也对JAVA的安全带来了一定的隐患?<br /></div> <div style="FONT-SIZE: 12px"> <p style="FONT-WEIGHT: bold; FONT-SIZE: 26px">Java性能的优化(下)  </p> <hr style="COLOR: #000000; HEIGHT: 1px" /> <p> </p> <div style="FONT-SIZE: 12px">黄伟?<br /> <br /><br /><br /><br />三.优化JAVAE序设计和编码,提高JAVAE序性能的一些方法?<br />通过使用一些前面介l过的辅助性工h扑ֈE序中的瓉Q然后就可以对瓶颈部分的代码q行优化。一般有两种ҎQ即优化代码或更改设计方法。我们一般会选择后者,因ؓ不去调用以下代码要比调用一些优化的代码更能提高E序的性能。而一个设计良好的E序能够_代码Q从而提高性能?<br />下面提供一些在JAVAE序的设计和~码中,Z能够提高JAVAE序的性能Q而经帔R用的一些方法和技巧?<br />1Q对象的生成和大的调整?<br />JAVAE序设计中一个普遍的问题是没有好好的利用JAVA语言本n提供的函敎ͼ从而常怼生成大量的对象(或实例)。由于系l不仅要花时间生成对象,以后可能q需花时间对q些对象q行垃圾回收和处理。因此,生成q多的对象将会给E序的性能带来很大的媄响?<br />?Q关于String ,StringBufferQ?和append <br />JAVA语言提供了对于Stringcd变量的操作。但如果使用不当Q会l程序的性能带来影响。如下面的语句: <br />String name=new String(“HuangWeiFeng”); <br />System.out.println(name+”is my name”); <br />看似已经很精了,其实q如此。ؓ了生成二q制的代码,要进行如下的步骤和操作?<br />Q?Q?生成新的字符?new String(STR_1); <br />Q?Q?复制该字W串?<br />Q?Q?加蝲字符串常?#8221;HuangWeiFeng”(STR_2); <br />Q?Q?调用字符串的构架器(ConstructorQ? <br />Q?Q?保存该字W串到数l中Q从位置0开始) <br />Q?Q?从java.io.PrintStreamcM得到静态的out变量 <br />Q?Q?生成新的字符串缓冲变量new StringBuffer(STR_BUF_1); <br />Q?Q?复制该字W串~冲变量 <br />Q?Q?调用字符串缓冲的构架器(ConstructorQ? <br />Q?0Q?保存该字W串~冲到数l中Q从位置1开始) <br />Q?1Q?以STR_1为参敎ͼ调用字符串缓?StringBuffer)cM的appendҎ?<br />Q?2Q?加蝲字符串常?#8221;is my name”(STR_3); <br />Q?3Q?以STR_3为参敎ͼ调用字符串缓?StringBuffer)cM的appendҎ?<br />Q?4Q?对于STR_BUF_1执行toString命o?<br />Q?5Q?调用out变量中的printlnҎQ输出结果?<br />由此可以看出Q这两行单的代码Q就生成了STR_1,STR_2,STR_3,STR_4和STR_BUF_1五个对象变量。这些生成的cȝ实例一般都存放在堆中。堆要对所有类的超c,cȝ实例q行初始化,同时q要调用cL其每个超cȝ构架器。而这些操作都是非常消耗系l资源的。因此,对对象的生成q行限制Q是完全有必要的?<br />l修改,上面的代码可以用如下的代码来替换?<br />StringBuffer name=new StringBuffer(“HuangWeiFeng”); <br />System.out.println(name.append(“is my name.”).toString()); <br />pȝ进行如下的操作?<br />(1) 生成新的字符串缓冲变量new StringBuffer(STR_BUF_1); <br />(2) 复制该字W串~冲变量 <br />(3) 加蝲字符串常?#8221;HuangWeiFeng”(STR_1); <br />(4) 调用字符串缓冲的构架器(ConstructorQ? <br />(5) 保存该字W串~冲到数l中Q从位置1开始) <br />(6) 从java.io.PrintStreamcM得到静态的out变量 <br />(7) 加蝲STR_BUF_1; <br />(8) 加蝲字符串常?#8221;is my name”(STR_2); <br />(9) 以STR_2为参敎ͼ调用字符串缓?StringBuffer)实例中的appendҎ?<br />(10) 对于STR_BUF_1执行toString命o?STR_3) <br />(11)调用out变量中的printlnҎQ输出结果?<br />由此可以看出Q经q改q后的代码只生成了四个对象变量:STR_1,STR_2,STR_3和STR_BUF_1.你可能觉得少生成一个对象不会对E序的性能有很大的提高。但下面的代码段2 的执行速度是代码D??倍。因Z码段1生成了八个对象,而代码段2只生成了四个对象?<br />代码D?Q?<br />String name= new StringBuffer(“HuangWeiFeng”); <br />name+=”is my”; <br />name+=”name”; <br />代码D?Q?<br />StringBuffer name=new StringBuffer(“HuangWeiFeng”); <br />name.append(“is my”); <br />name.append(“name.”).toString(); <br />因此Q充分的利用JAVA提供的库函数来优化程序,Ҏ高JAVAE序的性能旉帔R要的.其注意点主要有如下几斚wQ?<br />Q?Q?可能的使用静态变量(Static Class VariablesQ?<br />如果cM的变量不会随他的实例而变化,可以定义ؓ静态变量,从而他所有的实例都共享这个变量?<br />例: <br />public class foo <br />{ <br />SomeObject so=new SomeObject(); <br />} <br />可以定义ؓQ?<br />public class foo <br />{ <br />static SomeObject so=new SomeObject(); <br />} <br />Q?Q?不要对已生成的对象作q多的改变?<br />对于一些类(如:Stringc?来讲Q宁愿在重新生成一个新的对象实例,而不应该修改已经生成的对象实例?<br />例: <br />String name=”Huang”; <br />name=”Wei”; <br />name=”Feng”; <br />上述代码生成了三个Stringcd的对象实例。而前两个马上需要系l进行垃圑֛收处理。如果要对字W串q行q接的操作,性能得更差。因为系l将不得为此生成更多得时变量。如上例1 所C?<br />Q?Q?生成对象Ӟ要分配给它合理的I间和大?<br />JAVA中的很多c都有它的默认的I间分配大小。对于StringBuffercLԌ默认的分配空间大是16个字W。如果在E序中用StringBu ffer的空间大不?6个字W,那么必进行正的初始化?<br />Q?Q?避免生成不太使用或生命周期短的对象或变量?<br />对于q种情况Q因该定义一个对象缓冲池。以为管理一个对象缓冲池的开销要比频繁的生成和回收对象的开销的多?<br />Q?Q?只在对象作用范围内进行初始化?<br />JAVA允许在代码的M地方定义和初始化对象。这P可以只在对象作用的范围内进行初始化。从而节U系l的开销?<br />例: <br />SomeObject so=new SomeObject(); <br />If(x==1) then <br />{ <br />Foo=so.getXX(); <br />} <br />可以修改为: <br />if(x==1) then <br />{ <br />SomeObject so=new SomeObject(); <br />Foo=so.getXX(); <br />} <br />2Q异?Exceptions) <br />JAVA语言中提供了try/catch来发方便用户捕捉异常Q进行异常的处理。但是如果用不当,也会lJAVAE序的性能带来影响。因此,要注意以下两炏V?<br />(1) 避免对应用程序的逻辑使用try/catch <br />如果可以用if,while{逻辑语句来处理,那么尽可能的不用try/catch语句 <br />(2) 重用异常 <br />在必要q行异常的处理时Q要可能的重用已经存在的异常对象。以为在异常的处理中Q生成一个异常对象要消耗掉大部分的旉?<br />3. U程(Threading) <br />一个高性能的应用程序中一般都会用到线E。因为线E能充分利用pȝ的资源。在其他U程因ؓ{待盘或网l读写?ӞE序能l处理和q行。但是对U程q用不当Q也会媄响程序的性能?<br />?Q正用Vectorc?<br />Vector主要用来保存各种cd的对象(包括相同cd和不同类型的对象Q。但是在一些情况下使用会给E序带来性能上的影响。这主要是由V ectorcȝ两个特点所军_的。第一QVector提供了线E的安全保护功能。即使VectorcM的许多方法同步。但是如果你已经认你的应用E序是单U程Q这些方法的同步完全不必要了。第二,在V ector查找存储的各U对象时Q常常要花很多的旉q行cd的匹配。而当q些对象都是同一cdӞq些匚w完全不必要了。因此,有必要设计一个单U程的,保存特定cd对象的类或集合来替代V ectorc?用来替换的程序如下(StringVector.javaQ: <br />public class StringVector <br />{ <br />private String [] data; <br />private int count; <br />public StringVector() { this(10); // default size is 10 } <br />public StringVector(int initialSize) <br />{ <br />data = new String[initialSize]; <br />} <br />public void add(String str) <br />{ <br />// ignore null strings <br />if(str == null) { return; } <br />ensureCapacity(count + 1); <br />data[count++] = str; <br />} <br /><br />private void ensureCapacity(int minCapacity) <br />{ <br />int oldCapacity = data.length; <br />if (minCapacity > oldCapacity) <br />{ <br />String oldData[] = data; <br />int newCapacity = oldCapacity * 2; <br />data = new String[newCapacity]; <br />System.arraycopy(oldData, 0, data, 0, count); <br />} <br />} <br />public void remove(String str) <br />{ <br />if(str == null) { return // ignore null str } <br />for(int i = 0; i < count; i++) <br />{ <br />// check for a match <br />if(data[i].equals(str)) <br />{ <br />System.arraycopy(data,i+1,data,i,count-1); // copy data <br />// allow previously valid array element be gc'd <br />data[--count] = null; <br />return; <br />} <br />} <br />} <br />public final String getStringAt(int index) { <br />if(index < 0) { return null; } <br />else if(index > count) <br />{ <br />return null; // index is > # strings <br />} <br />else { return data[index]; // index is good } <br />} <br />/* * * * * * * * * * * * * * * *StringVector.java * * * * * * * * * * * * * * * * */ <br />因此Q代码: <br />Vector Strings=new Vector(); <br />Strings.add(“One”); <br />Strings.add(“Two”); <br />String Second=(String)Strings.elementAt(1); <br />可以用如下的代码替换Q?<br />StringVector Strings=new StringVector(); <br />Strings.add(“One”); <br />Strings.add(“Two”); <br />String Second=Strings.getStringAt(1); <br />q样可以通过优化U程来提高JAVAE序的性能。用于测试的E序如下QTestCollection.javaQ? <br />import java.util.Vector; <br />public class TestCollection <br />{ <br />public static void main(String args []) <br />{ <br />TestCollection collect = new TestCollection(); <br />if(args.length == 0) <br />{ <br />System.out.println( <br />"Usage: java TestCollection [ vector | stringvector ]"); <br />System.exit(1); <br />} <br />if(args[0].equals("vector")) <br />{ <br />Vector store = new Vector(); <br />long start = System.currentTimeMillis(); <br />for(int i = 0; i < 1000000; i++) <br />{ <br />store.addElement("string"); <br />} <br />long finish = System.currentTimeMillis(); <br />System.out.println((finish-start)); <br />start = System.currentTimeMillis(); <br />for(int i = 0; i < 1000000; i++) <br />{ <br />String result = (String)store.elementAt(i); <br />} <br />finish = System.currentTimeMillis(); <br />System.out.println((finish-start)); <br />} <br />else if(args[0].equals("stringvector")) <br />{ <br />StringVector store = new StringVector(); <br />long start = System.currentTimeMillis(); <br />for(int i = 0; i < 1000000; i++) { store.add("string"); } <br />long finish = System.currentTimeMillis(); <br />System.out.println((finish-start)); <br />start = System.currentTimeMillis(); <br />for(int i = 0; i < 1000000; i++) { <br />String result = store.getStringAt(i); <br />} <br />finish = System.currentTimeMillis(); <br />System.out.println((finish-start)); <br />} <br />} <br />} <br />/* * * * * * * * * * * * * * * *TestCollection.java * * * * * * * * * * * * * * * * */ <br />试的结果如下(假设标准的时间ؓQ,小性能好Q: <br /><br /><br />关于U程的操作,要注意如下几个方面?<br />(1) 防止q多的同?<br />如上所C,不必要的同步常常会造成E序性能的下降。因此,如果E序是单U程Q则一定不要用同步?<br />(2) 同步Ҏ而不要同步整个代码段 <br />   Ҏ个方法或函数q行同步比对整个代码D进行同步的性能要好?<br />(3) Ҏ个对象用多”?#8221;的机制来增大q发?<br />一般每个对象都只有一?#8221;?#8221;Q这p明如果两个线E执行一个对象的两个不同的同步方法时Q会发生”死锁”。即使这两个Ҏq不׃nM资源。ؓ了避免这个问题,可以对一个对象实?#8221;多锁”的机制。如下所C: <br />class foo <br />{ <br />private static int var1; <br />private static Object lock1=new Object(); <br />private static int var2; <br />private static Object lock2=new Object(); <br />public static void increment1() <br />{ <br />synchronized(lock1) <br />{ <br />var1++; <br />} <br />} <br />public static void increment2() <br />{ <br />synchronized(lock2) <br />{ <br />var2++; <br />} <br />} <br />} <br />4Q输入和输出(I/O) <br />输入和输出包括很多方面,但涉及最多的是对盘Q网l或数据库的d操作。对于读写操作,又分为有~存和没有缓存的Q对于数据库的操作,又可以有多种cd的J DBC驱动器可以选择。但无论怎样Q都会给E序的性能带来影响。因此,需要注意如下几点: <br />(1) 使用输入输出~冲 <br />   可能的多用缓存。但如果要经常对~存q行hQflushQ?则徏议不要用缓存?<br />(2) 输出?Output Stream)和Unicode字符?<br />   当时用Output Stream和Unicode字符串时QWritecȝ开销比较大。因为它要实现Unicode到字?byte)的{?因此Q如果可能的?在用WritecM前就实现转换或用O utputStreamcM替WritercL使用?<br />(3) 当需序列化时使用transient <br />   当序列化一个类或对象时Q对于那些原子类型(atomicQ或可以重徏的原素要表识为transientcd。这样就不用每一ơ都q行序列化。如果这些序列化的对象要在网l上传输Q这一小的改变对性能会有很大的提高。   <br />(4) 使用高速缓存(CacheQ?<br />   对于那些l常要用而又不大变化的对象或数据Q可以把它存储在高速缓存中。这样就可以提高讉K的速度。这一点对于从数据库中q回的结果集其重要?<br />(5) 使用速度快的JDBC驱动器(DriverQ?<br />   JAVA对访问数据库提供了四U方法。这其中有两U是JDBC驱动器。一U是用JAVA外包的本地驱动器Q另一U是完全的JAVA驱动器。具体要使用哪一U得ҎJ AVA布v的环境和应用E序本n来定?<br />5.一些其他的l验和技?<br />(1) 使用局部变?<br />(2) 避免在同一个类中动q调用函数或Ҏ(get或set)来设|或调用变量?<br />(3) 避免在@环中生成同一个变量或调用同一个函敎ͼ参数变量也一P <br />(4) 可能的使用static,final,private{关键字 <br />(5) 当复制大量数据时Q用System.arraycopy()命o?<br /><br /></div> <p> </p> <hr style="COLOR: #000000; HEIGHT: 1px" /> </div> <img src ="http://m.tkk7.com/onejavaer/aggbug/101545.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://m.tkk7.com/onejavaer/" target="_blank">暗夜_</a> 2007-03-02 21:46 <a href="http://m.tkk7.com/onejavaer/articles/101545.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>equals() ?hashCode() http://m.tkk7.com/onejavaer/articles/101536.html暗夜_暗夜_Fri, 02 Mar 2007 11:41:00 GMThttp://m.tkk7.com/onejavaer/articles/101536.htmlhttp://m.tkk7.com/onejavaer/comments/101536.htmlhttp://m.tkk7.com/onejavaer/articles/101536.html#Feedback2http://m.tkk7.com/onejavaer/comments/commentRss/101536.htmlhttp://m.tkk7.com/onejavaer/services/trackbacks/101536.html 我们知道Qequals()函数是用来做比较的。java中的比较有两U:一U是内存地址的比较,一U是内容的比较。而比较个体也有两U:一U是单类型(q类单说来无所谓内存地址的比较或者内Ҏ较的区别Q;q有一U是对象的比较,本文中说的主要是后?/p>

在java中,Q对象)内存地址的比较,是通过==完成的。比?#160;

if (obj1  ==  obj2) {
    ...
}

q样的语句中Q我们认为,如果obj1和obj2的内存地址相同Q则q回true

而equals()通常是比较内容的。这里说“通常” Q是因ؓ在最Ҏ的ObjectcMQequal()函数做的是地址的比较。而在其他几乎所有的cMQequals()都经q重载,q行内容的比较?/p>

而在说equals()的时候我们还涉及hashCode()是因为在有些应用中(比如QHashMap的key是对象)Q必d重蝲equals()的同旉载hashCode()?strong>因ؓjava中默?Object)的hashCode是根据对象的地址计算得到的?/strong>

我们通常不会注意到这个问题,因ؓ我们通常所使用?em>key都是单类型,或者是String, Long{一些特D的对象Q其Ҏ性请参看W者在写java 拷贝和深拷贝时的讨论)Q这时候,q个问题被我们无意间l过?/p>

有h已经概括了这U我们忽略了的情况:“如果你想一个对象A攑օ另一个收集(集合Q对象B里,或者用这个对象A为查找一个元对象在收集对 象B里位|的钥匙QkeyQ,q支持是否容UIisContains()Q,删除攉对象B里的元对象(remove()?Q这L操作Q那么,equals()和hashCode()函数必须开发者自己定义?#8221; Q括号ؓW者添加)

Z便于理解QD一D늨序ؓ例:

import  java.util. * ;
public   class  Person {

int  id;
String name;

// define getter and setter here, omited

public  Person( int  id, String name) {
     
this .id  =  id;
     
this .name  =  name;
     
}


public   boolean  equals(Object o) {
       
if ( this == o)  return   true ;
    
if (o  instanceof  Person)
    
return  ( this .id  ==  ((Person)o).id)  &&  ( this .name.equals(((Person)o).name));
    }


/*          
public int hashCode(){
    return id*37;
}
*/


public   static   void  main(String args[])  {
    Person p1 
=   new  Person( 1 , " aaa " );
    Person p2 
=   new  Person( 1 , " aaa " );
    Map map 
=   new  HashMap();

    map.put(p2,p1);
    Person value 
=  (Person)map.get(p1);
    System.out.println(value.name);
  }

}

q段代码的结果是什么?{案是nullPointerExcetpion.

而把hashCode()的注释去除,E序可以返回正的l果了。ؓ什么呢Q因为:

Map.put(key,value)时根据key.hashCode生成一个内部hash|Ҏq个hash值将对象存放在一个table?/p>

Map.get(key)会比较key.hashCode和equalsҎQ当且仅当这两者相{时Q才能正定位到table。而我们说q,默认的java是对地址q行比较的?/p>

暗夜_ 2007-03-02 19:41 发表评论
]]>
JAVA正则表达?-Pattern和Matcherhttp://m.tkk7.com/onejavaer/articles/101126.html暗夜_暗夜_Wed, 28 Feb 2007 05:47:00 GMThttp://m.tkk7.com/onejavaer/articles/101126.htmlhttp://m.tkk7.com/onejavaer/comments/101126.htmlhttp://m.tkk7.com/onejavaer/articles/101126.html#Feedback0http://m.tkk7.com/onejavaer/comments/commentRss/101126.htmlhttp://m.tkk7.com/onejavaer/services/trackbacks/101126.html现在JDK1.4里终于有了自q正则表达式API包,JAVAE序员可以免LW三Ҏ供的正则表达式库的周折了Q我们现在就马上来了解一下这个SUN提供?#173;q来恩物-
-Ҏ来说实如此?
1.介:
java.util.regex是一?b style="COLOR: black; BACKGROUND-COLOR: #99ff99">?/b>正则表达式所订制的模式来对字W串q行匚w工作的类库包?

它包括两个类QPattern和Matcher Pattern
一个Pattern是一个正则表辑ּl编译后的表现模式?
Matcher
一个Matcher对象是一个状态机器,它依据Pattern对象做ؓ匚w模式对字W串展开匚w查?

首先一个Pattern实例订制了一个所用语法与PERL的类似的正则表达式经~译后的模式Q然后一个Matcher实例在这个给定的Pattern实例的模?#173;控制下进行字W串的匹配工作?

以下我们分别来看看q两个类Q?

2.Patternc?
Pattern的方法如下: static Pattern compile(String regex)
给定的正则表达式编译ƈ赋予lPatternc?
static Pattern compile(String regex, int flags)
同上Q但增加flag参数的指定,可选的flag参数包括QCASE
INSENSITIVE,MULTILINE,DOTALL,UNICODE CASEQ?CANON EQ
int flags()
q回当前Pattern的匹配flag参数.
Matcher matcher(CharSequence input)
生成一个给定命名的Matcher对象
static boolean matches(String regex, CharSequence input)
~译l定的正则表辑ּq且对输入的字串以该正则表达式ؓ模开展匹?该方法适合于该正则表达式只会用一ơ的情况Q也是只进行一ơ匹配工作,因ؓq种情况下ƈ­不需要生成一个Matcher实例?

String pattern()
q回该Patter对象所~译的正则表辑ּ?
String[] split(CharSequence input)
目标字W串按照Pattern里所包含的正则表辑ּ为模q行分割?

String[] split(CharSequence input, int limit)
作用同上Q增加参数limit目的在于要指定分割的D|Q如limi设ؓ2Q那么目标字W串根据正则表辑ּ分ؓ割ؓ两段?

一个正则表辑ּQ也是一串有特定意义的字W,必须首先要编译成Z个Patterncȝ实例Q这个Pattern对象会使用matcher()Ҏ来生成一­个Matcher实例Q接着便可以用该
Matcher实例以编译的正则表达式ؓ基础对目标字W串q行匚w工作Q多个Matcher是可以共用一个Pattern对象的?

现在我们先来看一个简单的例子Q再通过分析它来了解怎样生成一个Pattern对象q且~译一个正则表辑ּQ最后根据这个正则表辑ּ目标字W串q行分割Q?

import java.util.regex.*;
public class Replacement{
public static void main(String[] args) throws Exception {
// 生成一个Pattern,同时~译一个正则表辑ּ
Pattern p = Pattern.compile("[/]+");
//?/b>Pattern的split()Ҏ把字W串?/"分割
String[] result = p.split(
"Kevin has seen《LEON》seveal times,because it is a good film."
+"/
凯文已经看过《这个杀手不太冷》几ơ了Q因为它是一?
+"好电影?名词:凯文?);
for (int i=0; i<result.length; i++)
System.out.println(result[i]);

}
}

输出l果为:

Kevin has seen《LEON》seveal times,because it is a good film.
凯文已经看过《这个杀手不太冷》几ơ了Q因为它是一部好电媄?
名词:凯文?

很明显,该程序将字符串按"/"q行了分D,我们以下再?
split(CharSequence input, int
limit)Ҏ来指定分D늚D|Q程序改动ؓQ?
tring[] result = p.split("Kevin has seen《LEON》seveal times,because
it is a good film./
凯文已经看过《这个杀手不太冷》几ơ了Q因为它是一部好电媄?名词:凯文?Q?);

q里面的参数"2"表明目标语句分ZDc?

输出l果则ؓQ?

Kevin has seen《LEON》seveal times,because it is a good film.
凯文已经看过《这个杀手不太冷》几ơ了Q因为它是一部好电媄?名词:凯文?

׃面的例子Q我们可以比较出java.util.regex包在构造Pattern对象以及~译指定的正则表辑ּ的实现手法与我们在上一中所介绍的Jaka­rta-ORO
包在完成同样工作时的差别Q?b style="COLOR: black; BACKGROUND-COLOR: #ffff66">Jakarta
-ORO
包要先构造一个PatternCompilercd象接着生成一个Pattern对象Q再正则表辑ּ?/b>该PatternCompilercȝcompile(­)Ҏ来将所需的正则表辑ּ~译赋予Patternc:

PatternCompiler orocom=new Perl5Compiler();

Pattern pattern=orocom.compile("REGULAR EXPRESSIONS");

PatternMatcher matcher=new Perl5Matcher();

但是在java.util.regex包里Q我们仅需生成一个Patternc,直接使用它的compile()Ҏ可以达到同L效果:
Pattern p = Pattern.compile("[/]+");

因此gjava.util.regex的构造法?b style="COLOR: black; BACKGROUND-COLOR: #ffff66">Jakarta-ORO更ؓzƈҎ理解?

3.Matcherc?
MatcherҎ如下Q?Matcher appendReplacement(StringBuffer sb,
String replacement)
当前匹配子串替换ؓ指定字符Ԍq且替换后的子串以及其之前Cơ匹配子串之后的字符串段dC个StringBuffer对象里?

StringBuffer appendTail(StringBuffer sb)
最后一ơ匹配工作后剩余的字W串dC个StringBuffer对象里?

int end()
q回当前匚w的子串的最后一个字W在原目标字W串中的索引位置
?
int end(int group)
q回与匹配模式里指定的组相匹配的子串最后一个字W的位置?

boolean find()
试在目标字W串里查找下一个匹配子丌Ӏ?
boolean find(int start)
重设Matcher对象Qƈ且尝试在目标字符串里从指定的位置开始查找下一个匹配的子串?

String group()
q回当前查找而获得的与组匚w的所有子串内?
String group(int group)
q回当前查找而获得的与指定的l匹配的子串内容
int groupCount()
q回当前查找所获得的匹配组的数量?
boolean lookingAt()
目标字W串是否以匹配的子串起始?
boolean matches()
试Ҏ个目标字W展开匚w,也就是只有整个目标字W串完全匚w时才q回真倹{?

Pattern pattern()
q回该Matcher对象的现有匹配模式,也就是对应的Pattern
对象?
String replaceAll(String replacement)
目标字W串里与既有模式相匹配的子串全部替换为指定的字符丌Ӏ?

String replaceFirst(String replacement)
目标字W串里第一个与既有模式相匹配的子串替换为指定的字符丌Ӏ?

Matcher reset()
重设该Matcher对象?
Matcher reset(CharSequence input)
重设该Matcher对象q且指定一个新的目标字W串?
int start()
q回当前查找所获子串的开始字W在原目标字W串中的位置?

int start(int group)
q回当前查找所获得的和指定l匹配的子串的第一个字W在原目标字W串中的位置?

Q光看方法的解释是不是很不好理解Q不要急,待会l合例子比较容易明白了Q?

一个Matcher实例是被用来对目标字W串q行Z既有模式Q也是一个给定的Pattern所~译的正则表辑ּQ进行匹配查扄Q所有往Matcher的输­入都是通过CharSequence接口提供的,q样做的目的在于可以支持对从多元化的数据源所提供的数据进行匹配工作?

我们分别来看看各Ҏ的用:

★matches()/lookingAt ()/find()Q?
一个Matcher对象是由一个Pattern对象调用其matcher()Ҏ而生成的Q一旦该Matcher对象生成,它就可以q行三种不同的匹配查找操?#173;Q?

matches()Ҏ试Ҏ个目标字W展开匚w,也就是只有整个目标字W串完全匚w时才q回真倹{?

lookingAt
()Ҏ检目标字W串是否以匹配的子串起始?
find()Ҏ试在目标字W串里查找下一个匹配子丌Ӏ?

以上三个Ҏ都将q回一个布值来表明成功与否?

★replaceAll ()/appendReplacement()/appendTail()Q?
Matchercd时提供了四个匹配子串替换成指定字符串的ҎQ?

replaceAll()
replaceFirst()
appendReplacement()
appendTail()

replaceAll()与replaceFirst()的用法都比较单,L上面Ҏ的解释。我们主要重点了解一下appendReplacement()­和appendTail()Ҏ?

appendReplacement(StringBuffer sb, String replacement)
当前匹配子串替换ؓ指定字符Ԍq且替换后的子串以及其之前Cơ匹配子串之后的字符串段dC个StringBuffer对象里,而appendTai­l(StringBuffer
sb)
Ҏ则将最后一ơ匹配工作后剩余的字W串dC个StringBuffer对象里?

例如Q有字符串fatcatfatcatfat,假设既有正则表达式模式ؓ"cat"Q第一ơ匹配后调用appendReplacement(sb,"dog"­),那么q时StringBuffer
sb的内容ؓfatdogQ也是fatcat中的cat被替换ؓdogq且与匹配子串前的内容加到sb里,而第二次匚w后调用appendReplaceme­nt(sb,"dog")Q那么sb的内容就变ؓfatdogfatdogQ如果最后再调用一ơappendTailQsbQ?那么sb最l的内容是fatd­ogfatdogfat?

q是有点模糊Q那么我们来看个单的E序Q?
//该例把句子里的"Kelvin"改ؓ"Kevin"
import java.util.regex.*;
public class MatcherTest{
public static void main(String[] args)
throws Exception {
//生成Pattern对象q且~译一个简单的正则表达?Kelvin"
Pattern p = Pattern.compile("Kevin");
//?/b>Patterncȝmatcher()Ҏ生成一个Matcher对象
Matcher m = p.matcher("Kelvin Li and Kelvin Chan are both working in
Kelvin Chen's KelvinSoftShop company");
StringBuffer sb = new StringBuffer();
int i=0;
//使用find()Ҏ查找W一个匹配的对象
boolean result = m.find();
//使用循环句子里所有的kelvin扑ևq替换再内容加到sb?
while(result) {
i++;
m.appendReplacement(sb, "Kevin");
System.out.println("W?+i+"ơ匹配后sb的内ҎQ?+sb);
//l箋查找下一个匹配对?
result = m.find();

}

//最后调用appendTail()Ҏ最后一ơ匹配后的剩余字W串加到sb里;
m.appendTail(sb);
System.out.println("调用m.appendTail(sb)后sb的最l内Ҏ:"+
sb.toString());

}
}

最l输出结果ؓQ?
W?ơ匹配后sb的内ҎQKevin
W?ơ匹配后sb的内ҎQKevin Li and Kevin
W?ơ匹配后sb的内ҎQKevin Li and Kevin Chan are both
working in Kevin
W?ơ匹配后sb的内ҎQKevin Li and Kevin Chan are both
working in Kevin Chen's Kevin
调用m.appendTail(sb)后sb的最l内ҎQKevin Li and Kevin Chan
are both working in Kevin Chen's KevinSoftShop company.

看了上面q个例程是否对appendReplacement()QappendTail()两个Ҏ的用更清楚呢,如果q是不太肯定最好自己动手写几行代码?#173;试一下?

★group()/group(int group)/groupCount()Q?
该系列方法与我们在上介l的Jakarta-ORO中的MatchResult
.group()ҎcM(有关Jakarta-ORO请参考上的内容)Q都是要q回与组匚w的子串内容,下面代码很好解释其用法Q?

import java.util.regex.*;

public class GroupTest{
public static void main(String[] args)
throws Exception {
Pattern p = Pattern.compile("(ca)(t)");
Matcher m = p.matcher("one cat,two cats in the yard");
StringBuffer sb = new StringBuffer();
boolean result = m.find();
System.out.println("该次查找获得匚wl的数量为:"+m.groupCount());
for(int i=1;i<=m

}
}

输出为:
该次查找获得匚wl的数量为:2
W?l的子串内容为:ca
W?l的子串内容为:t

Matcher对象的其他方法因比较好理解且׃幅有限Q请读者自qE验证?

4Q一个检验Email地址的小E序Q?
最后我们来看一个检验Email地址的例E,该程序是用来验一个输入的EMAIL地址里所包含的字W是否合法,虽然q不是一个完整的EMAIL地址验程序,­它不能检验所有可能出现的情况Q但在必要时您可以在其基上增加所需功能?

import java.util.regex.*;
public class Email {
public static void main(String[] args) throws Exception {
String input = args[0];
//输入的EMAIL地址是否?
非法W号"."?@"作ؓ起始字符
Pattern p = Pattern.compile("^\.|^\@");
Matcher m = p.matcher(input);
if (m
//是否以"www."v?
p = Pattern.compile("^www\.");
m = p.matcher(input);
if (m
//是否包含非法字W?
p = Pattern.compile("[^A-Za-z0-9\.\@_\-~#]+");
m = p.matcher(input);
StringBuffer sb = new StringBuffer();
boolean result = m.find();
boolean deletedIllegalChars = false;
while(result) {
//如果扑ֈ了非法字W那么就设下标记
deletedIllegalChars = true;
//如果里面包含非法字符如冒号双引号{,那么把他们消去Q加到SB里面
m.appendReplacement(sb, "");
result = m.find();

}

m.appendTail(sb);
input = sb.toString();
if (deletedIllegalChars) {
System.out.println("输入的EMAIL地址里包含有冒号、逗号{非法字W,请修?);
System.out.println("您现在的输入? "+args[0]);
System.out.println("修改后合法的地址应类? "+input);

}
}
}

例如Q我们在命o行输入:java Email www.ke...@163.net

那么输出l果会是:EMAIL地址不能?www.'起始

如果输入的EMAIL为@k...@163.net

则输ZؓQEMAIL地址不能?.'?@'作ؓ起始字符

当输入ؓQcgjmail...@163.net

那么输出是Q?

输入的EMAIL地址里包含有冒号、逗号{非法字W,请修?
您现在的输入? cgjmail...@163.net
修改后合法的地址应类? cgjm...@163.net

5QȝQ?
本文介绍了jdk1.4.0-beta3里正则表辑ּ?-java.util.regex中的cM及其ҎQ如果结合与上一中所介绍?b style="COLOR: black; BACKGROUND-COLOR: #ffff66">Jakarta
-OR­O
API作比较,读者会更容易掌握该API的用,当然该库的性能在未来的日子里不断扩展Q希望获得最C息的读者最好到及时到SUN的网站去了解?

6Q结束语Q?
本来计划再多写一介l一下需付费的正则表辑ּ库中较具代表性的作品Q但觉得既然有了免费且优U的正则表辑ּ库可以用,何必q要L需付费的呢Q相信很多读?#173;也是q么想的:Q所以有兴趣了解更多其他的第三方正则表达式库的朋友可以自己到|上查找或者到我在参考资料里提供的网址ȝ看?

参考资?

java.util.regex的帮助文?
Dana Nourie 和Mike McCloskey所写的Regular Expressions and the
Java™ Programming Language
需要更多的W三Ҏ则表辑ּ资源以及Z它们所开发的应用E序Lhttp://www.meurrens.org/ip-Links/java/regex/index.html

关于作?
陈广?Kevin
Chen,汕头大学电子信息工程pdU学士,台湾大新出版C区开发部Q现正围l中日韩电子资料使用JAVA开发电子词典等相关目。可通过E-mail:c­gjm...@163.net于他联系?/p>

暗夜_ 2007-02-28 13:47 发表评论
]]>
整清 java 中的 cR抽象类、接口、ѝ对?/title><link>http://m.tkk7.com/onejavaer/articles/100858.html</link><dc:creator>暗夜_</dc:creator><author>暗夜_</author><pubDate>Tue, 27 Feb 2007 01:43:00 GMT</pubDate><guid>http://m.tkk7.com/onejavaer/articles/100858.html</guid><wfw:comment>http://m.tkk7.com/onejavaer/comments/100858.html</wfw:comment><comments>http://m.tkk7.com/onejavaer/articles/100858.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://m.tkk7.com/onejavaer/comments/commentRss/100858.html</wfw:commentRss><trackback:ping>http://m.tkk7.com/onejavaer/services/trackbacks/100858.html</trackback:ping><description><![CDATA[ <p> <font color="#a52a2a"> <font color="#006400">本文以一条龙的Ş式一ơ性解决问题?/font> <br /> <br />cLq泛的概念,表示一个有共同性质的群体。如QhcR?br /><br />代码Q?br />      <font color="#a52a2a"> // 声明一个类“Human”</font><font color="#000000"><br />       <font size="2">     <strong>class Human{<br />            private String name;<br />            public String getName(){<br />                               return name;<br />                                              }<br />           public void setName(String value){<br />                                         this.name = value;<br />                                                  }<br />                                  //......<br />                               }</strong></font></font><br /><br /><font color="#a52a2a">对象指的是具体的一个实实在在的东西。如、张三、李四?br /></font><br />代码Q?br />       <font color="#000000">                </font><font color="#a52a2a">   <strong><font color="#000000" size="2">Human zhangsan = new Human();</font></strong><br /><br /></font>图:<br />     <img title="ren" height="308" alt="?png" src="http://m.tkk7.com/images/blogjava_net/lusm/?png" width="576" border="0" /><br /><br />图中我们怎么创徏张三和李四呢Q?我们前面的代码好像还没涉及,恩好Q看下面<br /><font color="#000000"><br /><font size="2"><strong>Human human = new Human();</strong><br /></font><br /><font color="#a52a2a">E序执行到这里之后,java虚拟机将会在内存中创Z?#160;Human 对象Qƈ这个对象的引用赋给 human 变量?/font><br /></font><br />接着Q?font color="#000000"><strong><font size="2">human.setName("张三"); human.setName("李四");</font></strong><font color="#a52a2a">好了对象Q实例)创徏好了Q呵?/font>Q?br /><br /><font color="#a52a2a">图:<br /></font>      <img title="?" height="280" alt="?.png" src="http://m.tkk7.com/images/blogjava_net/lusm/?.png" width="564" border="0" /><br /></font><br /><font color="#a52a2a">“?#8221;是一?font color="#ff0000">基类</font>Q则“男h”?#8220;?#8221;的一?font color="#ff0000">子类</font>。如?#8220;张三”是一?#8220;男h”Q也是?#8220;张三”?#8220;男h”的一个对象,那么昄“张三”也是“?#8221;q个基类的一个对象?br /></font>   <strong><font color="#000000"></font></strong><strong><font color="#000000" size="2">class nanren extends  human(String args[ ]){<br />           //.............<br />        }</font></strong><br /><br />Ҏ是类的行为,如h会笑、会坐、会走\ 一栗?br /><br />图:<br />      <img title="?" height="280" alt="?.png" src="http://m.tkk7.com/images/blogjava_net/lusm/?.png" width="564" border="0" /><br />        <br /> </font> <font color="#a52a2a">代码Q?br /></font> <font color="#a52a2a">        <font size="2">   <strong><font color="#000000">zhangsan.go();zhangsan.xiao();zhangsan.shuijiao();zhangsan.qita();</font></strong></font><br /><br /><font color="#000000"><font color="#a52a2a">接口只定义了一些方法,而没有实现这些方法,它规定了实现接口的类必须具备的方法(能力Q,<font color="#ff0000">它只是一个规?/font>?/font><br /></font><br />我们规定Q只要是人就可以走\、笑、睡觉、做其他的事Q于是我们用代码实现q个规定<br /><font color="#000000"><strong><font size="2">public interface you_are_human{<br />public void go();<br />public void xiao();<br />public void shuijiao();<br />public void qita();<br />}</font></strong><br /><font color="#a52a2a">q时Q张三想做hQ但他只x有走路和W的能力。首先,他必d明自己是人,也就是前面对人的规定Q?br />然后惛_什么由他自己决定:<br /><br /></font><strong><font size="2">public class zhangsan extends Human implements you_are_human{<br />public void go(){<br />// ......<br />}<br />public void xiao(){<br />// ......<br />}<br />}</font></strong></font><br />使用的时候:<br /><font color="#000000" size="2"><strong>you_are_human  zhangsan = new you_are_human();<br /><br /></strong></font></font> <strong> <font size="2">zhangsan.go();<br /><br />zhangsan.xiao();</font> </strong> <font color="#a52a2a"> <br /> <br />那有的h׃问,q和前面我定义类有什么区别;<br /><br />q是因ؓQjava的类的承是从上C的,L1 》老爸1 》儿?</font> </p> <p> <font color="#a52a2a">                                                                      L2   》老爸2  ?#160;儿子2<br />     而不能是Q爷?  ?#160;儿子1<br /><br />q样׃ؕ套了 Q是不,闹笑话;所以,c规定了不承关p,防止乱套Qɾl构变得清晰?br /><br />所以,当我们用树型结构时Q用类?br /><br /><br /></font> </p> <p> <font color="#a52a2a">׃Q在生活中还有许多这L情况Q如Q张三是中国人,那张三他也是国人双重n份?br />                    <br />                                                                   再如Q李四是java工程?也是厨师?br />那怎么办?Q?br /><br />我们可以q么做:<br /></font> <font color="#a52a2a">规定多个w䆾</font> <font color="#a52a2a"> <font color="#000000"> <strong> <br /> <font size="2">public interface zhengjian{<br />interface China(){<br />public void China_L(){<br />//.................<br />                             }<br />                           }<br />interface  USA(){<br />public  void USA_L(){<br />//...........<br />           }</font> </strong> <font size="2"> <br /> </font> </font> </font> <font color="#000000" size="2">}<br /></font> <font color="#a52a2a"> <br /> <strong> <font color="#000000" size="2">public class zhangsan extends zhengjian implements Chna , USA{<br />public void China_L(){<br />// ......<br />}<br />public void USA_L(){<br />// ......<br />}<br />}</font> </strong> <br /> <br />当张三去国Ӟ老美叫他拿个l证来看Q?br /><br /><strong><font color="#000000" size="2">zhangsan.USA_L();</font></strong><br /><br /></font> </p> <p> <font color="#a52a2a"> </font> </p> <p> <font color="#a52a2a">呵呵Q再举个例子大家清楚了Q?br /><br />HP?#8220;三星”?#8220;IBM”两种Q我通常而言不可能一个HP是既?#8220;三星”又是“IBM”的吧~~~~~~~~c?br />          “家庭?#8221;?#8220;办公?#8221;两种Q但往往我们能买到拥有两U款式相l合厂品是吧    ~~~~~~~~~~~接口<br /><br />中国hQ?u>cL?#8220;徏世袭?#8221;Q接口有?#8220;q反常理׃u”Q呵?img height="20" src="http://m.tkk7.com/Emoticons/QQ/lol.gif" width="20" border="0" />开个玩W?/u>?br /><br />q样说完大家再去看些相关文章׃觉得很容易了 呵呵<img height="20" src="http://m.tkk7.com/Emoticons/QQ/icon17.gif" width="20" border="0" /><br /><br />剩下抽象cd单了Q那是抽象类Q?font color="#000000"><font color="#a52a2a">abstract</font>Q?/font>他还是类Qclass)Q只不过是抽象的|了?br /><br />抽象c?font color="#000000"><font color="#a52a2a">Ҏ具体cd的部分实?-----抽象cL对具体的抽象Ҏ特征包括Q?font color="#ff0000">Ҏ的名字、参数的数目、参数的cd?br /><br />不包括:q回cd、参数名字、和抛出的异常?br /></font><br /><a target="_blank"><font color="#a52a2a">java</font></a><font color="#a52a2a">接口Q抽象类Q用来声明一个新的类?<font color="#a52a2a">Java设计师应当主要用接口和抽象cd软g单位与内部和外部<u>耦合</u>(软g工程中内?h?br /><br /></font><font color="#a52a2a">在理想的情况下,一个具体类应当只实现接口和抽象cM声明的方法,而不应当l出多余的方法!<br /><br /></font><font color="#a52a2a">抽象cM提供一个类的部分实现。抽象类可以有实例变量、以及一个或多个构造函数?br /><br /></font>个概念够抽象了吧Q?br /><font color="#000000">public  abstract   class   Human{...}  <br /><font color="#a52a2a"><br />男h也是</font> <br />public   abstract   class  man{...}    </font><br /></font><br /></font><font color="#a52a2a">有一点必讲清:<font color="#ff0000">接口不能l承抽象c,</font><font color="#a52a2a">接口只能l承实实在在的类Q?br /><br />如,我可以ؓ某个HP厂品Q类Q规定一U规范(接口Q,但由于各个厂家推陈出斎ͼ所以,我很隑֯某一cd厂品规定Q?#8220;家庭型hp”很难下个结论(接口Q?br /></font><br /><br /><font color="#006400"><strong>从Y件优化角度来考虑cd接口问题。类class条理清楚内聚性好Q用于Y件模块内部实玎ͼ汽R的内部机<br /><br />梎ͼQ接口interface很灵z耦合性好Q用于模块外部实玎ͼ如,汽R操作板的按钮Q。从而实现强内聚、松耦合<br /><br />的Y件设计思想?/strong></font><br /></font></font></font> </p> <img src ="http://m.tkk7.com/onejavaer/aggbug/100858.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://m.tkk7.com/onejavaer/" target="_blank">暗夜_</a> 2007-02-27 09:43 <a href="http://m.tkk7.com/onejavaer/articles/100858.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>include指o和include动作的区别是什?http://m.tkk7.com/onejavaer/articles/80979.html暗夜_暗夜_Mon, 13 Nov 2006 13:23:00 GMThttp://m.tkk7.com/onejavaer/articles/80979.htmlhttp://m.tkk7.com/onejavaer/comments/80979.htmlhttp://m.tkk7.com/onejavaer/articles/80979.html#Feedback3http://m.tkk7.com/onejavaer/comments/commentRss/80979.htmlhttp://m.tkk7.com/onejavaer/services/trackbacks/80979.html     include指o和include动作都能实现外部文包含到JSP文档中的功能Q名UC很相|非常Ҏh。include指o和include动作到底有什么分别,哪一U方式会更好呢?
1.include指o
    include可以在JSP面转换成Servlet之前Q将JSP代码插入其中。它的主要优Ҏ功能强大Q所包含的代码可以含有M上媄响主面的JSP构造,比如属性、方法的定义和文档类型的讑֮。它的缺Ҏ难于l护只要被包含的面发生更改Q就得更改主面Q这是因Z面不会自动地查看被包含的页面是否发生更攏V?br />include指o的语法格式如?br />    <%@ include file="Relative Url"%>

2.include动作
 
jsp:include动作是在主页面被hӞ次U页面的输出包含q来。尽被包含的页面的输出中不能含有JSPQ但q些面可以是其他资源所产生的结果。服务器按照正常的方式对指向被包含资源的URLq行解释Q因而这个URL可以是Servlet或JSP面。服务器以通常的方式运行被包含的页面,生的输出攑ֈ主页面中Q这U方式与RequestDispatchercȝincludeҎ一致。它的优Ҏ在被包含的页面发生更ҎQ无d主页面做Z攏V它的缺Ҏ所包含的是ơ面的输出,而非ơ面的实际代码,所以在被包含的面中不能用Q何有可能在整体上影响主页面的JSP构造?br />  jsp:include动作的完整语法如?br /> <jsp:include page="Relative path to resource" flush="true">
  其中jsp:include之间不能有空|page属性指定被包含的页面,q个属性是必需的,是指向某U资源的相对URL。如果这个相对URL不是?开_则将其解释ؓ相对于主面的\径;如果是以/开_是这个URL被解释ؓ相对于当前WEB应用的根目录Q而不是服务器的根目录Q这是因URL是由服务器来解释的,不是qL览器来解释的。像下面q行代码Q是qL览器进行解释的Q因此会按照相对于服务器的根目录q行解释?br />  flush属性是一个可选的ơ属性,默认gؓfalseQ它指定在将面包含q来之前是否应该清空主页面的输出?br />   注意Q在JSP1.1中,flush是必需的属性,而且聚会只能是true?br />3.两者的区别和比?/strong>
   jsp:include动作和include指o之间的根本性的不同在于它们被调用的旉。jsp:include动作在请求期间被Ȁz,而include指o在页面{换期间被ȀzR?br />   两者之间的差异军_着它们在用上的区别。用include指o的页面要比用jsp:include动作的页面难于维护。前面已l说q,使用JSP指oQ如果包含的JSP面发生变化Q那么用到这个页面的所有页面都需要手动更新。在JSP服务器的相关规范中ƈ没要求能够检出包含的文件什么时候发生改变,实际上大多数服务器页都有d现这U机制。这样就会导致十分严重的l护问题Q需要记住所有包含某一个页面的其他面Q或者重新编译所有的面Q以使更改能够生效。在q点上,jsp:include׃现出了十分巨大的优势Q它在每ơ请求时重新把资源包含进来。在实现文g包含上,应该可能地使用jsp:include动作?br />   jsp:include动作直比于include指o在维护上有着明显优势Q而include指o仍然能够得以存在Q自然在其他斚w有特D的优势。这个优势就是include指o的功能更强大Q执行速度也稍快。include指o允许所包含的文件中含有影响主页面的JSP代码Q比如响应报送的讄和属性方法的定义。以下表格就是两U包含方式的Ҏ:

 

include指o

jsp:include动作

语法格式

<%@ include file=”..”%>

<jsp:include page=”..”>

发生作用的时?/span>

面转换期间

h期间

包含的内?/span>

文g的实际内?/span>

面的输?/span>

转换成的Servlet

主页面和包含面转换Z?/span>Servlet

主页面和包含面转换为独立的Servlet

影响主页?/span>

可以

不可?/span>

 

include指o

jsp:include动作

发生更改时是否需要显式更改主面

需?/span>

不需?/span>

~译旉

较慢Q资源必被解析

较快

执行旉

E快

较慢Q每ơ资源必被解析

灉|?/span>

较差Q页面名U固?/span>

更好Q页面可以动态指?/span>


   了解到jsp:include动作和include指o各自的功能和区别Q在使用Ӟ可以通过考虑各方面的因素Q来军_使用哪一U方式。尽各自都有一定的优缺点,在实际用中Q还是应优先考虑使用jsp:include动作Q这是因为它在代码维护上的优势远胜过其在功能上的不?

暗夜_ 2006-11-13 21:23 发表评论
]]>
Web服务器开发环境下的线E安全问?/title><link>http://m.tkk7.com/onejavaer/articles/74100.html</link><dc:creator>暗夜_</dc:creator><author>暗夜_</author><pubDate>Mon, 09 Oct 2006 08:23:00 GMT</pubDate><guid>http://m.tkk7.com/onejavaer/articles/74100.html</guid><wfw:comment>http://m.tkk7.com/onejavaer/comments/74100.html</wfw:comment><comments>http://m.tkk7.com/onejavaer/articles/74100.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://m.tkk7.com/onejavaer/comments/commentRss/74100.html</wfw:commentRss><trackback:ping>http://m.tkk7.com/onejavaer/services/trackbacks/74100.html</trackback:ping><description><![CDATA[ <p>Servlet是在多线E环境下的。即可能有多个请求发l一个servelt实例Q每个请求是一个线E?<br />struts下的action也类|同样在多U程环境下。可以参考struts user guide: http://struts.apache.org/struts-action/userGuide/building_controller.html 中的Action Class Design Guidelines一? Write code for a multi-threaded environment - Our controller servlet creates only one instance of your Action class, and uses this one instance to service all requests. Thus, you need to write thread-safe Action classes. Follow the same guidelines you would use to write thread-safe Servlets. <br />?为多U程环境~写代码。我们的controller servlet指挥创徏你的Action cȝ一个实例,用此实例来服务所有的h。因此,你必ȝ写线E安全的ActioncR遵循与写线E安全的servlet同样的方针?<br /><br />1.什么是U程安全的代?<br />在多U程环境下能正确执行的代码就是线E安全的?<br />安全的意思是能正执行,否则后果是程序执行错误,可能出现各种异常情况?/p> <p>2.如何~写U程安全的代?<br />很多书籍里都详细讲解了如何这斚w的问题,他们主要讲解的是如何同步U程对共享资源的使用的问题。主要是对synchronized关键字的各种用法Q以及锁的概c?<br />Java1.5中也提供了如d锁这cȝ工具cR这些都需要较高的技巧,而且相对难于调试?<br /><br />但是Q线E同步是不得以的Ҏ,是比较复杂的,而且会带来性能的损失。等效的代码中,不需要同步在~写Ҏ度和性能上会更好些?<br />我这里强调的是什么代码是始终为线E安全的、是不需要同步的。如? <br />1)帔R始终是线E安全的Q因为只存在L作?<br />2)Ҏ造器的访?new 操作)是线E安全的Q因为每ơ都新徏一个实例,不会讉K׃n的资源?<br />3)最重要的是:局部变量是U程安全的。因为每执行一个方法,都会在独立的I间创徏局部变量,它不是共享的资源。局部变量包括方法的参数变量?<br />struts user guide里有Q?<br />Only Use Local Variables - The most important principle that aids in thread-safe coding is to use only local variables, not instance variables , in your Action class. <br />?只用用局部变量?-~写U程安全的代码最重要的原则就是,在ActioncM只用局部变量,不用实例变量?/p> <p> <br />ȝQ?<br />在Java的Web服务器环境下开发,要注意线E安全的问题。最单的实现方式是在Servlet和Struts Action里不要用类变量、实例变量,但可以用类帔R和实例常量?<br />如果有这些变量,可以它们{换ؓҎ的参C入,以消除它们?<br />注意一个容易؜淆的地方Q被Servlet或Action调用的类?如值对象、领域模型类)中是否可以安全的使用实例变量Q如果你在每ơ方法调用时 <br />新徏一个对象,再调用它们的ҎQ则不存在同步问?--因ؓ它们不是多个U程׃n的资源,只有׃n的资源才需要同?--而Servlet和Action的实例对于多个线E是׃n的?<br />换句话说QServlet和Action的实例会被多个线E同时调用,而过了这一?如果在你自己的代码中没有另外启动U程Q且每次调用后箋业务对象旉是先新徏一个实例再调用Q则都是U程安全的?/p> <img src ="http://m.tkk7.com/onejavaer/aggbug/74100.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://m.tkk7.com/onejavaer/" target="_blank">暗夜_</a> 2006-10-09 16:23 <a href="http://m.tkk7.com/onejavaer/articles/74100.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>java.util.ArrayList 详解http://m.tkk7.com/onejavaer/articles/72934.html暗夜_暗夜_Sat, 30 Sep 2006 00:14:00 GMThttp://m.tkk7.com/onejavaer/articles/72934.htmlhttp://m.tkk7.com/onejavaer/comments/72934.htmlhttp://m.tkk7.com/onejavaer/articles/72934.html#Feedback0http://m.tkk7.com/onejavaer/comments/commentRss/72934.htmlhttp://m.tkk7.com/onejavaer/services/trackbacks/72934.html阅读全文

暗夜_ 2006-09-30 08:14 发表评论
]]>
JSP生成静态页实践及其设计思想http://m.tkk7.com/onejavaer/articles/72910.html暗夜_暗夜_Fri, 29 Sep 2006 14:29:00 GMThttp://m.tkk7.com/onejavaer/articles/72910.htmlhttp://m.tkk7.com/onejavaer/comments/72910.htmlhttp://m.tkk7.com/onejavaer/articles/72910.html#Feedback0http://m.tkk7.com/onejavaer/comments/commentRss/72910.htmlhttp://m.tkk7.com/onejavaer/services/trackbacks/72910.html我们以两个大型网站ؓ例作比较Q?br />51job和智联招聘(先声明我不是Z们作q告Q仅以他们ؓ例作技术上的比较)
51job采用的是比较“先进”的php技术,而智联用的是比较落后的asp.但我们可能会明显的感觉到51job的反应速度相比招聘实在是太慢了Qؓ什么会q样Q细心的人可能会察觉C。智联虽然用的是asp,但他采用了另一U更巧妙的技?-asp生成静态页技术。所有的动态页基本上都转换成了html静态页Q不用访问数据库Q当然反应快了?br />下面我们讨论一下jsp怎么转换成html??
首先要做一个模ѝ后~不限Q但一般都?.template例子
<html>
<head>
<title>#title#</title>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<LINK href="../css.css" rel=stylesheet type=text/css>
</head>
<body>
<P align="center">
#title#
<BR><BR><BR>
作者:#author#
<BR><BR>
<BR>
#content#
<BR><BR><BR><BR>
</P>
</body>
</html>

做一个处理模板的cL者jsp文g?明问题我们从单入手以一个jsp文gZ)
filePath = request.getRealPath("/")+"WEB-INF/templates/template.htm";
 out.print(filePath);
 String templateContent
="";
 FileInputStream fileinputstream 
= new FileInputStream(filePath);//d模块文g
 int lenght = fileinputstream.available();
 
byte bytes[] = new byte[lenght];
 fileinputstream.read(bytes);
 fileinputstream.close();
 templateContent 
= new String(bytes);
 out.print(
"以下是模板内容:<br>"+templateContent+"<br> 以下是置换以后的html内容<br><hr>");
 templateContent
=templateContent.replaceAll("#title#",title);
 templateContent
=templateContent.replaceAll("#author#",editer);//替换掉模块中相应的地?/span>
 templateContent=templateContent.replaceAll("#content#",content);
 
// Ҏ旉得文件名
 Calendar calendar = Calendar.getInstance();
 String fileame 
= String.valueOf(calendar.getTimeInMillis()) +".html";
 fileame 
= request.getRealPath("/")+fileame;//生成的html文g保存路径

 out.print(templateContent);
 FileOutputStream fileoutputstream 
= new FileOutputStream(fileame);//建立文g输出?/span>
 byte tag_bytes[] = templateContent.getBytes();
 fileoutputstream.write(tag_bytes);
 fileoutputstream.close();
嗯,核心技术就是这样了Q如果大家要求的性能更高Q可以改用freemarker做模ѝfreemarker的用方法可以参阅另一文章?a class="singleposttitle" id="viewpost1_TitleUrl" href="/zhanglijun33/archive/2006/07/20/freemarker.html">Freemarker 模板工具的作用及使用?br />
引自Q?a href="/zhanglijun33/archive/2006/07/28/60568.aspx">http://m.tkk7.com/zhanglijun33/archive/2006/07/28/60568.aspx

暗夜_ 2006-09-29 22:29 发表评论
]]>
վ֩ģ壺 ޹˾þۺһ77| ɫͼƵ߹ۿ| ԺԺҳ| þþþþþۺձ| ƵĻ| ޹ƷþþþϼС | þ޹ŷ޾Ʒһ| ˾žŴɫ㽶վ| ëƬ4455ww| ѹaƬ| Ѳ߹ۿվ| 2021þþƷѹۿ| һɫƬ| þþ޾Ʒ| ˾Ʒձվ| ޳aƬ77777Ⱥɫ| ߾ƷAAVV| ѾƷһ35| ëƬѹۿƵ| ༤ۺ͵ͼ| ɫ߹ۿ| 337pձŷ޴| ƷƵѹۿ| ҹƬ| ԺԺҳ| ޹ۺϾƷĵһ| þþƷר| av޽վ| ھƷ99Ѹ| 91Ʒ鶹ϵ | ޾Ʒavˮ| ؼAƬëƬѿ | ԭƷav| ɫ¶ۺ| һۿƵ߲ | ĻӰѹۿ| av乾| պһһ| þþþþþ99Ʒѹۿ| ѹۿ| վ߲|