FAF.Rei's profile云之彼端※約束之地PhotosBlogListsMore Tools Help

Blog


    Struts动态多文件上传

    首先保证页面中的<input type="file">标签的名称name不同,struts标签property也一样。
    包含这些<input>的<form>其属性必须为 enctype="multipart/form-data"  method="post"。
    在formbean中,不需要定义类型为org.apache.struts.upload.FormFile的属性,也不需要List对象,建议使用DynaActionForm。
    action中取出上传的文件代码:
    DynaActionForm dyForm = (DynaActionForm) form;
    Hashtable files = dyForm.getMultipartRequestHandler().getFileElements();
    for (Enumeration e = files.keys(); e.hasMoreElements();) {
    FormFile formfile = (FormFile) files.get((String) e.nextElement());
                    if (formfile != null && formfile.getFileSize() > 0) {
    这里你可以使用formfile.getInputStream()来获取一个文件的输入流进行保存。
                    }
          }
     
    这样就可以动态的在页面中添加上传文件的<input type="file">,不过究竟可以允许上传多少个还没有进行测过。
     
    其实在ActionForm对象的MultipartRequestHandler属性中存放了从页面上传服务器的原始数据,所有<form>中的上传数据都可以找到。
    Hashtable getAllElements() 所有的标签
    Hashtable getFileElements()   所有文件标签
    Hashtable getTextElements() 所有文本标签
     
    其返回的Hashtable可以通过get("标签name")获得对象数组
     
    如:
    页面中为<input type="text" name="name">
    在formbean中没有该name属性,
    在action中获得其value为
    String name[] = (String[])dyForm.getMultipartRequestHandler().getTextElements().get("name");
    String n = name[0];
    如果页面中有两个<input type="text" name="name">标签
    则name.length()为2。
    String name1 = name[0];
    String name2 = name[1];      
    许多页面动态上传数据往往可以通过这种方法来取。
     
    另外需要注意的是页面传入的数据存HttpServletRequest parameter对象中,无论是否使用Struts,都可以通过request.getParameter("标签名")获取value。
    同时此数据会在Action结束后传回ActionForward对象页面(redirect=false)
    即:页面A--提交-->StrutsAction--返回-->页面B,在页面B中仍可以取得页面A的上传数据,通过${param.页面A标签名}、reuqest.getParameter或者使用Struts标签<bean:write name="formbean名" property="formbean属性名"/>
    但是如果页面<form>标签属性enctype="multipart/form-data"此时表单上传的数据在HttpServletRequest parameter对象中的生存周期只到StrutsAction,无法到达页面B。
    即:在StrutsAction中可以使用reuqest.getParameter("name")获取,但在页面B中无法通过${param.页面A标签名}、reuqest.getParameter获得,而Struts标签不受影响。这点需要留意。
    普通的request是HttpServletRequest,如果用enctype="multipart/form-data"的话,request就变成了MultipartRequestWrapper。
    下面是struts的源代码:
    protected HttpServletRequest processMultipart(HttpServletRequest request) {
        if (!"POST".equalsIgnoreCase(request.getMethod())) {
            return (request);
        }
       
        String contentType = request.getContentType();
        if ((contentType !=null) &&
            contentType.startsWith("multipart/form-data")) {
            return (new MultipartRequestWrapper(request));
        }else{
            return (request);
        }
      }
     

    JS中使用clientHeight、offsetHeight 和 scrollHeight注意事项

    我们这里说说四种浏览器对 document.body 的 clientHeight、offsetHeight 和 scrollHeight 的解释,这里说的是 document.body,如果是 HTML 控件,则又有不同。
     
    这四种浏览器分别为IE(Internet Explorer)、NS(Netscape)、Opera、FF(FireFox)。
     
    clientHeight
    大家对 clientHeight 都没有什么异议,都认为是内容可视区域的高度,也就是说页面浏览器中可以看到内容的这个区域的高度,一般是最后一个工具条以下到状态栏以上的这个区域,与页面内容无关。
     
    offsetHeight
    IE、Opera 认为 offsetHeight = clientHeight + 滚动条 + 边框。
    NS、FF 认为 offsetHeight 是网页内容实际高度,可以小于 clientHeight。
     
    scrollHeight
    IE、Opera 认为 scrollHeight 是网页内容实际高度,可以小于 clientHeight。
    NS、FF 认为 scrollHeight 是网页内容高度,不过最小值是 clientHeight。
     
    简单地说
    clientHeight 就是透过浏览器看内容的这个区域高度。
    NS、FF 认为 offsetHeight 和 scrollHeight 都是网页内容高度,只不过当网页内容高度小于等于 clientHeight 时,scrollHeight 的值是 clientHeight,而 offsetHeight 可以小于 clientHeight。
    IE、Opera 认为 offsetHeight 是可视区域 clientHeight 滚动条加边框。scrollHeight 则是网页内容实际高度。
     
    同理
    clientWidth、offsetWidth 和 scrollWidth 的解释与上面相同,只是把高度换成宽度即可。
     
    但是
    FF 在不同的 DOCTYPE 中对 clientHeight 的解释不同, xhtml 1 trasitional 中则不是如上解释的。其它浏览器则不存在此问题。

    java ArrayList toArray()方法的注意

        ArrayList类扩展AbstractList并执行List接口。ArrayList支持可随需要而增长的动态数组。
     
        ArrayList有如下的构造函数:
      
            ArrayList( )
            ArrayList(Collection c)
            ArrayList(int capacity)
     
     如果调用new ArrayList()构造时,其默认的capacity(初始容量)为10。
     
     参见ArrayList源码,其中是这样定义的:
     
        public ArrayList() {
      this(10);
         }
     
     默认初始化内部数组大小为10。
     
       程序编译后执行ArrayList.toArray(),把ArrayList转化为数组时,该数组大小仍为capacity(为10)。
     
     当装入的数据和capacity值不等时(小于capacity),比如只装入了5个数据,数组中后面的(capacity - size)个对象将置为null,此时当数组强制类型转换时,容易出现一些问题,如java.lang.ClassCastException异常等。
     
     解决办法是:在用ArrayList转化为数组装数据后,使用trimToSize()重新设置数组的真实大小。
     
      toArray()正确使用方式如下:
     
            1)  Long[] l = new Long[<total size>];
                  list.toArray(l);
     
            2)  Long[] l = (Long []) list.toArray(new Long[0]);
     
            3)  Long [] a = new Long[<total size>];
                  Long [] l = (Long []) list.toArray(a);
     
     
     java sdk doc 上讲:
     
          public Object[] toArray(Object[] a)
     
          a--the array into which the elements of this list are to be stored, if it is big enough; otherwise, a new array of the same  runtime type is allocated for this purpose.
     
          如果这个数组a足够大,就会把数据全放进去,返回的数组也是指向这个数组,(数组多余的空间存储的是null对象);要是不够大,就申请一个跟参数同样类型的数组,把值放进去,然后返回。
     
         需要注意的是:你要是传入的参数为9个大小,而list里面有5个object,那么其他的四个很可能是null , 使用的时候要特别注意。
     
     
    参考代码:
     
      ArrayList result=GetResult();
     
      int n=result.size();
     
      String[][] myArray=new String[n][]; //定义二维数组
     
      for (int i=0;i<n;i++)  //构造二维数组
      {
        ArrayList tempArray= (ArrayList)result.get(i);
        myArray[i]=(String[])tempArray.toArray();     //此处会出现java.lang.ClassCastException的错误
      }
     
      正确方式
      for (int i=0;i<n;i++)  //构造二维数组
          {
                ArrayList tempArray= (ArrayList)result.get(i);
                myArray[i]=(String[])tempArray.toArray(new String[0]);   //注意此处的写法
           }

    Regular Expression Example

    匹配中文字符的正则表达式: [\u4e00-\u9fa5]

    匹配双字节字符(包括汉字在内):[^\x00-\xff]

    应用:计算字符串的长度(一个双字节字符长度计2,ASCII字符计1)

    String.prototype.len=function(){return this.replace([^\x00-\xff]/g,"aa").length;}

    匹配空行的正则表达式:\n[\s| ]*\r

    匹配HTML标记的正则表达式:/<(.*)>.*<\/\1>|<(.*) \/>/

    匹配首尾空格的正则表达式:(^\s*)|(\s*$)

    应用:javascript中没有像vbscript那样的trim函数,我们就可以利用这个表达式来实现,如下:

    String.prototype.trim = function()
    {
        return this.replace(/(^\s*)|(\s*$)/g, "");
    }

    利用正则表达式分解和转换IP地址:

    下面是利用正则表达式匹配IP地址,并将IP地址转换成对应数值的Javascript程序:

    function IP2V(ip)
    {
     re=/(\d+)\.(\d+)\.(\d+)\.(\d+)/g  //匹配IP地址的正则表达式
    if(re.test(ip))
    {
    return RegExp.$1*Math.pow(255,3))+RegExp.$2*Math.pow(255,2))+RegExp.$3*255+RegExp.$4*1
    }
    else
    {
     throw new Error("Not a valid IP address!")
    }
    }

    不过上面的程序如果不用正则表达式,而直接用split函数来分解可能更简单,程序如下:

    var ip="10.100.20.168"
    ip=ip.split(".")
    alert("IP值是:"+(ip[0]*255*255*255+ip[1]*255*255+ip[2]*255+ip[3]*1))

    匹配Email地址的正则表达式:\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*

    匹配网址URL的正则表达式:http://([\w-]+\.)+[\w-]+(/[\w- ./?%&=]*)?

     

    得用正则表达式从URL地址中提取文件名的javascript程序,如下结果为page1

    s="http://www.9499.net/page1.htm"
    s=s.replace(/(.*\/){0,}([^\.]+).*/ig,"$2")
    alert(s)

    利用正则表达式限制网页表单里的文本框输入内容:

    用正则表达式限制只能输入中文:onkeyup="value=value.replace(/[^\u4E00-\u9FA5]/g,'')" onbeforepaste="clipboardData.setData('text',clipboardData.getData('text').replace(/[^\u4E00-\u9FA5]/g,''))"

    用正则表达式限制只能输入全角字符: onkeyup="value=value.replace(/[^\uFF00-\uFFFF]/g,'')" onbeforepaste="clipboardData.setData('text',clipboardData.getData('text').replace(/[^\uFF00-\uFFFF]/g,''))"

    用正则表达式限制只能输入数字:onkeyup="value=value.replace(/[^\d]/g,'') "onbeforepaste="clipboardData.setData('text',clipboardData.getData('text').replace(/[^\d]/g,''))"

    用正则表达式限制只能输入数字和英文:onkeyup="value=value.replace(/[\W]/g,'') "onbeforepaste="clipboardData.setData('text',clipboardData.getData('text').replace(/[^\d]/g,''))"

     

     

    正则表达式,相关链接
    http://blog.csdn.net/laily/category/19548.aspx
    http://blog.csdn.net/laily/archive/2004/06/30/30525.aspx 微软的正则表达式教程(五):选择/编组和后向引用

    http://blog.csdn.net/laily/archive/2004/06/30/30522.aspx 微软的正则表达式教程(四):限定符和定位符

    http://blog.csdn.net/laily/archive/2004/06/30/30517.aspx 微软的正则表达式教程(三):字符匹配

    http://blog.csdn.net/laily/archive/2004/06/30/30514.aspx 微软的正则表达式教程(二):正则表达式语法和优先权顺序

    http://blog.csdn.net/laily/archive/2004/06/30/30511.aspx 微软的正则表达式教程(一):正则表达式简介

    http://blog.csdn.net/laily/archive/2004/06/30/30360.aspx 小程序大作为:高级查找/替换、正则表达式练习器、Javascript脚本程序调试器

    http://blog.csdn.net/laily/archive/2004/06/24/25872.aspx 经典正则表达式

    正则表达式,正规表达式,正则表达式匹配,正则表达式语法,模式匹配,正规表达式匹配 javascript正则表达式 ASP正则表达式 ASP.NET正则表达式 C#正则表达式 JSP正则表达式 PHP正则表达式 VB.NET正则表达式 VBSCript正则表达式编程 delphi正则表达式 jscript

     
    正则表达式 regular expression
    正则表达式 RegExp
    模式 pattern
    匹配 Match
    .NET命名空间: System.Text.RegularExpression


    补充:
    ^\d+$  //匹配非负整数(正整数 + 0)
    ^[0-9]*[1-9][0-9]*$  //匹配正整数
    ^((-\d+)|(0+))$  //匹配非正整数(负整数 + 0)
    ^-[0-9]*[1-9][0-9]*$  //匹配负整数
    ^-?\d+$    //匹配整数
    ^\d+(\.\d+)?$  //匹配非负浮点数(正浮点数 + 0)
    ^(([0-9]+\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\.[0-9]+)|([0-9]*[1-9][0-9]*))$  //匹配正浮点数
    ^((-\d+(\.\d+)?)|(0+(\.0+)?))$  //匹配非正浮点数(负浮点数 + 0)
    ^(-(([0-9]+\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\.[0-9]+)|([0-9]*[1-9][0-9]*)))$  //匹配负浮点数
    ^(-?\d+)(\.\d+)?$  //匹配浮点数
    ^[A-Za-z]+$  //匹配由26个英文字母组成的字符串
    ^[A-Z]+$  //匹配由26个英文字母的大写组成的字符串
    ^[a-z]+$  //匹配由26个英文字母的小写组成的字符串
    ^[A-Za-z0-9]+$  //匹配由数字和26个英文字母组成的字符串
    ^\w+$  //匹配由数字、26个英文字母或者下划线组成的字符串
    ^[\w-]+(\.[\w-]+)*@[\w-]+(\.[\w-]+)+$    //匹配email地址
    ^[a-zA-z]+://匹配(\w+(-\w+)*)(\.(\w+(-\w+)*))*(\?\S*)?$  //匹配url


    1.确认有效电子邮件格式
    下面的代码示例使用静态 Regex.IsMatch 方法验证一个字符串是否为有效电子邮件格式。如果字符串包含一个有效的电子邮件地址,则 IsValidEmail 方法返回 true,否则返回 false,但不采取其他任何操作。您可以使用 IsValidEmail,在应用程序将地址存储在数据库中或显示在 ASP.NET 页中之前,筛选出包含无效字符的电子邮件地址。

    [Visual Basic]
    Function IsValidEmail(strIn As String) As Boolean
    ' Return true if strIn is in valid e-mail format.
    Return Regex.IsMatch(strIn, ("^([\w-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([\w-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$")
    End Function
    [C#]
    bool IsValidEmail(string strIn)
    {
    // Return true if strIn is in valid e-mail format.
    return Regex.IsMatch(strIn, @"^([\w-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([\w-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$");
    }


    2.清理输入字符串
    下面的代码示例使用静态 Regex.Replace 方法从字符串中抽出无效字符。您可以使用这里定义的 CleanInput 方法,清除掉在接受用户输入的窗体的文本字段中输入的可能有害的字符。CleanInput 在清除掉除 @、-(连字符)和 .(句点)以外的所有非字母数字字符后返回一个字符串。

    [Visual Basic]
    Function CleanInput(strIn As String) As String
    ' Replace invalid characters with empty strings.
    Return Regex.Replace(strIn, "[^\w\.@-]", "")
    End Function
    [C#]
    String CleanInput(string strIn)
    {
    // Replace invalid characters with empty strings.
    return Regex.Replace(strIn, @"[^\w\.@-]", "");
    }


    3.更改日期格式
    以下代码示例使用 Regex.Replace 方法来用 dd-mm-yy 的日期形式代替 mm/dd/yy 的日期形式。

    [Visual Basic]
    Function MDYToDMY(input As String) As String
    Return Regex.Replace(input, _
    "\b(?<month>\d{1,2})/(?<day>\d{1,2})/(?<year>\d{2,4})\b", _
    "${day}-${month}-${year}")
    End Function
    [C#]
    String MDYToDMY(String input)
    {
    return Regex.Replace(input,
    "\\b(?<month>\\d{1,2})/(?<day>\\d{1,2})/(?<year>\\d{2,4})\\b",
    "${day}-${month}-${year}");
    }
    Regex 替换模式
    本示例说明如何在 Regex.Replace 的替换模式中使用命名的反向引用。其中,替换表达式 ${day} 插入由 (?<day>...) 组捕获的子字符串。

    有几种静态函数使您可以在使用正则表达式操作时无需创建显式正则表达式对象,而 Regex.Replace 函数正是其中之一。如果您不想保留编译的正则表达式,这将给您带来方便


    4.提取 URL 信息
    以下代码示例使用 Match.Result 来从 URL 提取协议和端口号。例如,“http://www.contoso.com:8080/letters/readme.html”将返回“http:8080”。

    [Visual Basic]
    Function Extension(url As String) As String
    Dim r As New Regex("^(?<proto>\w+)://[^/]+?(?<port>:\d+)?/", _
    RegexOptions.Compiled)
    Return r.Match(url).Result("${proto}${port}")
    End Function
    [C#]
    String Extension(String url)
    {
    Regex r = new Regex(@"^(?<proto>\w+)://[^/]+?(?<port>:\d+)?/",
    RegexOptions.Compiled);
    return r.Match(url).Result("${proto}${port}");
    }

    Struts+Hibernate+Ajax中文解决方案

    表述层把数据传回Struts的Action类
    解决方案一:对Http请求数据转码
    A:在处理请求前  request.setCharacterEncoding("gb2312")
    B:在处理请求后  String clientDate = request.getParameter("clientDate");
                         if(clientDate!=null){
                              clientDate = new String(cllientDate.getBytes("ISO-8859-1"),"gb2312");
                         }
     
    解决方案二(推荐):使用jsp得filter
    1.修改web.xml文件,在<web-app>标签后增加如下内容.
    <filter>
       <filter-name>Set_Character_Encoding</filter-name>
       <filter-class>fafrei.tools.SetEncodingFilter</filter-class>
        <init-param>
        <param-name>encoding</param-name>
        <param-value>gb2312</param-value>
       </init-param>
     </filter>
     <filter-mapping>
     <filter-name>Set_Character_Encoding</filter-name>
     <url-pattern>/*</url-pattern>
    </filter-mapping>
     
    2.创建类文件
    package fafrei.tools;
    import java.io.IOException;
    import javax.servlet.Filter;
    import javax.servlet.FilterChain;
    import javax.servlet.FilterConfig;
    import javax.servlet.ServletException;
    import javax.servlet.ServletRequest;
    import javax.servlet.ServletResponse;
     
    public class SetEncodingFilter implements Filter {
       protected String encoding = null;
       protected FilterConfig filterConfig = null;
       protected boolean ignore = true;
       public void destroy() {
         this.encoding = null;
         this.filterConfig = null;
    }
    public void doFilter(
         ServletRequest request,
         ServletResponse response,
         FilterChain chain) throws IOException, ServletException {
         if (ignore || (request.getCharacterEncoding() == null)) {
            request.setCharacterEncoding(selectEncoding(request));
         }
          chain.doFilter(request, response);
     }

     public void init(FilterConfig filterConfig) throws ServletException {
        this.filterConfig = filterConfig;
        this.encoding = filterConfig.getInitParameter("encoding");
        String value = filterConfig.getInitParameter("ignore");
        if (value == null)
        this.ignore = true;
        else if (value.equalsIgnoreCase("true") || value.equalsIgnoreCase("yes"))
           this.ignore = true;
           else
           this.ignore = false;
        }
     protected String selectEncoding(ServletRequest request) {
        return (this.encoding);
     }
     public FilterConfig getFilterConfig() {
        return filterConfig;
     }
     public void setFilterConfig(FilterConfig filterConfig) {
        this.filterConfig = filterConfig;
     }
    }

     
    处理XML配置文件
    需要在文件中加入<?xml version='1.0' encoding="gb2312"?>
     
    处理相应结果编码
    servlet中:
      response.setContentType("text/html;charset=gb2312");
    jsp中:
      <%page contentType="text/html;charset=gb2312"%>
    Html中:
      <head>
        <META HTTP-EQUIV="Content-Type" CONTENT="text/html;charset=gb2312">
      </head>
     
     处理数据库编码
     如果数据库的字符编码为gb2312,则可以直接读取数据。如果为iso-8859-1,则必须先转码
        Connection con = DbUtil.connectToDb();
        PreparedStatement pStmt = null;
        ResultSet rs = null;
        pStmt = conprepareStatement("select name from emp;");
        rs = pStmt.executeQuery();
        while(rs.next()){
              String name = rs.getString("name");
              String name_ch = new String(name.getBytes("iso-8859-1"),"gb2312");  
       }
     如果使用hibernate,转码也如此进行。
     
    Ajax中的服务器返回数据
    这里返回的为xml格式,其他格式也类似处理
       response.setContentType("text/xml;charset=gb2312");
       response.setHeader("Cache-Control", "no-cache");
       PrintWriter out = response.getWriter();
       out.println("<?xml version='1.0' encoding='"+"gb2312"+"' ?>");
    这里先后顺序千万不要弄错!
     

    [javascript]表单中的数据验证

    <HTML>
    <HEAD>
    <TITLE>Date Entry Validation</TITLE>
    <SCRIPT LANGUAGE="JavaScript">
    <!--

    //检查输入是否为空
    function isEmpty(inputStr) {
      if (inputStr == "" || inputStr == null) {
        return true
      }
      return false
    }

    // 验证数据是否在指定范围内
    //for this application
    function inRange(inputStr, lo, hi) {
      var num = parseInt(inputStr, 10)
      if (num < lo || num > hi) {
        return false
      }
      return true
    }

    // 验证月份是否符合逻辑
    function validateMonth(field, bypassUpdate) {
      var input = field.value
      if (isEmpty(input)) {
        alert("Be sure to enter a month value.")
        select(field)
        return false
      } else {
        input = parseInt(field.value, 10)
        if (isNaN(input)) {
          alert("Entries must be numbers only.")
          select(field)
          return false
        } else {
          if (!inRange(input,1,12)) {
             alert("Enter a number between 1 (January) and 12 (December).")
             select(field)
             return false
          }
        }
      }
      if (!bypassUpdate) {
          calcDate()
      }
      return true
    }

    //验证天数是否符合逻辑
    function validateDate(field) {
      var input = field.value
      if (isEmpty(input)) {
        alert("Be sure to enter a date value.")
        select(field)
        return false
      } else {
        input = parseInt(field.value, 10)
        if (isNaN(input)) {
          alert("Entries must be numbers only.")
          select(field)
          return false
        } else {
          var monthField = document.birthdate.month
          if (!validateMonth(monthField, true)) return false
          var monthVal = parseInt(monthField.value, 10)
          var monthMax = new Array(31,31,29,31,30,31,30,31,
                                   31,30,31,30,31)
          var top = monthMax[monthVal]
          if (!inRange(input,1,top)) {
            alert("Enter a number between 1 and " + top + ".")
            select(field)
            return false
          }
        }
      }
      calcDate()
      return true
    }

    //验证年份是否符合逻辑
    function validateYear(field) {
      var input = field.value
      if (isEmpty(input)) {
        alert("Be sure to enter a year value.")
        select(field)
        return false
      } else {
        input = parseInt(field.value, 10)
        if (isNaN(input)) {
          alert("Entries must be numbers only.")
          select(field)
          return false
        } else {
          if (!inRange(input,1900,2005)) {
            alert("Enter a number between 1900 and 2005.")
            select(field)
            return false
          }
        }
      }
      calcDate()
      return true
    }

    function select(field) {
      field.focus()
      field.select()
    }

    function calcDate() {
      var mm = parseInt(document.birthdate.month.value, 10)
      var dd = parseInt(document.birthdate.date.value, 10)
      var yy = parseInt(document.birthdate.year.value, 10)
      document.birthdate.fullDate.value = mm + "/" + dd + "/" + yy
    }

    //表单验证

    function checkForm(form) {
      if (validateMonth(form.month)) {
        if (validateDate(form.date)) {
          if (validateYear(form.year)) {
            return true
          }
        }
      }
      return false
    }
    //-->
    </SCRIPT>
    </HEAD>
    <BODY>
    <FORM NAME="birthdate" ACTION="mailto:fun@dannyg.com" METHOD=POST
        onSubmit="return checkForm(this)">
    Please enter your birthdate...<BR>
    Month:<INPUT TYPE="text" NAME="month" VALUE=1 SIZE=2
        onChange="validateMonth(this)">
    Date:<INPUT TYPE="text" NAME="date" VALUE=1 SIZE=2
        onChange="validateDate(this)">
    Year:<INPUT TYPE="text" NAME="year" VALUE=1900 SIZE=4
        onChange="validateYear(this)">
    <P>
    Thank you for entering:<INPUT TYPE="text" NAME="fullDate" SIZE=10><P>
    <INPUT TYPE="submit"> <INPUT TYPE="Reset">
    </FORM>
    </BODY>
    </HTML>

    native code compilers

    native code compilers
    Most compilers generate JVM byte codes. Native Code Compilers will optionally generate native *.exe files. JITs create native code at execute time, but don't create *.exe files. The Microsoft SDK for Java includes a tool called jexegen which turns your .class file(s) into an .exe file. It doesn't compile them or convert them to machine code; it just stuffs the contents of the .class files into the .exe file along with some code to pass those bytecodes to the MS JVM to be interpreted. The resulting exe files need access to the Microsoft JVM to work, unlike true native exe files which are standalone and written in machine code. download it as part of the Microsoft SDK for Java 4. There is a similar product called Java2exe.
    Here are seven ways to get what acts like a Java executable file:

    1.Use a native compiler. This is the only method that gives you a true machine code executable. You may still have to distribute some DLLs or the JRE along with your executable.

    2.Set up a shortcut with the appropriate java.exe command to load the class.

    3.Bundle your classes in a jar with the Main-Class attribute. Set up an association for *.jar to make it executable.

    4.Write yourself a tiny C program that exec's a Java command to load your class. Assuming the jar file Foo.jar with main class Bar, here how to making a Foo.exe tiny kickoff program. Compile the following program foo.c to foo.exe:

    #include <process.h>
    int main(void)
    {
    execlp("java.exe",
    "java.exe",
    "-cp",
    "foo.jar",
    "Bar",
    NULL);
    return 0;
    }

    If you want to play really strange games, concatenate the jar file onto the end of your foo.exe kicker, and put the EXE file on the classpath where you would normally need to place foo.jar. This way you can distribute but a single file, albeit uncompressed. Reputedly java.exe will happily treat this combo as a standard jar. Executing the foo.exe just ignores the jar tacked on the end. e.g. change the foo.c code to read

    #include <process.h>
    int main(void)
    {
    execlp("java.exe",
    "java.exe",
    "-cp",
    "foo.exe",
    "Bar",
    NULL);
    return 0;
    }

    then
    rename foo.exe littlefoo.exe
    copy /b littlefoo.exe + foo.jar foo.exe
    You only need distribute foo.exe.

    5.Use the InstallAnywhere NOW installer (or other installer). It uses a standard platform-dependent EXE kickoff file for a standard interpreted platform-independent Java application packaged in a jar file.

    6.Use Microsoft's Jexegen bundler. It only works with the Microsoft JVM. Webgain Café also works this way as does J2Exe.

    7.Distribute using Java Web Start. Users can click on menu or desktop items to kick off pure java Programs.

    What are the advantages of a native compiler?

    Execution speedVisit any of the vendor sites, such as Jet for independent benchmarks. The improvement is even more marked for old clunker machines that your customers may use. Native compilations tend to me more scalable, doing well as you add more threads. Depending on just what you are doing, you may get over twice the speed of Java 1.4.1 Hotspot.
    Load speedA natively compiled program will load and start execution much faster than one using Java 1.4.1 JVM. Customers resent slow load times even more than slow execution times. They have nothing to do but sit there and wait. JITed Java is precluded from many applications because of its extraordinarily slow load time. Natively compiled Java opens the doors to all the traditional C applications.
    Self-Contained Distribution PackageJava, or even Java Web Start requires the customer to pre-install the JRE. You are legally not permitted to bundle that JRE with your app. The customer has to go get it for himself. Native apps can be distributed in familiar ways as totally self-contained packages. On the other hand, once Java Web Start is installed, the end user can install new apps with a single click.
    Distribution sizeJava class files are quite tiny, but they need the entire JRE to make them work. If the customer has Java already installed, then the class files packed in a jar are exceedingly compact. However, if he does not have Java installed, that then the native distribution will be smaller.
    SecurityNative apps, especially optimised apps, are much harder to decompile (reverse engineer).
    PrejudiceThe customer need not know your app is written in Java. Some customers are Microsoft fanatics who follow the party line that Java is slow or evil.
    Code SharingCompilers like Jet, bundle classes into DLLs. This means if you have two JVMs running, you need only one copy of the DLL in RAM. This makes more efficient use of RAM.
    What are the disadvantages of a native compiler:
    Single PlatformYour code works on only one platform. Even if you buy a multiplatform compiler, you need to generate different versions, one for each platform, and different install scripts for each platform. It is even more import than ever to test the code on each platform.
    CostThe compiler is an extra cost item.
    ComplexityDistribution is more complex with DLLs and EXEs and an install script. (Jet comes with an install generator, so you don't necessarily have to buy Installshield or equivalent.)
    DLL version hellIn place of the problem of mixed generations of JRE, you have the problem of mixed generations of support DLLs on your client site.
    Learning CurveNative compilation is more complex than standard compilation. You need to learn new skills to master it, e.g. dealing with a mixture of static and dynamic class loading. It is quite simple. The only mildly complicated thing is dealing with dynamic class loading.
    You can't use native compilers on Applets or Java Web Start Weblets.


    Most native code compilers are for Windows, though TowerJ creates native code for various Unices. Supercede has been sold to the Jove people, leaving the floor to Jet, BulletTrain, IBM Visual Age and JBuilder, Excelsior JET, GNU Java Compiler for Linux; Jove, Webgain Café, TowerJ and gcj.
    compiler (with table showing how each compiler works), exe, installer, interpreter, jar, J2Exe, Java2exe, NativeJ, Jexegen, JIT, JVM, optimiser, Marco Schmidt's list of native compilers, the Bear Cave list of native compilers

    SWT打包方法

    在打包SWT程序時候需要注意下,需要自己手動加載win32的動態連接庫,一般名稱爲swt-win32-****.dll。****処一般為版本識別號。
    如果沒有加載的話,打包好程序啓動會出現以下錯誤提示。
    Photobucket - Video and Image Hosting
     
    解壓好后,將swt-win32-3232.dll複製到要打包的工程項目下(此dll僅僅針對windows系統)
    ps:如果需要在非windows系統下運行,則需要其相對應的插件。需要到http://www.eclipse.org/尋找
     
    使用複製-〉粘貼 即可完成
    Photobucket - Video and Image Hosting
     
    完成后工程項目下應該有如下文件
    Photobucket - Video and Image Hosting
     
    再次使用FarJar打包,點擊jar包即可運行
    Photobucket - Video and Image Hosting
     
    值得注意的是可以直接複製swt-win32-****.dll放入系統Windows/System32目錄下,這樣就不需要為每一個打包項目加載swt-win32-****.dll即可以直接在本機運行了。
     
    打包推薦使用FatJar,eclipse的第三方插件,非常好用,能自動完成打包這繁瑣的工作!

    Http協議中get與post傳輸方式的區別

     
      在B/S應用程式中,前臺與後臺的數據交互,都是通過HTML中Form表單完成的。Form提供了兩種數據傳輸的方式——get和post。雖然它們都是數據的提交方式,但是在實際傳輸時確有很大的不同,並且可能會對數據產生嚴重的影響。雖然為了方便的得到變數值,Web容器已經遮罩了二者的一些差異,但是了解二者的差異在以後的編程也會很有幫助的。
     
    Form中的get和post方法,在數據傳輸過程中分別對應了HTTP協議中的GET和POST方法。二者主要區別如下:
    1、Get是用來從伺服器上獲得數據,而Post是用來向伺服器上傳遞數據。
    2、Get將表單中數據的按照variable=value的形式,添加到action所指向的URL後面,並且兩者使用“?”連接,而各個變數之間使用“&”連接;Post是將表單中的數據放在form的數據體中,按照變數和值相對應的方式,傳遞到action所指向URL。
    3、Get是不安全的,因為在傳輸過程,數據被放在請求的URL中,而如今現有的很多伺服器、***或者用戶代理都會將請求URL記錄到日誌文件中,然後放在某個地方,這樣就可能會有一些隱私的資訊被第三方看到。另外,用戶也可以在瀏覽器上直接看到提交的數據,一些系統內部消息將會一同顯示在用戶面前。Post的所有操作對用戶來說都是不可見的。
    4、Get傳輸的數據量小,這主要是因為受URL長度限制;而Post可以傳輸大量的數據,所以在上傳文件只能使用Post(當然還有一個原因,將在後面的提到)。
    5、Get限制Form表單的數據集的值必須為ASCII字符;而Post支援整個ISO10646字符集。
    6、Get是Form的默認方法。
     
    所以我們在傳送一些内容較少、不涉及安全性相關的内容時可以選擇get方式,否則則必須選用post方式了。倘若是向服務器傳送文件時,則必須採用post方式。

    MyEclipse中使用JSTL

    基本配置:Eclipse 3.2   MyEclipse 5.0
     
    首先新建web 項目,選擇項目點擊右鍵->MyEclipse->Add JSTL Libraries,把JSTL加載進項目
    snap003_.jpg
     
    加載完成后,應該在項目下WebRoot->WEB-INF有如下TLD文件
    snap004_.jpg
    然後配置Web.xml文件,注意2.4版本的配置和2.3以前本版的配置有所區別,把跟jsp设置有关的内容都放在<jsp-config></jsp-config>里面,所以<taglib>項要寫在<jsp-config>内,否則會提示有錯誤!

    snap005_.jpg

    安2.3版本以前的寫法則會出現錯誤,此要注意!
    snap002_.jpg
    保存后,新建jsp文件,測試JSTL是否安裝成功!
    snap006_.jpg

    snap007_.jpg

    大功告成,一下就可以用JSTL編寫了

     

    JSTL 1.0

    JSTL 1.0 发布于 2002 年 6 月,由四个定制标记库( coreformatxmlsql )和一对通用标记库验证器( ScriptFreeTLVPermittedTaglibsTLV )组成。 core 标记库提供了定制操作,通过限制了作用域的变量管理数据,以及执行页面内容的迭代和条件操作。它还提供了用来生成和操作 URL 的标记。顾名思义, format 标记库定义了用来格式化数据(尤其是数字和日期)的操作。它还支持使用本地化资源束进行 JSP 页面的国际化。 xml 库包含一些标记,这些标记用来操作通过 XML 表示的数据,而 sql 库定义了用来查询关系数据库的操作。

    两个 JSTL 标记库验证器允许开发人员在其 JSP 应用程序中强制使用编码标准。可以配置 ScriptFreeTLV 验证器以在 JSP 页面中禁用各种类型的 JSP 脚本元素 ― scriptlet、表达式和声明。类似地, PermittedTaglibsTLV 验证器可以用来限制可能由应用程序的 JSP 页面访问的定制标记库集(包括 JSTL 标记库)。

    尽管 JSTL 最终将会成为 J2EE 平台的必需组件,但目前只有少数应用程序服务器包括它。JSTL 1.0 的参考实现可作为 Apache 软件基金会(Apache Software Foundation)的 Jakarta Taglibs 项目(请参阅 参考资料)的一部分而获得。可以将该参考实现中的定制标记库合并到任何支持 JSP 1.2 和 Servlet 2.3 规范的服务器,以添加对 JSTL 的支持。

     

    JAVA文件操作的編寫

    /** 
     *  <p>Title:  文件的各种操作</p> 
     *  <p>Copyright:  FAF  (c)  2006</p> 
     *  <p>Company:  FAIRY AIR FORCE</p> 
     *  @author  FAF-Rei 
     *  @version  1.0 
     */
     
    package  faf.rei.common; 
     
    import  java.io.*; 
     
    public  class  FileOperate  { 
     
       /** 
        *  打开文件 
        *  @param  filePath  String  如  c:/fqf 
        *  @return  String 
        */ 
       public static String openFile(String filePath) throws IOException{
        
         java.io.File myfile=new java.io.File(filePath);  
         int flength=(int)myfile.length();
         int num=0;
         char[] data=new char[flength];;
         FileReader fReader=new FileReader(myfile);  
         while(fReader.ready()){   
         num+=fReader.read(data,num,flength-num); 
        } 
          fReader.close(); 
          String filecontent=new String(data,0,num);
          return filecontent;
       }
      
      
       /** 
         *  新建目录 
         *  @param  folderPath  String  如  c:/fqf 
         *  @return  boolean 
         */ 
       public static void  newFolder(String  folderPath) throws IOException{  
            
               java.io.File  myFilePath  =  new  java.io.File(folderPath); 
               if  (!myFilePath.exists())  {    
                   if(!myFilePath.mkdirs()) {
                      throw new IOException("create folder failture");
                  }         
               }       
       } 
     
       /** 
         *  新建文件 
         *  @param  filePathAndName  String  文件路径及名称  如c:/fqf.txt 
         *  @param  fileContent  String  文件内容 
         *  @return  boolean 
         */ 
       public static void  newFile(String  filePathAndName,  String  fileContent)  throws IOException {  

               File  myFilePath  =  new  File(filePathAndName); 
               if  (!myFilePath.exists())  { 
                   myFilePath.createNewFile(); 
               } 
               FileWriter  resultFile  =  new  FileWriter(myFilePath); 
               PrintWriter  myFile  =  new  PrintWriter(resultFile); 
               String  strContent  =  fileContent; 
               myFile.println(strContent); 
               resultFile.close();  
     
       } 
     
       /** 
         *  删除文件 
         *  @param  filePathAndName  String  文件路径及名称  如c:/fqf.txt 
         *  @return  boolean 
         */ 
       public static void  delFile(String  filePathAndName) throws IOException  {  
            
               java.io.File  myDelFile  =  new  java.io.File(filePathAndName); 
               if(!myDelFile.delete()){
                   throw new IOException("delete file failture");
               }
         } 
     
       /** 
         *  删除文件夹及里面的所有内容
         *  @param  folderPath  String  文件夹路径及名称  如c:/fqf 
         *  @return  boolean 
         */ 
       public static void  delFolder(String  folderPath)   { 
           
               delAllFile(folderPath);  //删除完里面所有内容 
               String  filePath  =  folderPath; 
               filePath  =  filePath.toString(); 
               java.io.File  myFilePath  =  new  java.io.File(filePath); 
               myFilePath.delete();  //删除空文件夹  

       } 
     
       /** 
         *  删除文件夹里面的所有文件 
         *  @param  path  String  文件夹路径  如  c:/fqf 
         */ 
       public static void  delAllFile(String  path)   { 
          
           File  file  =  new  File(path); 
           if  (!file.exists())  { 
               return; 
           } 
           if  (!file.isDirectory())  { 
               return; 
           } 
           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]);//先删除文件夹里面的文件 
                   delFile(path+"/"+  tempList[i]);//再删除空文件夹 
               } 
           } 
       } 
     
       /** 
         *  复制单个文件 
         *  @param  oldPath  String  原文件路径  如:c:/fqf.txt 
         *  @param  newPath  String  复制后路径  如:f:/fqf.txt 
         *  @return  boolean 
         */ 
       public static void  copyFile(String  oldPath,  String  newPath)  throws IOException {  
       
               int  bytesum  =  0; 
               int  byteread  =  0; 
               File  oldfile  =  new  File(oldPath); 
               if  (oldfile.exists())  {  //文件存在时 
                   InputStream  inStream  =  new  FileInputStream(oldPath);  //读入原文件 
                   FileOutputStream  fs  =  new  FileOutputStream(newPath); 
                   byte[]  buffer  =  new  byte[1444]; 
                 
                   while  (  (byteread  =  inStream.read(buffer))  !=  -1)  { 
                       bytesum  +=  byteread;  //字节数  文件大小 
                       System.out.println(bytesum); 
                       fs.write(buffer,  0,  byteread); 
                   } 
                   inStream.close(); 
               }  
     
       } 
     
       /** 
         *  复制整个文件夹内容 
         *  @param  oldPath  String  原文件路径  如:c:/fqf 
         *  @param  newPath  String  复制后路径  如:f:/fqf/ff 
         *  @return  boolean 
         */ 
       public static void  copyFolder(String  oldPath,  String  newPath)  throws IOException {  
       
               (new  File(newPath)).mkdirs();  //如果文件夹不存在  则建立新文件夹 
               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()){//如果是子文件夹 
                       copyFolder(oldPath+"/"+file[i],newPath+"/"+file[i]); 
                   } 
               }  
     
       } 
     
       /** 
         *  移动文件到指定目录 
         *  @param  oldPath  String  如:c:/fqf.txt 
         *  @param  newPath  String  如:d:/fqf.txt 
         */ 
       public static void  moveFile(String  oldPath,  String  newPath)  throws IOException {  
      
            copyFile(oldPath,  newPath); 
            delFile(oldPath);  
            
       } 
     
       /** 
         *  移动文件到指定目录 
         *  @param  oldPath  String  如:c:/fqf.txt 
         *  @param  newPath  String  如:d:/fqf.txt 
         */ 
       public static void  moveFolder(String  oldPath,  String  newPath)  throws IOException {  

            copyFolder(oldPath,  newPath); 
            delFolder(oldPath);  

       } 
    }
     
    次類為自己編寫,基本文件功能都實現,如閣下有改進或更爲高效的代碼編寫歡迎指出!

    SWT Designer 5.0 .1注册方法

    SWT Designer这个工具对于编写swt代码帮助很大,支持可视化开发,所见即所得。但是非注册版屏蔽了很多有用的功能,对于平时编程很不方便。特发此注册方法,希望大家受用!

     

    SWT Designer 5.0 .1下载地址: http://download.instantiations.com/Designer/integration/latest/Designer_v5.0.1_for_Eclipse3.2.zip

     

    注册有两种工具,以下将分别介绍:

    A.使用SWT-keygen 2.0 (建议使用)

    下载地址:http://www.thefilehut.com/userfiles/gufen/forblog/swt.designer.pro.keygen.for.eclipse.3.1.rar

    解压后运行其目录下的swt.ui,会跳出一个swt designer keygen 2.0对话框。

    然后启动eclipse 3.2。(注:SWT Designer 5.0 .1支持eclipse 3.2,不清楚3.2以下版本是否支持)

    打开首选项

     

    选择Designer

    根据installation root中的版本信息在keygen的Version中输入其相对版本号(如下图所示)

    然后点击“Registration and Activate”

     

     

    根据下图显示选择,然后点击“下一步”

     

    把其中的选项填写完(随便填),点击“下一步”

     

    此处要填写序列号,点击keygen上的Generate,会生成一个序列号,把此号分别填入对应输入框,然后点击“下一步”

     

     

    如果注册成功,其后跳出的对话框会显示activation is complete。这样注册就成功了。如下

     

    B.使用SWT.Designer_Window.Builder.Pro_v5.0.x_for_Eclipse3.2_Keygen

    下载地址:http://lihongjun.blog.ccidnet.com/job.php?action=download&pid=&tid=57071&aid=6416

    把里面的文件全部解压至eclipse安装目录下。

    然后点击win32.bat文件,会跳出一个cmd控制台里面有一个序列号。

     

    然后启动eclipse。打开“首选项”-->“designer”-->“License”,把 "Automaticaly activate when possible"前的勾去掉,点击确定。然后点击Registration and Activate”,其后按照上面相应步骤进行。最后序列号就用把刚才生成的序列号填上即可

    JAVA Programming ①

     
     

     

     

     

    ⒈方法的覆盖、隐藏:
     

    什么时候方法被真正覆盖了,什么时候方法只是被隐藏了。有几点注意事项:
    1.试图用子类的静态方法隐藏父类中同样标识的实例方法是不合法的,编译器将会报错。
    2.试图用子类的实例方法覆盖父类中同样标识的静态方法是不合法的,编译器同样会报错。

    3.静态方法和最终方法(带关键字final)不能被覆盖。

    4.实例方法能够被覆盖。

    5.抽象方法必须在具体类中被覆盖。

     

    这里我们可以看一个实例:

    class Super

    {

       static String greeting()

      {

          return "goodnight";

       }

     

        String name()

        {

            return "richard";

        }

    }

     

    class Sub extends Super

    {

         static String greeting()

         {

         return"hello";

          }

     

          String name()

          {

          return "dick";

          }

    }

     

    class test

    {

          public static void main(String[] args)

         {

           Super s=new Sub();

           System.out.pringln(s.greeting()+","+s.name();

          }

    }

     

     

    你觉得这个地输出结果是什么呢?

    A.hello,dick

    B.hello,richard

    C.goodnight,richard

    D.goodnight,dick

     

     

    正确答案是:A

     

     

    恭喜你答错了。真正的正确答案是:D

     

    如果你获得出了同样的输出结果,你对方法的覆盖有了很好的理解。如果选错了,也不要丧气。

    在这里你必须明白的是虽然变量s数据类型为Super类,但仍是苏sub类的一个实例。父类Super中greeting()是静态方法,name()是实例方法。子类Sub中greeting()是静态方法,name()是实例方法。参照一下刚开始所提到的注意事项,相信很快就会恍然大悟了吧。父类的静态方法是不能被子类的静态方法覆盖的,他只是被子类的静态方法隐藏了。实例方法能够被覆盖。

     

    2.String.equals()方法与“==”运算符的比较

      在讲解具体概念前我们先看一个例子:

      public class StringExample

      {

         String s0="Programming";

         String s1=new String("Programming");

         String s2="Program"+"ming";

        

         System.out.println("s0.equals(s1):"+(s0.equals(s1)));

         System.out.println("s0.equals(s2):"+(s0.equals(s2)));

         System.out.println("s0==s1:"+(s0==s1));

         System.out.println("s0==s2:"+(s0==s2));

        }

      }

    你认为答案会是什么呢?

    A.s0.equals(s1):true

       s0.equals(s2):true

       s0==s1:false

       s0==s2:true

    B.s0.equals(s1):false

       s0.equals(s2):false

       s0==s1:true

       s0==s2:true

    C.s0.equals(s1):true

       s0.equals(s2):false

       s0==s1:true

       s0==s2:false

    D.s0.equals(s1):false

       s0.equals(s2):true

       s0==s1:false

       s0==s2:true

     

    答案选A

     

     

     

    恭喜你,答...........对了。

     

      在这里我们要弄清楚这个例子包含了3个String型变量,其中两个被赋值以常量表达式“Programming",另一个被赋值以一个新建的值为“Programming"得String类的实例。

      String.equals()方法比较的是字符串的内容。使用equals(...)方法,会对字符串的所有字符一个接一个进行比较。如果完全相同,那么返回true。在这种情况下,全部三个字符串都是相同的。运算符“==”比较的是String实例的引用。在这种情况下,很明显s0和s1并不是一个String实例,但s0和s2却是同一个。那么s0和s2怎么是同一个对象呢?这个就要看JAVA语言规范中关于字符串常量(String Literals)的章节。此例中,“Programming”,“Program”和“ming”都是字符串常量,他们在编译时就被确定了。当一个字符串由多个字符串常量连接而成的,例如s2,它同样是在编译期就被解析为一个字符串常量。JAVA确保一个字符串常量只有一份拷贝。所以当“Programming"和"Program"+"ming"被确定为值相等时,Java会设置两个变量的引用为同一个常量的引用。在常量池(constant pool)中,Java会跟踪所有的字符串常量。

    在这里我们看一下常量池解析操作的步骤:(JVM规范5.4节)

    1.如果另一个常量池入口(constant pool entry)被标记为CONSTANT_String,并且指出同样的Unicode字符序列已经被解析,那么这项操作的结果就是为之前的常量池入口创建的String实例的引用。

    2.否则,如果innern()方法已经被这个常量池表述的一个包含同样的Unicode字符序列得String实例调用过了,那么这项操作的结果就是那个相同String实例的引用。

    3.否则,一个新的String实例会被创建。它包含了CONSTANT_String入口描述的Unicode字符序列:这个String实例就是该项操作的终结。

     

    当常量池第一次确定一个字符串,在Java内存栈中就创造一个String实例。在常量池中,后来的所有针对同样字符串内容的引用,都会得到之前创建的String实例。

     

    经过这么详细地讲解,应该理解"equals"和“==”的区别了巴,如果仍旧没有理解,建议仔细看一下《CORE JAVA 1》。

     

     

     
       

    SWT/JFACE 编程心得

     
     
     
      一.下拉菜单的编写:
     
    Menu先前赋值,必须为SWT.POP_UP;
    按键的箭头下拉菜单编写:
    ToolItem.addListener(SWT.Selection, new Listener() {  
              public void handleEvent(Event event) {      
                     if (event.detail == SWT.ARROW) {           
                           Rectangle rect = ToolItem.getBounds();          
                           Point pt = new Point(rect.x, rect.y +                          rect.height);      
                           pt = ToolBar.toDisplay(pt);        
                           menu.setLocation(pt.x, pt.y);          
                           menu.setVisible(true);        }  
                                                                    }
                                                                               });
    按键主体的事件处理:
    ToolItem.addListener(SWT.Selection, new Listener() {  
              public void handleEvent(Event event) {      
                     if (event.detail == SWT.NULL) {  
                                  ............        
                                                                  }   
                                                                     }
                                                                   });
     
    二.使用viewform的注意事项:
     
    viewform做底层容器,在这之上建立toolbar内toolitem按钮将无法正常显示图片,甚至不能显示按钮。只能够显示文字。经过与《精通eclipse》作者陈刚联系证实,此确实是一个bug。本来心存好感的swt/jface居然出现了这样低级的bug,真是让人心寒,swt/jface类中甚至都不支持数组创建,艾~~
    希望在以后的版本中能够加以改正阿。有些GUI的编写不得不又得用SWING类了,累啊,真的好累啊。