显示标签为“Java”的博文。显示所有博文
显示标签为“Java”的博文。显示所有博文

2012年12月20日星期四

Hibernate中findById时出现org.hibernate.MappingException: Unknown entity:的解决办法

 

原因:在使用myeclispe生成pojo和DAO代码后,对相关类进行了重构,改变了包。造成反射时找不到类。

出现错误的findById代码

public Trace findById(Long id) {
        log.debug("getting Trace instance with id: " + id);
        try {
            Trace instance = (Trace) getHibernateTemplate().get("Trace", id);
            return instance;
        } catch (RuntimeException re) {
            log.error("get failed", re);
            throw re;
        }
    }

 

修改后的方法

public Trace findById(Long id) {
        log.debug("getting Trace instance with id: " + id);
        try {
            Trace instance = (Trace) getHibernateTemplate().get("cn.cslg.Trace", id);
            return instance;
        } catch (RuntimeException re) {
            log.error("get failed", re);
            throw re;
        }
    }

2012年12月15日星期六

使用MyEclipse生成hibernate pojo和dao的过程

 

首先在MyEclipse中配置好数据源并打开。

选择需要生成pojo的表。

在右键菜单中选择 Hibernate Reverse Engineering,按下面的步骤进行设置。

生成pojo和dao之后,可以移动到相关的包。在DAO类中可以通过重构,将方法提取到DAO接口。

注意:如果表中没有主键,则会生成一个额外的类,并使用全部字段作为联合主键。

 

QQ截图20121215185333

 

QQ截图20121215185352

QQ截图20121215185407

2012年2月19日星期日

ACM在线评判系统的原理

 

一、自动编译

在程序中通过启动编译器进程对源文件进行编译,通过获取编译器进程的错误输出流和标准输出流对象,可以获取编译器的输出,判断是否有编译错误发生,同时,再通过检查源文件目录下有无生成的可执行文件或者class文件,可判断最后的连接是否成功

二、运行和判断核心

如果自动编译成功,则需要根据预定义的测试用例对生成的可执行文件进行判断。过程大致如下:

1 主程序

1.1 在主程序中输入可执行文件名,相关的命令行参数,测试用例的个数,测试用例的执行时间限制,内存使用限制,测试用例文件名信息(输入文件和输出文件必须是成对出现的);

1.2 创建RunCmd对象,通过构造方法的参数将第一步输入的数据传递给RunCmd对象,启动RunCmd的方法doWork作为线程体进行评判。

2 线程RunCmd(doWork)

2.1 创建一个新的进程,相关参数为第一步中的可执行文件名和相关的命令行参数,并设置进程的输入输出和标准错误输出的重定向

2.2 启动进程,获取其标准输入流对象

2.3 打开一个测试用例输入文件,将其中的内容写入到2.2启动的进程的标准输入

2.4 获取进程的内存使用大小

2.5 线程睡眠一段时间(长度为测试用例的最长执行时间限制)

2.6 如果进程未结束,则杀死进程,将超时的代码写到标准输出,线程返回

2.7 如果内存使用超过限制,则将Time Limit Exceeded的代码写到标准输出,线程返回

2.8 获取标准错误输出和标准输出的内容

2.8.1 如果进程返回代码不为0或标准错误输出内容不为空,则将Run Time Error的代码写到标准输出,线程返回

2.8.2 将获得的输出结果与测试用例中的输出文件进行比较,将返回Wrong Answer,Accepted或者Presentation Error的代码

2.8.3 输出执行时间、内存大小等信息到标准输出

2.9 如果在执行过程中遇到内存不足或其他异常,则输出system error的代码或者Output Limit Exceeded的代码

在这个核心的基础上,很容易就可以开发出ACM OJ系统,在线考试系统,实验自动批改的系统等

2011年8月16日星期二

exe4j生成的exe文件的unpack

今天看到一个比较实用的Java软件,想知道它是如何实现的,但是这个软件已经使用exe4j封装成了可执行文件。通过搜索网络,看到下面的这篇文章:

http://www.blogjava.net/cnfree/archive/2010/08/22/329559.html

其中的关键:

  1. exe文件的解码(OR 88)
  2. 使用WinHex从解码后的文件中分离出jar文件

其中第一步在文中已经给出了源代码如下:

import java.io.*;
import java.util.*;
public class gen {
public static void main(String args[]) throws IOException {
        FileInputStream fin = new FileInputStream(args[0]); // 可以将整个exe文件解码
        FileOutputStream fout = new FileOutputStream(args[1]);
        BufferedInputStream bin = new BufferedInputStream(fin);
        BufferedOutputStream bout = new BufferedOutputStream(fout);
int in = 0;
do {
            in = bin.read();
if (in == -1)
break;
            in ^= 0x88;
            bout.write(in);
        } while (true);
        bin.close();
        fin.close();
        bout.close();
        fout.close();
    }
}

第二步在文章中是这样描述的:

分析提取出来的数据文件,使用WinHex查看其16进制代码。由于Jar文件的开头总是PK开头,并且总包含有manifest.mf文件,并且结尾总是有3个00,同时结尾段有整个Jar包文件的索引,我们可以根据这一特性来分析我们需要的片段。
1、搜索Jar的manifest,然后往前找,找到的第一个PK段,即为一个Jar的开头。
2、查看片段里Jar里的每个class信息,直到最后的文件索引片段。
3、一个Jar的结束片段位于索引片段之后,仍然包含着PK段,并且最后包含着3个00,且这3个00距离PK大概20个字节左右
根据以上3条准则,足以提取整个Jar数据段,然后导入新文件中,并且以zip字段命名,尝试用ZIP解压缩软件打开,看看是否抽取正确。

这个步骤需要不断尝试才能得到正确的文件,通过实践发现有更简单的方法:在解码后的文件中,如果包含多个jar文件,则之间用十六进制88分隔,每个jar文件均以PK开始,因此可以在WinHex中这样操作:

搜索十六进制串:88888888504B03040A00,其中前面的88分隔符可以根据需要调整数量,将找到的PK(504B)标注为块的开始,按F3再次搜索此特征串,从找到的下一个位置处往前搜索到第一个非88的字节作为块的结束,然后在Edit|Block中将选中的块插入到新文件即可,现在找到的PK的位置即为下一个jar文件的开始。依次类推,可分离出所有的jar文件,注意:最后一个jar文件的结束是PK200 (即jar文件所使用的压缩算法)。

经过实践,这个方法能快速地找到并分离exe4j打包的exe文件中的jar文件。

更简单的方法是:

打包成可执行文件的Java程序在运行时,会将jar全部解压然后调用java运行库执行,只要到系统temp文件夹中搜索*.jar即可得到。

2010年12月22日星期三

计算考试剩余时间

        String start = (String) session.getAttribute("StartTime");
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date date = null;
        try {
            date = format.parse(start);
        } catch (ParseException e) {
            throw new ServletException(e);
        }

        Calendar c = Calendar.getInstance();

        long escape = (c.getTimeInMillis() - date.getTime()) / (1000 * 60);
        long remain = (Integer) session.getAttribute("Minutes") - escape;

2010年12月16日星期四

java中调用mysql存储过程

 

有参数的情况

CallableStatement cstmt=conn.prepareCall("{call hasContest(?)}");
cstmt.registerOutParameter(1, Types.BOOLEAN);
cstmt.execute();
boolean b=cstmt.getBoolean(1);

 

无参数的情况

CallableStatement cstmt=conn.prepareCall("{call hasContest}");
ResultSet rs=cstmt.executeQuery();
rs.next();
return rs.getBoolean(1);

 

给定的数据库用户必须具有执行的权限,同时在数据的url中要添加参数,如下所示

jdbc:mysql://10.28.79.2:3306/cbbt?noAccessToProcedureBodies=true

2010年5月1日星期六

XSLT中for-each的select语法问题

在一个程序中,要用到如下的XSL用于XSLT转换

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output encoding="utf-8"/>
<xsl:template match="/">
<messages>
    <xsl:for-each select="//tr[@bgcolor='#f3f2f1' and position()>=3 and position()<last()]">
        <message>
            <msgid>
                <xsl:value-of select="td[1]/div/input/@value"/>
            </msgid>
            <teacher>
                <xsl:value-of select="td[3]/div"/>
            </teacher>
            <content>
                <xsl:value-of select="td[4]/div"/>
            </content>
            <timestamp>
                <xsl:value-of select="td[6]/div"/>
            </timestamp>
        </message>
    </xsl:for-each>
</messages>
</xsl:template>
</xsl:stylesheet>

在.NET中报错,出错信息为:

未处理 System.Xml.Xsl.XslLoadException
  Message="XSLT 编译错误。"
  Source="System.Data.SqlXml"
  LineNumber=6
  LinePosition=81
  SourceUri="file:///D:/myprog/C%23/jxlltEasy/jxlltEasy/bin/Debug/msg.xsl"
  StackTrace:
       在 System.Xml.Xsl.Xslt.XsltLoader.LoadStylesheet(XmlReader reader, Boolean include)
       在 System.Xml.Xsl.Xslt.XsltLoader.Load(Compiler compiler, Object stylesheet, XmlResolver xmlResolver)
       在 System.Xml.Xsl.Xslt.Compiler.Compile(Object stylesheet, XmlResolver xmlResolver, QilExpression& qil)
       在 System.Xml.Xsl.XslCompiledTransform.CompileXsltToQil(Object stylesheet, XsltSettings settings, XmlResolver stylesheetResolver)
       在 System.Xml.Xsl.XslCompiledTransform.LoadInternal(Object stylesheet, XsltSettings settings, XmlResolver stylesheetResolver)
       在 System.Xml.Xsl.XslCompiledTransform.Load(String stylesheetUri)
       在 jxlltEasy.jxlltForm.btnRefresh_Click(Object sender, EventArgs e) 位置 D:\myprog\C#\jxlltEasy\jxlltEasy\jxlltForm.cs:行号 120
       在 System.Windows.Forms.Control.OnClick(EventArgs e)
       在 System.Windows.Forms.Button.OnClick(EventArgs e)
       在 System.Windows.Forms.Button.OnMouseUp(MouseEventArgs mevent)
       在 System.Windows.Forms.Control.WmMouseUp(Message& m, MouseButtons button, Int32 clicks)
       在 System.Windows.Forms.Control.WndProc(Message& m)
       在 System.Windows.Forms.ButtonBase.WndProc(Message& m)
       在 System.Windows.Forms.Button.WndProc(Message& m)
       在 System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
       在 System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
       在 System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
       在 System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg)
       在 System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(Int32 dwComponentID, Int32 reason, Int32 pvLoopData)
       在 System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)
       在 System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)
       在 System.Windows.Forms.Application.Run(Form mainForm)
       在 jxlltEasy.Program.Main() 位置 D:\myprog\C#\jxlltEasy\jxlltEasy\Program.cs:行号 18
       在 System.AppDomain._nExecuteAssembly(Assembly assembly, String[] args)
       在 System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
       在 Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
       在 System.Threading.ThreadHelper.ThreadStart_Context(Object state)
       在 System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
       在 System.Threading.ThreadHelper.ThreadStart()
  InnerException: System.Xml.XmlException
       Message="“<”(十六进制值 0x3C)是无效的属性字符。 行 6,位置 81。"

       Source="System.Xml"
       LineNumber=6
       LinePosition=81
       SourceUri="file:///D:/myprog/C%23/jxlltEasy/jxlltEasy/bin/Debug/msg.xsl"
       StackTrace:
            在 System.Xml.XmlTextReaderImpl.Throw(Exception e)
            在 System.Xml.XmlTextReaderImpl.Throw(String res, String[] args)
            在 System.Xml.XmlTextReaderImpl.Throw(Int32 pos, String res, String[] args)
            在 System.Xml.XmlTextReaderImpl.ParseAttributeValueSlow(Int32 curPos, Char quoteChar, NodeData attr)
            在 System.Xml.XmlTextReaderImpl.ParseAttributes()
            在 System.Xml.XmlTextReaderImpl.ParseElement()
            在 System.Xml.XmlTextReaderImpl.ParseElementContent()
            在 System.Xml.XmlTextReaderImpl.Read()
            在 System.Xml.Xsl.Xslt.XsltInput.ReadNextSiblingHelper()
            在 System.Xml.Xsl.Xslt.XsltInput.ReadNextSibling()
            在 System.Xml.Xsl.Xslt.XsltInput.MoveToFirstChildAny()
            在 System.Xml.Xsl.Xslt.XsltInput.MoveToFirstChild()
            在 System.Xml.Xsl.Xslt.XsltLoader.LoadInstructions(List`1 content, InstructionFlags flags)
            在 System.Xml.Xsl.Xslt.XsltLoader.LoadLiteralResultElement(Boolean asStylesheet)
            在 System.Xml.Xsl.Xslt.XsltLoader.LoadInstructions(List`1 content, InstructionFlags flags)
            在 System.Xml.Xsl.Xslt.XsltLoader.LoadTemplate(NsDecl stylesheetNsList)
            在 System.Xml.Xsl.Xslt.XsltLoader.LoadRealStylesheet()
            在 System.Xml.Xsl.Xslt.XsltLoader.LoadDocument()
            在 System.Xml.Xsl.Xslt.XsltLoader.LoadStylesheet(XmlReader reader, Boolean include)
       InnerException:

在Java中,出错信息为:

Fatal Error] :6:80: The value of attribute "select" associated with an element type "xsl:for-each" must not contain the '<' character.
Exception in thread "main" org.xml.sax.SAXParseException: The value of attribute "select" associated with an element type "xsl:for-each" must not contain the '<' character.
    at org.apache.xerces.parsers.DOMParser.parse(Unknown Source)
    at cn.ldsoft.xpath.XMLHelper.parseXMLFromInputSource(XMLHelper.java:70)
    at cn.ldsoft.xpath.XMLHelper.parseXMLFromFile(XMLHelper.java:62)
    at cn.ldsoft.simple.Test.main(Test.java:22)

通过查阅资料得知,

合法的过滤运算符:
  • =  (等于)
  • != (不等于)
  • &lt; (小于)
  • &gt; (大于)

将position()<last()改为position() &lt; last(), 问题解决

2010年4月16日星期五

线程安全的数据库连接管理器

package cn.cslg.xk.util;
/**
* @author 李庆
*@Email Kingstarforever@gmail.com
*@dtaeTime 2010-4-2
*/
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

import org.apache.log4j.Logger;

public class ConnectionManger {

    private static ThreadLocal<Connection> connectionHoder = new ThreadLocal<Connection>();

    public static Connection getConnection() {
        Connection conn = connectionHoder.get();
        if (conn == null) {
            try {
                conn = JndiBean.getConnection();
                connectionHoder.set(conn);
                System.out.println(conn);
            } catch (Exception e) {
            e.printStackTrace();
                //throw new AppException("系统出现故障,请联系管理员!");
            }
        }
        return conn;
    }

    public static void closeConnection() {
        Connection conn = connectionHoder.get();
        if (conn != null) {
            try {
                conn.close();
                connectionHoder.remove();
            } catch (SQLException e) {
            }

        }
    }

    public static void rollback() {
        try {
            Connection conn = connectionHoder.get();
            if (conn != null) {
                conn.rollback();
            }
        } catch (SQLException e) {
        }
    }

    public static void setCommit(boolean b) {
        try {
            Connection conn = connectionHoder.get();
            if (conn != null) {
                conn.setAutoCommit(b);
            }
        } catch (SQLException e) {
        }

    }

    public static void Commit() {
        try {
            Connection conn = connectionHoder.get();
            if (conn != null) {
                conn.commit();
            }
        } catch (SQLException e) {
        }

    }

    public static void closePs(PreparedStatement ps) {

        try {
            if (ps != null) {
                ps.close();
            }
        } catch (SQLException e) {
        }
    }

    public static void closeRs(ResultSet rs) {
        try {
            if (rs != null) {
                rs.close();
            }
        } catch (SQLException e) {
        }
    }

    public static void closeStatment(Statement s) {

        try {
            if (s != null) {
                s.close();
            }
        } catch (SQLException e) {
        }
    }
}

2009年10月18日星期日

Filter Servlet控制用户权限

//过滤器代码

package cn.cslg.labsys.filter;

import java.io.IOException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import javax.naming.NamingException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import cn.cslg.labsys.db.DBPoolException;
import cn.cslg.labsys.db.JndiBean;

/**
* 过滤器,对用户登录情况进行检查,如果用户未登录,则转到登录页面处理
*
* @author jimshen
*
*/
public class SessionChecker implements Filter {

    private String targetURI;

    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException {
        // 取得HTTP request/response/session对象
        HttpServletResponse httpResponse = (HttpServletResponse) response;
        HttpServletRequest httpRequest = (HttpServletRequest) request;
        HttpSession session = httpRequest.getSession(false);

        // 如果用户已登录,按既定流程运行
        try{
        if (session != null) {
            String user = (String) session.getAttribute("TNum");
            if (user != null) {
                String url = httpRequest.getRequestURI();
                if(pright(url,user)){
                    chain.doFilter(request, response);
                    return;
                }else
                    return;
            }
        }
        }catch(DBPoolException e){
            throw new ServletException(e);
        }catch(NamingException e){
            throw new ServletException(e);
        }catch(SQLException e){
            throw new ServletException(e);
        }
        httpResponse.sendRedirect(targetURI);

    }

    private boolean pright(String url, String tnum) throws DBPoolException,
            NamingException, SQLException {
        Connection conn = null;
        try {
            conn = JndiBean.getConnection();
            String sql="select * from priviledge where  locate(module,?)<>0 and Tnum=?";
            PreparedStatement pstmt=conn.prepareStatement(sql);
            pstmt.setString(1,url);
            pstmt.setString(2, tnum);
            ResultSet rs=pstmt.executeQuery();
            if(rs.next())
                return true;
            rs.close();
            pstmt.close();
            sql="select * from priviledge where locate(module,?)<>0";
            pstmt=conn.prepareStatement(sql);
            pstmt.setString(1,url);
            rs=pstmt.executeQuery();
            if(rs.next())
                return false;
            return true;
        } finally {
            if (conn != null)
                conn.close();
        }
    }

    public void init(FilterConfig filterConfig) throws ServletException {
        targetURI = filterConfig.getInitParameter("targetURI");
    }

    public void destroy() {
    }
}

//过滤器配置(web.xml)
<!-- filter to check user privilidge -->
    <filter>
        <filter-name>SessionChecker</filter-name>
        <filter-class>cn.cslg.labsys.filter.SessionChecker</filter-class>
        <init-param>
            <param-name>targetURI</param-name>
            <param-value>/LabSys/index.jsp</param-value>
        </init-param>
    </filter>

    <filter-mapping>
        <filter-name>SessionChecker</filter-name>
        <url-pattern>/outlines/*</url-pattern>
    </filter-mapping>
    <filter-mapping>
        <filter-name>SessionChecker</filter-name>
        <url-pattern>/labfile/*</url-pattern>
    </filter-mapping>

//priviledge表结构
TNum(用户名)    module(模块名,即目录名)
s09002        labfile
s09025        labfile

2009年5月30日星期六

Aptana Plugin For Eclipse 1.2.7 破解

针对最新的aptana_update_024747,可以从 http://www.aptana.com/download/下载并安装。

安装完成后,在eclipse/plugins目录中找到 com.aptana.ide.core_1.2.7.024747.jar

用jad或者相关反编译软件反编译 com.aptana.ide.core.licensing.ClientKey 这个类,我用的是 http://proglife.yo2.cn/articles/eclipse%E4%B8%8B%E7%9A%84%E5%8F%8D%E7%BC%96%E8%AF%91%E6%96%B9%E6%A1%88.html 里边的方案进行反编译的。

新建一个Java类ClientKey,将反编译出来的代码粘贴到这个类中,并修改如下:

package com.aptana.ide.core.licensing;

import java.util.Calendar;
import java.util.TimeZone;

public final class ClientKey
{
  public static final String BEGIN_LICENSE_MARKER = "--begin-aptana-license--";
  public static final String END_LICENSE_MARKER = "--end-aptana-license--";
  public static final int PRO = 0;
  public static final int TRIAL = 1;
  private static final TimeZone GMT = TimeZone.getTimeZone("GMT");
  public static final String EMAILS_NON_MATCHING = "EMAILS_NON_MATCHING";
  public static final ClientKey EMPTY_KEY = new ClientKey(1, "any@gmail.com", 0L);
  private String email;
  private long expiration;
  private int type;

  public ClientKey(int type, String email, long expiration)
  {
    this.type = type;
    this.email = email;
    this.expiration = expiration;
  }

  public boolean isCloseToExpiring()
  {
    return false;
  }

  public boolean isValid()
  {
    return true;
  }

  public boolean isCloseToMatching()
  {
    return true;
  }

  public boolean isExpired()
  {
   return false;
  }

  public String getEmail()
  {
      return "any@gmail.com";
  }

  public Calendar getExpiration()
  {
    Calendar expirationCal = Calendar.getInstance();
    expirationCal.add(Calendar.YEAR, 50);
    return expirationCal;
  }

  public boolean isTrial()
  {
    return false;
  }

  public boolean isPro()
  {
    return (!(isTrial()));
  }

  public boolean shouldProPluginsRun()
  {
    if (isPro())
    {
      return true;
    }
    return (!(isExpired()));
  }

  public static String trimEncryptedLicense(String encrypted)
  {
    String newEncrypted = encrypted;
    newEncrypted = newEncrypted.trim();
    newEncrypted = newEncrypted.replaceAll("--begin-aptana-license--", "");
    newEncrypted = newEncrypted.replaceAll("--end-aptana-license--", "");
    newEncrypted = newEncrypted.replaceAll("\\s+", "");
    return newEncrypted;
  }
}

注意红色的是修改的部分。

编译该文件,并用生成的class文件替换com.aptana.ide.core_1.2.7.024747.jar中的ClientKey.class文件。(可用winrar打开后直接拖进去覆盖)。

重新启动eclipse即可生效。效果图如下:

1

2009年4月13日星期一

[原创]通过Java程序实现Dr.COM Hotspot的上网验证

package drcom;

import java.io.IOException;
import java.io.InputStream;

import org.apache.commons.httpclient.DefaultHttpMethodRetryHandler;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.HttpMethod;
import org.apache.commons.httpclient.NameValuePair;
import org.apache.commons.httpclient.cookie.CookiePolicy;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.params.HttpMethodParams;

public class Login {

    String userAgent = "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; InfoPath.1; .NET CLR 2.0.50727; MAXTHON 2.0)";
    HttpClient client = new HttpClient();
    static final String TARGET_SITE = "10.29.0.250";
    static final int TARGET_PORT = 80;
    public static void main(String[] args) throws HttpException, IOException {
        Login l=new Login();
        PostMethod method=new PostMethod("http://10.29.0.250/F.htm");
        l.initMethod(method);
        l.fillLogonData(method);
        method.setRequestHeader("Referer","http://10.29.0.250/");
        l.client.executeMethod(method);
        String s=l.getResponse(method);
        System.out.println(s);
    }
    public Login() {
        client.getHostConfiguration().setHost(TARGET_SITE, TARGET_PORT);
    }

    public void initMethod(HttpMethod method) {
        method.setRequestHeader("User-Agent", userAgent);
        method.setRequestHeader("Accept-Encoding", "gzip, deflate");
        method.setRequestHeader("Accept-Language", "zh-cn");
        method.setRequestHeader("Accept", "*/*");
        method.setRequestHeader("Connection", "Keep-Alive");
        method.getParams().setCookiePolicy(CookiePolicy.RFC_2109);
        method.getParams().setParameter(HttpMethodParams.RETRY_HANDLER,
                new DefaultHttpMethodRetryHandler());
    }
    public String getResponse(HttpMethod method) throws IOException {
        InputStream is = method.getResponseBodyAsStream();
        StringBuffer buf = new StringBuffer();
        byte b[] = new byte[16384];
        int len = 0;
        while ((len = is.read(b)) > 0) {
            buf.append(new String(b, 0, len, "gb2312"));
        }
        String response = buf.toString();
        return response;
    }
    public void fillLogonData(PostMethod method) {
        NameValuePair[] data = new NameValuePair[3];
        data[0] = new NameValuePair("DDDDD", "username");
        data[1] = new NameValuePair("upass", "password");
        data[2]=new NameValuePair("0MKKey","登录 Login");
        method.addParameters(data);
    }

}

2009年4月2日星期四

Failed shutdown of Apache Portable Runtime

新安装的机器,在MyEclipse中停止Tomcat服务器时出现如下信息
[org.apache.catalina.core.AprLifecycleListener]-[INFO] Failed shutdown of Apache Portable Runtime

解决方法:

(1)安装Tomcat时预先安装native1.dll 或者

(2)去 http://tomcat.heanet.ie/native/ 下载编译好的 tcnative-1.dll 文件,放到Tomcat的bin目录下

2009年2月23日星期一

使用XPATH从XML/XHTML中提取数据

import java.io.StringReader;

import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;

import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;

public class Evaluation {
    public static String extractString(String xmlStr, String xpath)
            throws XPathExpressionException {
        XPathFactory factory = XPathFactory.newInstance();
        XPath xp = factory.newXPath();
        XPathExpression xpe = xp.compile(xpath);
        InputSource is = new InputSource(new StringReader(xmlStr));
        String result = xpe.evaluate(is);
        return result;
    }

    public static NodeList extractNodeList(String xmlStr, String xpath)
            throws XPathExpressionException {
        XPathFactory factory = XPathFactory.newInstance();
        XPath xp = factory.newXPath();
        XPathExpression xpe = xp.compile(xpath);
        InputSource is = new InputSource(new StringReader(xmlStr));
        NodeList result = (NodeList) xpe.evaluate(is, XPathConstants.NODESET);
        return result;
    }

    public static String extractString(Node node, String xpath)
            throws XPathExpressionException {
        XPathFactory factory = XPathFactory.newInstance();
        XPath xp = factory.newXPath();
        XPathExpression xpe = xp.compile(xpath);
        return xpe.evaluate(node);
    }
}

一个困扰了很久的XML类冲突问题的解决

有一个使用XML技术的项目,其中使用到了ASF的xerces软件包,在J2SE模式下,该程序运行正常,但是当将项目中的类导入了J2EE项目中,部署到Tomcat后无法将JSP页面转换为servlet,出现以下的错误

HTTP Status 500 -


type Exception report

message

description The server encountered an internal error () that prevented it from fulfilling this request.

exception

javax.servlet.ServletException: (class: org/apache/xerces/jaxp/DocumentBuilderImpl, method: parse signature: (Lorg/xml/sax/InputSource;)Lorg/w3c/dom/Document;) Incompatible object argument for function call
org.apache.jasper.servlet.JspServlet.service(JspServlet.java:272)
javax.servlet.http.HttpServlet.service(HttpServlet.java:802)


root cause



java.lang.VerifyError: (class: org/apache/xerces/jaxp/DocumentBuilderImpl, method: parse signature: (Lorg/xml/sax/InputSource;)Lorg/w3c/dom/Document;) Incompatible object argument for function call
org.apache.xerces.jaxp.DocumentBuilderFactoryImpl.newDocumentBuilder(Unknown Source)
org.apache.jasper.xmlparser.ParserUtils.parseXMLDocument(ParserUtils.java:92)
org.apache.jasper.compiler.JspConfig.processWebDotXml(JspConfig.java:76)
org.apache.jasper.compiler.JspConfig.init(JspConfig.java:197)
org.apache.jasper.compiler.JspConfig.findJspProperty(JspConfig.java:249)
org.apache.jasper.compiler.Compiler.generateJava(Compiler.java:112)
org.apache.jasper.compiler.Compiler.compile(Compiler.java:295)
org.apache.jasper.compiler.Compiler.compile(Compiler.java:276)
org.apache.jasper.compiler.Compiler.compile(Compiler.java:264)
org.apache.jasper.JspCompilationContext.compile(JspCompilationContext.java:563)
org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:303)
org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:314)
org.apache.jasper.servlet.JspServlet.service(JspServlet.java:264)
javax.servlet.http.HttpServlet.service(HttpServlet.java:802)


note The full stack trace of the root cause is available in the Apache Tomcat/5.5.17 logs.




初步判断是因为类的版本有冲突引起的问题。这个问题困扰了很久也没有解决,后来下载了新的xerces软件包替换了原来的版本,居然问题就解决了。



注意:在更换xerces软件包之后要clean以下项目,否则还会出现这个错误

2008年11月12日星期三

HttpClient中用POST方式提交中文数据时的解决方案

在用HttpClient编程时,如果用PostMethod提交中文数据,则在服务器端不能得到正确的数据,可以通过下面的方法解决:

1、从PostMethod派生一个类,并改写getRequestCharSet()方法

import org.apache.commons.httpclient.methods.PostMethod;

class UTF8PostMethod extends PostMethod {
    public UTF8PostMethod(String url) {
        super(url);
    }

    @Override
    public String getRequestCharSet() {
        // return super.getRequestCharSet();
        return "gb2312";
    }
}

2、在相关的地方,用UTF8PostMethod替换原来的PostMethod类

2008年10月4日星期六

Eclipse下的反编译方案

方案一:JAD

从http://www.kpdus.com/jad.html下载JAD,将可执行文件解压缩到Windows目录下(也可以是环境变量PATH所指定搜索路径的任意目录下);从http://jadclipse.sourceforge.net下载net.sf.jadclipse_3.3.0.jar,解压缩到Eclipse安装目录下的对应位置。

方案二:JD-GUI

从http://java.decompiler.free.fr/下载jd-gui-0.2.5.windows.zip,将可执行文件解压缩到Windows目录下;感谢CCF论坛的Hanzac会员对上面的jadclipse插件做了修改,使它能和JD-GUI配合使用,下载地址:http://www.newdisk.cn/mypane.aspx?down=ok&filepath=hanzac/net.sf.hnindev.jdadaptor_3.3.1.jar。将其解压缩到Eclipse安装目录下的对应位置。

注意:上述两套方案中的Eclipse插件只能安装一个。

安装完成之后做如下配置:

选择菜单项 Window | Preferences .... ,定位到如下图所示位置,在文件类型中选择*.class

000

按下方的Add...按钮,打开对话框,选择JadClipse Class File Viewer,并按OK确认。

001

在对话框中按“default”按钮将刚才选择的Viewer设置为Class文件的默认查看程序。

004

从项目中选择一个Class双击,可看到其源代码。

005

【推荐】优秀的Java反编译软件 - JD-GUI

只有一个小小的EXE,运行后直接打开class file或者jar file就能反编译,效果也很不错。UI有Eclipse的风格,Find和Firefox的Find操作风格一致。
现在还在开发中,功能不是特别完善,应该会不断完善下去。

软件主页:http://java.decompiler.free.fr/

Main features

  • JD-Core and JD-GUI are written in C++. This allows an extremely fast decompilation and a display.
  • JD-Core does not require the Java runtime environment for its functioning, therefore no special setup is required.
  • JD-Core works with most current compilers including the following:
    • jdk1.1.8
    • jdk1.3.1
    • jdk1.4.2
    • jdk1.5.0
    • jdk1.6.0
    • jikes-1.22
    • harmony-jdk-r533500
    • Eclipse Java Compiler v_677_R32x, 3.2.1 release
    • jrockit90_150_06
  • JD-Core supports the following new features of Java 5:
    • Annotations
    • Generics
    • Type “enum”
  • JD-GUI supports Drag and Drop.
  • JD-GUI supports JAR files.
  • JD-GUI displays color coded Java source code.
  • JD-GUI allows you to browse the “class” files hierarchy.
  • JD-Core and JD-GUI use the excellent cross-platform wxWidgets toolkit.

 

Technorati 标签: ,

Aptana-JavaScript开发利器及其安装

一个JS的编辑调试工具 Aptana,功能不错,可以在Firefox下调试JS代码,具有很强的代码辅助功能,可以在代码辅助中添加第三方的类库。

它的特性包括:
*JavaScript,JavaScript函数,HTML,CSS语言的Code Assist功能。
*Outliner(大纲):显示JavaScript,HTML和CSS的代码结构。
*支持JavaScript,HTML,CSS代码提示,包括JavaScript自定函数。
*代码语法错误提示。
*支持Aptana UI自定义和扩展。
*支持跨平台。
*支持FTP/SFTP。
*调试JavaScript。
*支持流行AJAX框架的Code Assist功能:AFLAX,Dojo,JQuery,MochiKit,Prototype,Rico,script.aculo.us,Yahoo UI,Ext。
*Adobe AIR与iPhone开发工具

一般我使用的是Eclipse插件版本,安装的方法有两种。在 http://www.aptana.com/docs/index.php/Plugging_Aptana_into_an_existing_Eclipse_configuration#Introduction 上有详细的说明。

以前在用下载后安装的方法时出错,所以一直使用的是在线安装的方式,但是这个网站速度期满无比,安装过程需要重试n次才能完成,非常麻烦。这次重新安装机器,偶尔使用了下载再安装的方法,一点问题都没有。

下载的地址是 http://update.aptana.com/update/studio/3.2/aptana_update_015414.zip
推荐使用迅雷下载。

在IBM DeveloperWorks网站上还看到了一篇利用Aptana和AIR来开发桌面应用程序的文章:使用 Ext、Aptana 和 AIR 构建桌面应用程序

 

Technorati 标签: ,,

2008年6月7日星期六

从IBM developerWorks上一篇关于Java内存泄漏的文章引起的讨论,内存泄漏产生 的原因和解决途径

在研究Java内存泄漏时,看到了这篇文章 http://www.ibm.com/developerworks/cn/java/l-JavaMemoryLeak/index.html

觉得其中的例子是有问题的,至少如果v(Vector对象)是局部变量的话就不会引起内存泄漏。

下面给出了一个简单的内存泄露的例子。在这个例子中,我们循环申请Object对象,并将所申请的对象放入一个Vector中,如果我们仅仅释放引用本身,那么Vector仍然引用该对象,所以这个对象对GC来说是不可回收的。因此,如果对象加入到Vector后,还必须从Vector中删除,最简单的方法就是将Vector对象设置为null。

Vector v=new Vector(10);
for (int i=1;i<100; i++)
{
Object o=new Object();
v.add(o);
o=null;
}

//此时,所有的Object对象都没有被释放,因为变量v引用这些对象。


同时,在www.matrix.org.cn上也找到了这篇文章,看到支持的批评的都有。


下面是一些有价值的一些观点:



1、这个根本不是计算机科学中所谓的“内存泄漏”,而是程序员心理上认为的“内存泄漏”,那个例子只能说是程序员有意想保存那些object在vector里,GC当然不会回收。


2、这不是内存泄漏的问题, java中不存在全局变量,因此上述的Vector肯定在一个Class之中,而当这个Class的对象不再被引用时Vector也就被释放了


3、我觉得这篇文章的例子不会存在内存泄漏啊,只要Vector不再被引用,不是就会释放所有的资源了吗?只不过是何时释放内存的问题罢了。作者是不是把没有及时释放内存也定义成了内存泄漏啊!这些内存最终都会释放的。不过作者的说法也不是没有借鉴意义,如果想及时的释放内存的话,还是需要考虑的。


4、“只要Vector不使用,GC还是会回收的,只是时间的问题。 ” ---------  如果是一个站点,同时在线人数多了,那些未释放的内存还不是让你的服务器完蛋。有内存在浪费而不懂得释放就像你花10块钱买别人1块钱能买到的东西一样浪费。总之一句话,编写程序时,发现能释放的,短时间内没用的马上就释放。


但是,当这个对象v是作为类的属性,特别是静态属性时,会引起很大的麻烦。


在《Effective Java 》中,第五条



Eliminate obsolete object references
When you switch from a language with manual memory management, such as C or C++, to a garbage-collected language, your job as a programmer is made much easier by the fact that your objects are automatically reclaimed when you're through with them. It seems almost like magic when you first experience it. It can easily lead to the impression that you don't have to think about memory management, but this isn't quite true.
Consider the following simple stack implementation:
Code View: Scroll / Show All
// Can you spot the "memory leak"?
public class Stack {
private Object[] elements;
private int size = 0;
private static final int DEFAULT_INITIAL_CAPACITY = 16;
public Stack() {
elements = new Object[DEFAULT_INITIAL_CAPACITY];
}
public void push(Object e) {
ensureCapacity();
elements[size++] = e;
}
public Object pop() {
if (size == 0)
throw new EmptyStackException();
return elements[--size];
}
/**
* Ensure space for at least one more element, roughly
* doubling the capacity each time the array needs to grow.
*/
private void ensureCapacity() {
if (elements.length == size)
elements = Arrays.copyOf(elements, 2 * size + 1);
}
}
There's nothing obviously wrong with this program (but see Item 26 for a generic version). You could test it exhaustively, and it would pass every test with flying colors, but there's a problem lurking. Loosely speaking, the program has a "memory leak," which can silently manifest itself as reduced performance due to increased garbage collector activity or increased memory footprint. In extreme cases, such memory leaks can cause disk paging and even program failure with an OutOfMemoryError, but such failures are relatively rare.
So where is the memory leak? If a stack grows and then shrinks, the objects that were popped off the stack will not be garbage collected, even if the program using the stack has no more references to them. This is because the stack maintains obsolete references to these objects. An obsolete reference is simply a reference that will never be dereferenced again. In this case, any references outside of the "active portion" of the element array are obsolete. The active portion consists of the elements whose index is less than size.
Memory leaks in garbage-collected languages (more properly known as unintentional object retentions) are insidious. If an object reference is unintentionally retained, not only is that object excluded from garbage collection, but so too are any objects referenced by that object, and so on. Even if only a few object references are unintentionally retained, many, many objects may be prevented from being garbage collected, with potentially large effects on performance.
The fix for this sort of problem is simple: null out references once they become obsolete. In the case of our Stack class, the reference to an item becomes obsolete as soon as it's popped off the stack. The corrected version of the pop method looks like this:
public Object pop() {
if (size == 0)
throw new EmptyStackException();
Object result = elements[--size];
elements[size] = null; // Eliminate obsolete reference
return result;
}
An added benefit of nulling out obsolete references is that, if they are subsequently dereferenced by mistake, the program will immediately fail with a NullPointerException, rather than quietly doing the wrong thing. It is always beneficial to detect programming errors as quickly as possible.
When programmers are first stung by this problem, they may overcompensate by nulling out every object reference as soon as the program is finished using it. This is neither necessary nor desirable, as it clutters up the program unnecessarily. Nulling out object references should be the exception rather than the norm. The best way to eliminate an obsolete reference is to let the variable that contained the reference fall out of scope. This occurs naturally if you define each variable in the narrowest possible scope (Item 45).
So when should you null out a reference? What aspect of the Stack class makes it susceptible to memory leaks? Simply put, it manages its own memory. The storage pool consists of the elements of the elements array (the object reference cells, not the objects themselves). The elements in the active portion of the array (as defined earlier) are allocated, and those in the remainder of the array are free. The garbage collector has no way of knowing this; to the garbage collector, all of the object references in the elements array are equally valid. Only the programmer knows that the inactive portion of the array is unimportant. The programmer effectively communicates this fact to the garbage collector by manually nulling out array elements as soon as they become part of the inactive portion.
Generally speaking, whenever a class manages its own memory, the programmer should be alert for memory leaks. Whenever an element is freed, any object references contained in the element should be nulled out.
Another common source of memory leaks is caches. Once you put an object reference into a cache, it's easy to forget that it's there and leave it in the cache long after it becomes irrelevant. There are several solutions to this problem. If you're lucky enough to implement a cache for which an entry is relevant exactly so long as there are references to its key outside of the cache, represent the cache as a WeakHashMap; entries will be removed automatically after they become obsolete. Remember that WeakHashMap is useful only if the desired lifetime of cache entries is determined by external references to the key, not the value.
More commonly, the useful lifetime of a cache entry is less well defined, with entries becoming less valuable over time. Under these circumstances, the cache should occasionally be cleansed of entries that have fallen into disuse. This can be done by a background thread (perhaps a Timer or ScheduledThreadPoolExecutor) or as a side effect of adding new entries to the cache. The LinkedHashMap class facilitates the latter approach with its removeEldestEntry method. For more sophisticated caches, you may need to use java.lang.ref directly.
A third common source of memory leaks is listeners and other callbacks. If you implement an API where clients register callbacks but don't deregister them explicitly, they will accumulate unless you take some action. The best way to ensure that callbacks are garbage collected promptly is to store only weak references to them, for instance, by storing them only as keys in a WeakHashMap.
Because memory leaks typically do not manifest themselves as obvious failures, they may remain present in a system for years. They are typically discovered only as a result of careful code inspection or with the aid of a debugging tool known as a heap profiler. Therefore, it is very desirable to learn to anticipate problems like this before they occur and prevent them from happening.


我的理解是,这个并不是真正意义上的内存泄漏,而是由于JVM GC的不可控和不确定性引起的。Java里全是句柄,内存是托管的;我们不可能造成内存丢失,有可能犯的错误是仍旧把持着句柄不放,造成内存无法回收。


主要是针对生命周期比较长的对象。例如,对Effective Java Item 5中的这个数组进行pop操作之后,有很长时间未操作,那个所引用的对象在所在单元被覆盖之前就不会被回收,造成所谓的“内存泄漏”。


当然,当这个对象消亡时,所引用的对象最终会释放。但是,如果有成千上万的用户访问时,集合一直保持着对实际已经不再使用的对象的引用,最终会导致OutOfMemory错误,这就是这儿“内存泄漏”的实质。


在编写程序时,应该尽量使用生命周期短的小对象。不要让生命周期很长的对象一直把持其他对象的引用不释放。


当然,如果上面例子中的属性是static的,那么问题就更严重了,因为一旦类被加载,那么该静态属性就一直存在了。


引用CCF会员太阳公公的话



在我看来Java内存泄漏主要存在两种地方:
1.静态变量:这个简单就不说了。
2.资源:涉及到数据库、网络、消息、文件等资源访问的地方。比如:曾经遇见Oracle JDBC的bug,一个查询结束了,却不释放连接。于是相关的资源统统不会释放。
3.死锁:例如线程死锁,资源是不会释放的。
通常情况下,写J2EE的Java程序,并不需要特别关注内存泄漏问题。
当然还有其他的情况造成JVM out of memory,并不一定是泄漏。
比如,曾经在一个高并发的Java程序中解析>50M的XML,造成内存溢出,即使那台服务器的内存有的是。我理解为JVM无法快速申请大量内存,配置JVM启动参数就可以解决了。
另外需要注意的是长时间的操作,系统不会释放这个操作中利用到的内存。
比如,通过一系列复杂查询统计后生成文件,这个过程如果比较长,这期间GC发生了也不会释放内存。
除此之外,JVM都有很多启动参数,是值得研究的。SUN JVM、BEA JRocket、IBM JVM的参数还有些不一样。


解决内存泄漏除了注意及时释放对象引用之外,还可以使用弱引用对象。IBM developerWorks上有两篇文章提到了这个问题:

http://www.ibm.com/developerworks/cn/java/j-refs/index.html

http://www.ibm.com/developerworks/cn/java/j-jtp11225/

根据上述两篇文章写了一小段测试代码:


import java.lang.ref.WeakReference;

public class WeakTest {
    public static void main(String[] args){
        String s=new String("Hello");
        WeakReference<String> wr=new WeakReference<String>(s);
        s=null;                                                                                //1
        System.gc();
        System.out.println(wr.get());
    }
}


其中s是强引用,wr是弱引用。当编号为1的语句存在时,最后输出的是null,说明gc之后弱引用的对象被回收了。

在Java中提供了现成的采用弱引用的集合类WeakHashMap。

2008年6月1日星期日

Java的自动装箱与拆箱

在JDK 1.5之前,只能往集合类中存放对象。基本类型的数据只能先包装成包装类对象才能放进去。在JDK 1.5中引入了自动装箱和拆箱的功能。

Integer i = 100;

相当于编译器自动为您作以下的语法编译:

Integer i = new Integer(100);

所以自动装箱与拆箱的功能是所谓的“编译器蜜糖”(Compiler Sugar),虽然使用这个功能很方便,但在程序运行阶段您得了解Java的语义。例如下面的程序是可以通过编译的:

Integer i = null;
int j = i;

这样的语法在编译时期是合法的,但是在运行时期会有错误,因为这种写法相当于:

Integer i = null;
int j = i.intValue();

null表示i没有参考至任何的对象实体,它可以合法地指定给对象参考名称。由于实际上i并没有参考至任何的对象,所以也就不可能操作intValue()方法,这样上面的写法在运行时会出现NullPointerException错误。

自动装箱、拆箱的功能提供了方便性,但隐藏了一些细节,所以必须小心。

那么自动装箱的原理是什么呢?

在《使用JProfiler剖析Java Application中对象的分配和回收(gc)》一文中,原先的代码是:

package my;

import java.io.IOException;
import java.util.ArrayList;

public class Test {

    public static void main(String[] args) throws IOException {
        char ch=' ';
        while(ch!='n')
            ch=(char)System.in.read();
        for(int i=0;i<1000;i++)
            test();
        ch=' ';
        while(ch!='n')
            ch=(char)System.in.read();
    }

    public static void test(){
        ArrayList<Integer> arr=new ArrayList<Integer>();
        for(int i=0;i<10000;i++)
            arr.add((int)(Math.random()*100));
        //arr.clear();
        //arr=null;
    }
}

后来发现,程序运行结束以后总有256个Integer对象不能回收,百思不得其解。后来反编译了代码,看到实际上是编译器自动完成了将基本类型数据变成包装类对象的操作。下面是反编译的结果,注意红色的部分是编译器做的工作。

package my;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;

public class Test
{
  public static void main(String[] args)
    throws IOException
  {
    char ch = ' ';
    while (ch != 'n')
      ch = (char)System.in.read();
    for (int i = 0; i < 1000; ++i)
      test();
    ch = ' ';
    while (ch != 'n')
      ch = (char)System.in.read();
  }

  public static void test()
  {
    ArrayList arr = new ArrayList();
    for (int i = 0; i < 10000; ++i)
      arr.add(Integer.valueOf((int)(Math.random() * 100.0D)));
  }
}

而这个valueOf()方法的源代码如下:

/**
     * Returns a <tt>Integer</tt> instance representing the specified
     * <tt>int</tt> value.
     * If a new <tt>Integer</tt> instance is not required, this method
     * should generally be used in preference to the constructor
     * {@link #Integer(int)}, as this method is likely to yield
     * significantly better space and time performance by caching
     * frequently requested values.
     *
     * @param  i an <code>int</code> value.
     * @return a <tt>Integer</tt> instance representing <tt>i</tt>.
     * @since  1.5
     */
    public static Integer valueOf(int i) {
    final int offset = 128;
    if (i >= -128 && i <= 127) { // must cache
        return IntegerCache.cache[i + offset];
    }
        return new Integer(i);
    }

IntegerCache是Integer类的内部类

private static class IntegerCache {
    private IntegerCache(){}

    static final Integer cache[] = new Integer[-(-128) + 127 + 1];

    static {
        for(int i = 0; i < cache.length; i++)
        cache[i] = new Integer(i - 128);
    }
    }

当要包装的数值在-128-+127之间时,就会产生256个Integer对象,并返回其中的一个。如果在此范围之外,则直接返回一个Integer对象。这样就不难理解为什么最后有256个不能回收的Integer对象了。

带来的问题:

下面的三个程序输出各是什么?

public class AutoBoxDemo {
    public static void main(String[] args) {
        Integer i1 = 100;
        Integer i2 = 100;
        if (i1 == i2)
            System.out.println("i1 == i2");
        else
            System.out.println("i1 != i2");
    }
}

答案:i1==i2  (数值在-128到127之间,自动装箱返回的是IntegerCache中的引用,因此是同一个对象)

public class AutoBoxDemo {
    public static void main(String[] args) {
        Integer i1 = 200;
        Integer i2 = 200;
        if (i1 == i2)
            System.out.println("i1 == i2");
        else
            System.out.println("i1 != i2");
    }
}

答案:i1!=i2 (数值超出-128到127这个范围,直接new一个对象返回,数值相等,但是对象不是同一个)

public class AutoBoxDemo {
    public static void main(String[] args) {
        Integer i1 = 200;
        Integer i2 = 200;
        if (i1.equals(i2))
            System.out.println("i1 == i2");
        else
            System.out.println("i1 != i2");
    }
}

答案:i1==i2 (数值超出-128到127这个范围,直接new一个对象返回,数值相等,用equals比较当然是相等的)

再次提醒:对象的相等性比较应该用equals,==进行的是同一性比较。