﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-微软亚洲工程院-随笔分类-.NET</title><link>http://www.cppblog.com/littlesupersun/category/5057.html</link><description>Microsoft ATC--software design engineer</description><language>zh-cn</language><lastBuildDate>Wed, 21 May 2008 07:41:10 GMT</lastBuildDate><pubDate>Wed, 21 May 2008 07:41:10 GMT</pubDate><ttl>60</ttl><item><title>一道经常被问到的题（css,div中的绝对定位和相对定位）</title><link>http://www.cppblog.com/littlesupersun/archive/2007/09/04/31558.html</link><dc:creator>香心晓筑</dc:creator><author>香心晓筑</author><pubDate>Tue, 04 Sep 2007 09:40:00 GMT</pubDate><guid>http://www.cppblog.com/littlesupersun/archive/2007/09/04/31558.html</guid><wfw:comment>http://www.cppblog.com/littlesupersun/comments/31558.html</wfw:comment><comments>http://www.cppblog.com/littlesupersun/archive/2007/09/04/31558.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/littlesupersun/comments/commentRss/31558.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/littlesupersun/services/trackbacks/31558.html</trackback:ping><description><![CDATA[层的随意定位的特性给<a href="http://www.jjzx.cn/tag-22-1.html"><u><font color=#0000ff>网页</font></u></a><a href="http://www.jjzx.cn/tag-27-1.html"><u><font color=#0000ff>设计</font></u></a>者带来的很大的方便，但同时也带来了一定的麻烦。为什么这样说呢？
<p>　　大家都知道，为了让网页能够自动地适应<a href="http://www.jjzx.cn/tag-59-1.html"><u><font color=#0000ff>用户</font></u></a>设置的分辨率，在<a href="http://www.jjzx.cn/leibie-5-1.html"><u><font color=#0000ff>网页制作</font></u></a>过程中人们采用了百分比的设置方式，从而页面的所有元素从新排版，保证原来的格式。但如果你在页面上使用了层，你会发现当浏览器大小改变时，层的位置却没有改变，结果它和其他的元素之间的配合出现了错位现象，页面变得杂乱无章了。而我们是不能够强制用户使用特定的分辨率的，那么就只有想办法让层的位置也能够象表格一样根据浏览器大小的改变而重新定位，这就需要合理地使用相对定位和绝对定位了。</p>
<p>　　<strong>绝对定位（position:absolute）：</strong>即层默认的定位方式，绝对于浏览器左上角的边缘开始计算定位数值。</p>
<p>　　<strong>相对定位（position:relative）：</strong>层的位置相对于某个元素设置，该元素位置改变，则层的位置相应改变。</p>
<p>　　对比两种定位方式，不难发现，使用相对定位的层才是真正实现设计者思想的方式，从而完全掌握层的排版。 </p>
<p>　　那么，绝对定位有没有用呢？当然有用了，当你的网页全部使用层来排版，而且页面是使用默认的居左放置的，那么使用默认的绝对定位方式可以方便的排版，提高设计的工作<a href="http://www.jjzx.cn/tag-35-1.html"><u><font color=#0000ff>效率</font></u></a>。</p>
<p>　　在Dreamweaver中，插入的层虽然都是使用的绝对（absolute）定位方式，但是插入的方式不同，带来的效果是不同的。前面我们已经知道，使用菜单插入的层是没有定位的坐标的，只有当你使用鼠标拖动该层改变其位置后，才会写入坐标值。而拖拉出来的层的初始位置坐标就是鼠标开始动作时的坐标。</p>
<p>　　请明确一个概念：由Dreanweaver赋予坐标值的层是绝对于浏览器边缘定位的层。不带坐标值的层则是相对于某元素定位的层！</p>
<p>　　所以，最简单的设置相对定位层的的方式就是：选定插入层的位置（例如某个单元格或者页面中某处）将光标停留在该位置，然后选择Insert--&gt;Layer，即可在该位置创建一个固定大小的层，这个层就是相对于该位置定位的了。需要注意，采用这种方式创建的层，你只可以使用鼠标调整它的大小，绝对不可以移动它的位置！也就是说，在属性面板上，层的位置栏中（Left Top）绝对不可以有数值。</p>
<p>　　很多情况下，插入的层的位置并不一定准确，特别是Dreamweaver并非真正的所见即所得的<a href="http://www.jjzx.cn/tag-40-1.html"><u><font color=#0000ff>软件</font></u></a>，网页的排版只有到浏览器中显示才可以真正看到排版的表现，所以上面所说的方法就显的过于简单而容易出问题了。这个时候，你需要给层一个定位的参照物，让它真正地做到相对的定位。</p>
<p>　　简单的参照物可以是一个父层，即先插入一个相对定位的空白的层，在此层中插入你真正需要的层，而这个层是可以随意拖拉改变位置的。但这样毕竟在网页中多插入了一个空白的层，我想它一定不是专业的网页设计师所希望的。下面我们介绍使用CSS来实现真正的相对定位的层。</p>
<p>　　我们需要先设置一个<a href="http://www.jjzx.cn/tag-174-1.html"><u><font color=#0000ff>CSS </font></u></a>Class，来定义定位的方式为相对：</p>
<p>　　.ceng { position: relative; }</p>
<p>　　然后，赋予你所需要的参照物（可以是<a href="http://www.jjzx.cn/tag-156-1.html"><u><font color=#0000ff> table</font></u></a>,tr,td... ）一个<a href="http://www.jjzx.cn/tag-161-1.html"><u><font color=#0000ff> Css</font></u></a>属性为这个类。这样浏览器就会以它的左上角为原点，建立新的坐标系。再在这个参照物的下级插入层，则层绝对于该参照物定位，如果你需要改变层的位置，你可以直接在层的属性面板上输入Left Top的数值（不可以使用鼠标拖拉），切记此数值的坐标原点是你所指定的参照物，而不是浏览器的边缘（在Dreamweaver中编辑时，该层看起来象是绝对于页面边缘定位的，但在浏览器中，它是绝对于你所指定的参照物的）。</p>
<p>　　很多朋友使用层是为了等到动态的效果，例如使用时间线让某个物体运动起来，增加网页的动感，那么相对定位后的层还可以运动吗？回答当然是肯定的。由于定义<a href="http://www.jjzx.cn/tag-38-1.html"><u><font color=#0000ff>对象</font></u></a>的两个位置需要拖动该对象改变位置，所以使用简单的层定位的方法是不行的，但如果你使用CSS来设置相对定位的效果的话，那么就完全可以实现了。只是需要注意，定义运动的初始位置和结束位置时，你仍然不可以使用鼠标拖拉，而只能自行输入Left和Top的数值。</p>
<p>　　本来层的使用并不是很复杂的，但我却把它单独作为一个章节，原因就是层的定位有一定难度，希望朋友们看过以上的介绍后，在Dreamweaver中多实验几次，否则还是容易出现问题的。</p>
<p>　　OK！关于层的使用就说这么多。</p>
<img src ="http://www.cppblog.com/littlesupersun/aggbug/31558.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/littlesupersun/" target="_blank">香心晓筑</a> 2007-09-04 17:40 <a href="http://www.cppblog.com/littlesupersun/archive/2007/09/04/31558.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Ajax简介</title><link>http://www.cppblog.com/littlesupersun/archive/2007/08/31/31302.html</link><dc:creator>香心晓筑</dc:creator><author>香心晓筑</author><pubDate>Fri, 31 Aug 2007 06:17:00 GMT</pubDate><guid>http://www.cppblog.com/littlesupersun/archive/2007/08/31/31302.html</guid><wfw:comment>http://www.cppblog.com/littlesupersun/comments/31302.html</wfw:comment><comments>http://www.cppblog.com/littlesupersun/archive/2007/08/31/31302.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.cppblog.com/littlesupersun/comments/commentRss/31302.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/littlesupersun/services/trackbacks/31302.html</trackback:ping><description><![CDATA[<p>　　作为J2EE开发人员，我们似乎经常关注&#8220;后端机制（backend mechanics）&#8221;。我们通常会忘记，J2EE的主要成功之处在Web应用程序方面；许多原因使得人们喜欢利用Web开发应用程序，但主要还是因为其易于部署的特点允许站点以尽可能低的成本拥有上百万的用户。遗憾的是，在过去几年中，我们在后端投入了太多的时间，而在使我们的Web用户界面对用户自然和响应灵敏方面却投入不足。</p>
<p>　　本文介绍一种方法，Ajax，使用它可以构建更为动态和响应更灵敏的Web应用程序。该方法的关键在于对浏览器端的JavaScript、 DHTML和与服务器异步通信的组合。本文也演示了启用这种方法是多么简单：利用一个Ajax框架（指DWR）构造一个应用程序，它直接从浏览器与后端服务进行通信。如果使用得当，这种强大的力量可以使应用程序更加自然和响应灵敏，从而提升用户的浏览体验。</p>
<p>　　该应用程序中所使用的示例代码已打包为单独的WAR文件，可供下载。</p>
<p><strong>简介</strong></p>
<p>　　术语Ajax用来描述一组技术，它使浏览器可以为用户提供更为自然的浏览体验。在Ajax之前，Web站点强制用户进入提交/等待/重新显示范例，用户的动作总是与服务器的&#8220;思考时间&#8221;同步。Ajax提供与服务器异步通信的能力，从而使用户从请求/响应的循环中解脱出来。借助于Ajax，可以在用户单击按钮时，使用JavaScript和DHTML立即更新UI，并向服务器发出异步请求，以执行更新或查询数据库。当请求返回时，就可以使用 JavaScript和CSS来相应地更新UI，而不是刷新整个页面。最重要的是，用户甚至不知道浏览器正在与服务器通信：Web站点看起来是即时响应的。</p>
<p>　　虽然Ajax所需的基础架构已经出现了一段时间，但直到最近异步请求的真正威力才得到利用。能够拥有一个响应极其灵敏的Web站点确实激动人心，因为它最终允许开发人员和设计人员使用标准的HTML/CSS/JavaScript堆栈创建&#8220;桌面风格的（desktop-like）&#8221;可用性。</p>
<p>　　通常，在J2EE中，开发人员过于关注服务和持久性层的开发，以至于用户界面的可用性已经落后。在一个典型的J2EE开发周期中，常常会听到这样的话，&#8220;我们没有可投入UI的时间&#8221;或&#8220;不能用HTML实现&#8221;。但是，以下Web站点证明，这些理由再也站不住脚了：</p>
<ul>
    <li><a href="http://backpackit.com/" target=_blank>BackPack</a>
    <li><a href="http://www.google.com/webhp?complete=1&amp;hl=en" target=_blank>Google Suggest</a>
    <li><a href="http://maps.google.com/" target=_blank>Google Maps</a>
    <li><a href="http://www.palmsphere.com/" target=_blank>PalmSphere</a> </li>
</ul>
<p>　　所有这些Web站点都告诉我们，Web应用程序不必完全依赖于从服务器重新载入页面来向用户呈现更改。一切似乎就在瞬间发生。简而言之，在涉及到用户界面的响应灵敏度时，基准设得更高了。</p>
<p><strong>定义Ajax</strong></p>
<p>　　Adaptive Path公司的Jesse James Garrett这样<a href="http://www.adaptivepath.com/publications/essays/archives/000385.php" target=_blank>定义Ajax</a>：</p>
<p>　　Ajax不是一种技术。实际上，它由几种蓬勃发展的技术以新的强大方式组合而成。Ajax包含：</p>
<ul>
    <li>基于<a href="http://www.w3.org/TR/xhtml1/" target=_blank>XHTML</a>和<a href="http://www.w3.org/Style/CSS/" target=_blank>CSS</a>标准的表示；
    <li>使用<a href="http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/introduction.html" target=_blank>Document Object Model</a>进行动态显示和交互；
    <li>使用XMLHttpRequest与服务器进行异步通信；
    <li>使用JavaScript绑定一切。 </li>
</ul>
<p>　　这非常好，但为什么要以Ajax命名呢？其实术语Ajax是由Jesse James Garrett创造的，他说它是&#8220;Asynchronous JavaScript + XML的简写&#8221;。</p>
<p><strong>Ajax的工作原理</strong></p>
<p>　　Ajax的核心是JavaScript对象XmlHttpRequest。该对象在Internet Explorer 5中首次引入，它是一种支持异步请求的技术。简而言之，XmlHttpRequest使您可以使用JavaScript向服务器提出请求并处理响应，而不阻塞用户。</p>
<p>　　在创建Web站点时，在客户端执行屏幕更新为用户提供了很大的灵活性。下面是使用Ajax可以完成的功能：</p>
<ul>
    <li>动态更新购物车的物品总数，无需用户单击Update并等待服务器重新发送整个页面。
    <li>提升站点的性能，这是通过减少从服务器下载的数据量而实现的。例如，在Amazon的购物车页面，当更新篮子中的一项物品的数量时，会重新载入整个页面，这必须下载 32K的数据。如果使用Ajax计算新的总量，服务器只会返回新的总量值，因此所需的带宽仅为原来的百分之一。
    <li>消除了每次用户输入时的页面刷新。例如，在Ajax中，如果用户在分页列表上单击Next，则服务器数据只刷新列表而不是整个页面。
    <li>直接编辑表格数据，而不是要求用户导航到新的页面来编辑数据。对于Ajax，当用户单击Edit时，可以将静态表格刷新为内容可编辑的表格。用户单击Done之后，就可以发出一个Ajax请求来更新服务器，并刷新表格，使其包含静态、只读的数据。 </li>
</ul>
<p>　　一切皆有可能！但愿它能够激发您开始开发自己的基于Ajax的站点。然而，在开始之前，让我们介绍一个现有的Web站点，它遵循传统的提交/等待/重新显示的范例，我们还将讨论Ajax如何提升用户体验。</p>
<p><strong>Ajax可用于那些场景？——一个例子：MSN Money页面</strong></p>
<p>　　前几天，在浏览MSN Money页面的时候，有一篇<a href="http://moneycentral.msn.com/content/Investing/Realestate/P63633.asp" target=_blank>关于房地产投资的文章</a>引起了我的好奇心。我决定使用站点的&#8220;Rate this article&#8221;（评价本文）功能，鼓励其他的用户花一点时间来阅读这篇文章。在我单击vote按钮并等待了一会儿之后，整个页面被刷新，在原来投票问题所在的地方出现了一个漂亮的感谢画面。</p>
<p><img height=63 src="file:///D:/java技术文档/2005110103_files/0511010101.jpg" width=303> </p>
<p>　　而Ajax能够使用户的体验更加愉快，它可以提供响应更加灵敏的UI，并消除页面刷新所带来的闪烁。目前，由于要刷新整个页面，需要传送大量的数据，因为必须重新发送整个页面。如果使用Ajax，服务器可以返回一个包含了感谢信息的500字节的消息，而不是发送26,813字节的消息来刷新整个页面。即使使用的是高速Internet，传送26K和1/2K的差别也非常大。同样重要的是，只需要刷新与投票相关的一小节，而不是刷新整个屏幕。</p>
<p>　　让我们利用Ajax实现自己的基本投票系统。</p>
<p><strong>原始的Ajax：直接使用XmlHttpRequest</strong></p>
<p>　　如上所述，Ajax的核心是JavaScript对象XmlHttpRequest。下面的示例文章评价系统将带您熟悉Ajax的底层基本知识：<a href="http://tearesolutions.com/ajax-demo/raw-ajax.html" target=_blank>http://tearesolutions.com/ajax-demo/raw-ajax.html</a>。注：如果您已经在本地WebLogic容器中安装了<a href="http://dev2dev.bea.com/2005/08/ajax-demo.war">ajax-demo.war</a>，可以导航到<a href="http://localhost:7001/ajax-demo/raw-ajax.html" target=_blank>http://localhost:7001/ajax-demo/raw-ajax.html</a>，</p>
<p>　　浏览应用程序，参与投票，并亲眼看它如何运转。熟悉了该应用程序之后，继续阅读，进一步了解其工作原理细节。</p>
　　首先，您拥有一些简单的定位点标记，它连接到一个JavaScriptcastVote(rank)函数。
<pre class=code>function castVote(rank) {
var url = "/ajax-demo/static-article-ranking.html";
var callback = processAjaxResponse;
executeXhr(callback, url);
}
</pre>
<p>　　该函数为您想要与之通信的服务器资源创建一个URL并调用内部函数executeXhr，提供一个回调JavaScript函数，一旦服务器响应可用，该函数就被执行。由于我希望它运行在一个简单的Apache环境中，&#8220;cast vote URL&#8221;只是一个简单的HTML页面。在实际情况中，被调用的URL将记录票数并动态地呈现包含投票总数的响应。</p>
　　下一步是发出一个XmlHttpRequest请求：
<pre class=code>function executeXhr(callback, url) {
// branch for native XMLHttpRequest object
if (window.XMLHttpRequest) {
req = new XMLHttpRequest();
req.onreadystatechange = callback;
req.open("GET", url, true);
req.send(null);
} // branch for IE/Windows ActiveX version
else if (window.ActiveXObject) {
req = new ActiveXObject("Microsoft.XMLHTTP");
if (req) {
req.onreadystatechange = callback;
req.open("GET", url, true);
req.send();
}
}
}
</pre>
<p>　　如您所见，执行一个XmlHttpRequest并不简单，但非常直观。和平常一样，在JavaScript领域，大部分的工作量都花在确保浏览器兼容方面。在这种情况下，首先要确定XmlHttpRequest是否可用。如果不能用，很可能要使用Internet Explorer，这样就要使用所提供的ActiveX实现。</p>
<p>executeXhr()方法中最关键的部分是这两行： </p>
<pre class=code>req.onreadystatechange = callback;
req.open("GET", url, true);
</pre>
<p>　　第一行定义了JavaScript回调函数，您希望一旦响应就绪它就自动执行，而req.open()方法中所指定的&#8220;true&#8221;标志说明您想要异步执行该请求。</p>
　　一旦服务器处理完XmlHttpRequest并返回给浏览器，使用req.onreadystatechange指派所设置的回调方法将被自动调用。
<pre class=code>function processAjaxResponse() {
// only if req shows "loaded"
if (req.readyState == 4) {
// only if "OK"
if (req.status == 200) {
$('votes').innerHTML = req.responseText;
} else {
alert("There was a problem retrieving the XML data:\n" +
req.statusText);
}
}
}
</pre>
<p>　　该代码相当简洁，并且使用了几个幻数，这使得难以一下子看出发生了什么。为了弄清楚这一点，下面的表格（引用自<a href="http://developer.apple.com/internet/webcontent/xmlhttpreq.html" target=_blank>http://developer.apple.com/internet/webcontent/xmlhttpreq.html</a>）列举了常用的XmlHttpRequest对象属性。</p>
<table cellSpacing=1 cellPadding=0 width="80%" bgColor=#cccccc border=0>
    <tbody>
        <tr bgColor=#ffffff>
            <td height=22>
            <p><strong>属性</strong></p>
            </td>
            <td>
            <p><strong>描述</strong></p>
            </td>
        </tr>
        <tr bgColor=#ffffff>
            <td vAlign=top height=22>
            <p>onreadystatechange</p>
            </td>
            <td vAlign=top>
            <p>每次状态改变所触发事件的事件处理程序</p>
            </td>
        </tr>
        <tr bgColor=#ffffff>
            <td vAlign=top height=22>
            <p>readyState</p>
            </td>
            <td vAlign=top>
            <p>对象状态值： </p>
            <ul>
                <li>0 = 未初始化（uninitialized）
                <li>1 = 正在加载（loading）
                <li>2 = 加载完毕（loaded）
                <li>3 = 交互（interactive）
                <li>4 = 完成（complete） </li>
            </ul>
            </td>
        </tr>
        <tr bgColor=#ffffff>
            <td vAlign=top height=22>
            <p>responseText</p>
            </td>
            <td vAlign=top>
            <p>从服务器进程返回的数据的字符串形式</p>
            </td>
        </tr>
        <tr bgColor=#ffffff>
            <td vAlign=top height=22>
            <p>responseXML</p>
            </td>
            <td vAlign=top>
            <p>从服务器进程返回的DOM兼容的文档数据对象</p>
            </td>
        </tr>
        <tr bgColor=#ffffff>
            <td vAlign=top height=22>
            <p>status</p>
            </td>
            <td vAlign=top>
            <p>从服务器返回的数字代码，比如404（未找到）或200（就绪）</p>
            </td>
        </tr>
        <tr bgColor=#ffffff>
            <td vAlign=top height=22>
            <p>statusText</p>
            </td>
            <td vAlign=top>
            <p>伴随状态码的字符串信息</p>
            </td>
        </tr>
    </tbody>
</table>
<p>　　现在processVoteResponse()函数开始显示出其意义了。它首先检查XmlHttpRequest的整体状态以保证它已经完成（readyStatus == 4），然后根据服务器的设定询问请求状态。如果一切正常（status == 200）,就使用innerHTML属性重写DOM的&#8220;votes&#8221;节点的内容。</p>
<p>　　既然您亲眼看到了XmlHttpRequest对象是如何工作的，就让我们利用一个旨在简化JavaScript与Java应用程序之间的异步通信的框架来对具体的细节进行抽象。</p>
<p><strong>Ajax: DWR方式</strong></p>
<p>　　按照与文章评价系统相同的流程，我们将使用Direct Web Remoting（DWR）框架实现同样的功能。</p>
<p>　　假定文章和投票结果存储在一个数据库中，使用某种对象/关系映射技术来完成抽取工作。为了部署起来尽可能地简单，我们不会使用数据库进行持久性存储。此外，为使应用程序尽可能通用，也不使用Web框架。相反，应用程序将从一个静态HTML文件开始，可以认为它由服务器动态地呈现。除了这些简化措施，应用程序还应该使用Spring Framework关联一切，以便轻松看出如何在一个&#8220;真实的&#8221;应用程序中使用DWR。</p>
<p>　　现在应该下载示例应用程序并熟悉它。该应用程序被压缩为标准的WAR文件，因此您可以把它放置到任何一个Web容器中——无需进行配置。部署完毕之后，就可以导航到<a href="http://localhost:7001/ajax-demo/dwr-ajax.html" target=_blank>http://localhost:7001/ajax_demo/dwr-ajax.html</a>来运行程序。</p>
<p>　　可以查看<a href="http://dev2dev.bea.com/2005/08/source.html" target=_blank>HTML 源代码</a>，了解它如何工作。给人印象最深的是，代码如此简单——所有与服务器的交互都隐藏在JavaScript对象ajaxSampleSvc的后面。更加令人惊讶的是，ajaxSampleSvc服务不是由手工编写而是完全自动生成的！让我们继续，看看这是如何做到的。</p>
<p><strong>引入DWR</strong></p>
<p>　　如同在&#8220;原始的Ajax&#8221;一节所演示的那样，直接使用XmlHttpRequest创建异步请求非常麻烦。不仅JavaScript代码冗长，而且必须考虑服务器端为定位Ajax请求到适当的服务所需做的工作，并将结果封送到浏览器。</p>
<p>　　设计DWR的目的是要处理将Web页面安装到后端服务上所需的所有信息管道。它是一个Java框架，可以很轻松地将它插入到Web应用程序中，以便JavaScript代码可以调用服务器上的服务。它甚至直接与Spring Framework集成，从而允许用户直接向Web客户机公开bean。</p>
<p>　　DWR真正的巧妙之处是，在用户配置了要向客户机公开的服务之后，它使用反射来生成JavaScript对象，以便Web页面能够使用这些对象来访问该服务。然后Web页面只需接合到生成的JavaScript对象，就像它们是直接使用服务一样；DWR无缝地处理所有有关Ajax和请求定位的琐碎细节。</p>
<p>　　让我们仔细分析一下示例代码，弄清它是如何工作的。</p>
<p><strong>应用程序细节：DWR分析</strong></p>
<p>　　关于应用程序，首先要注意的是，它是一个标准的Java应用程序，使用分层架构（Layered Architecture）设计模式。使用DWR通过JavaScript公开一些服务并不影响您的设计。 </p>
<p><img height=344 src="file:///D:/java技术文档/2005110103_files/0511010102.jpg" width=209> </p>
<p>　　下面是一个简单的Java服务，我们将使用DWR框架直接将其向JavaScript代码公开：</p>
<pre class=code>package com.tearesolutions.service;
public interface AjaxSampleSvc {
Article castVote(int rank);
}
</pre>
<p>　　这是一个被简化到几乎不可能的程度的例子，其中只有一篇文章可以投票。该服务由Spring管理，它使用的bean名是ajaxSampleSvc，它的持久性需求则依赖于ArticleDao。详情请参见applicationContext.xml。</p>
<p>　　为了把该服务公开为JavaScript对象，需要配置DWR，添加dwr.xml文件到WEB-INF目录下： </p>
<pre class=code>&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;!DOCTYPE dwr PUBLIC
"-//GetAhead Limited//DTD Direct Web Remoting 0.4//EN"
"http://www.getahead.ltd.uk/dwr/dwr.dtd"&gt;
&lt;dwr&gt;
&lt;allow&gt;
&lt;create creator="spring" javascript="ajaxSampleSvc"&gt;
&lt;param name="beanName" value="ajaxSampleSvc" /&gt;
&lt;/create&gt;
&lt;convert converter="bean" match="com.tearesolutions.model.Article"/&gt;
&lt;exclude method="toString"/&gt;
&lt;exclude method="setArticleDao"/&gt;
&lt;/allow&gt;
&lt;/dwr&gt;
</pre>
<p>　　dwr.xml文件告诉DWR哪些服务是要直接向JavaScript代码公开的。注意，已经要求公开Spring bean ajaxSampleSvc。DWR将自动找到由应用程序设置的SpringApplicationContext。为此，必须使用标准的servlet 过滤器ContextLoaderListener来初始化Spring ApplicationContext。</p>
　　DWR被设置为一个servlet，所以把它的定义添加到web.xml：
<pre class=code>&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD
Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd"&gt;
&lt;web-app&gt;
&lt;display-name&gt;Ajax Examples&lt;/display-name&gt;
&lt;listener&gt;
&lt;listener-class&gt;
org.springframework.web.context.ContextLoaderListener
&lt;/listener-class&gt;
&lt;/listener&gt;
&lt;servlet&gt;
&lt;servlet-name&gt;ajax_sample&lt;/servlet-name&gt;
&lt;servlet-class&gt;com.tearesolutions.web.AjaxSampleServlet&lt;/servlet-class&gt;
&lt;load-on-startup&gt;1&lt;/load-on-startup&gt;
&lt;/servlet&gt;
&lt;servlet&gt;
&lt;servlet-name&gt;dwr-invoker&lt;/servlet-name&gt;
&lt;display-name&gt;DWR Servlet&lt;/display-name&gt;
&lt;description&gt;Direct Web Remoter Servlet&lt;/description&gt;
&lt;servlet-class&gt;uk.ltd.getahead.dwr.DWRServlet&lt;/servlet-class&gt;
&lt;init-param&gt;
&lt;param-name&gt;debug&lt;/param-name&gt;
&lt;param-value&gt;true&lt;/param-value&gt;
&lt;/init-param&gt;
&lt;/servlet&gt;
&lt;servlet-mapping&gt;
&lt;servlet-name&gt;ajax_sample&lt;/servlet-name&gt;
&lt;url-pattern&gt;/ajax_sample&lt;/url-pattern&gt;
&lt;/servlet-mapping&gt;
&lt;servlet-mapping&gt;
&lt;servlet-name&gt;dwr-invoker&lt;/servlet-name&gt;
&lt;url-pattern&gt;/dwr/*&lt;/url-pattern&gt;
&lt;/servlet-mapping&gt;
&lt;/web-app&gt;
</pre>
<p>　　做完这些之后，可以加载<a href="http://localhost:7001/ajax-demo/dwr" target=_blank>http://localhost:7001/ajax-demo/dwr</a>，看看哪些服务可用。结果如下：</p>
<p><img height=102 src="file:///D:/java技术文档/2005110103_files/0511010103.jpg" width=305></p>
<p>图3. 可用的服务</p>
　　单击ajaxSampleSvc链接，查看有关如何在HTML页面内直接使用服务的示例实现。其中包含的两个JavaScript文件完成了大部分的功能：
<pre class=code>&lt;script type='text/javascript'
src='/ajax-demo/dwr/interface/ajaxSampleSvc.js'&gt;&lt;/script&gt;
&lt;script type='text/javascript'
src='/ajax-demo/dwr/engine.js'&gt;&lt;/script&gt;
</pre>
<p>ajaxSampleSvc.js是动态生成的：</p>
<pre class=code>function ajaxSampleSvc() { }
ajaxSampleSvc.castVote = function(callback, p0)
{
DWREngine._execute(callback, '/ajax-demo/dwr',
'ajaxSampleSvc', 'castVote', p0);
}
</pre>
<p>　　现在可以使用JavaScript对象ajaxSampleSvc替换所有的XmlHttpRequest代码，从而重构raw-ajax.html文件。可以在dwr-ajax.html文件中看到改动的结果；下面是新的JavaScript函数：</p>
<pre class=code>function castVote(rank) {
ajaxSampleSvc.castVote(processResponse, rank);
}
function processResponse(data) {
var voteText = "
<p><strong>Thanks for Voting!</strong></p>
"
+ "
<p>Current ranking: " + data.voteAverage
+ " out of 5</p>
"
+ "
<p>Number of votes placed: "
+ data.numberOfVotes + "</p>
";
$('votes').innerHTML = voteText;
}
</pre>
<p>　　惊人地简单，不是吗？由ajaxSampleSvc对象返回的Article域对象序列化为一个JavaScript对象，允许在它上面调用诸如numberOfVotes()和voteAverage()之类的方法。在动态生成并插入到DIV元素&#8220;votes&#8221;中的HTML代码内使用这些数据。</p>
<p><strong>下一步工作</strong></p>
<p>　　　在后续文章中，我将继续有关Ajax的话题，涉及下面这些方面：</p>
<ul>
    <li>Ajax最佳实践 </li>
</ul>
<p>　　像许多技术一样，Ajax是一把双刃剑。对于一些用例，其应用程序其实没有必要使用Ajax，使用了反而有损可用性。我将介绍一些不适合使用的模式，突出说明Ajax的一些消极方面，并展示一些有助于缓和这些消极方面的机制。例如，对<a href="http://www.netflix.com/BrowseSelection">Netflix电影浏览器</a>来说，Ajax是合适的解决方案吗？或者，如何提示用户确实出了一些问题，而再次单击按钮也无济于事？</p>
<ul>
    <li>管理跨请求的状态 </li>
</ul>
<p>　　在使用Ajax时，最初的文档DOM会发生一些变化，并且有大量的页面状态信息存储在客户端变量中。当用户跟踪一个链接到应用程序中的另一个页面时，状态就丢失了。当用户按照惯例单击Back按钮时，呈现给他们的是缓存中的初始页面。这会使用户感到非常迷惑！</p>
<ul>
    <li>调试技巧 </li>
</ul>
<p>　　使用JavaScript在客户端执行更多的工作时，如果事情不按预期方式进行，就需要一些调试工具来帮助弄清出现了什么问题。</p>
<p><strong>结束语</strong></p>
<p>　　本文介绍了Ajax方法，并展示了如何使用它来创建一个动态且响应灵敏的Web应用程序。通过使用DWR框架，可以轻松地把Ajax融合到站点中，而无需担心所有必须执行的实际管道工作。</p>
<p>　　特别感谢Getahead IT咨询公司的Joe Walker和他的团队开发出DWR这样神奇的工具。感谢你们与世界共享它！</p>
<img src ="http://www.cppblog.com/littlesupersun/aggbug/31302.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/littlesupersun/" target="_blank">香心晓筑</a> 2007-08-31 14:17 <a href="http://www.cppblog.com/littlesupersun/archive/2007/08/31/31302.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C#和JAVA事件处理的异同</title><link>http://www.cppblog.com/littlesupersun/archive/2007/08/31/31299.html</link><dc:creator>香心晓筑</dc:creator><author>香心晓筑</author><pubDate>Fri, 31 Aug 2007 06:12:00 GMT</pubDate><guid>http://www.cppblog.com/littlesupersun/archive/2007/08/31/31299.html</guid><wfw:comment>http://www.cppblog.com/littlesupersun/comments/31299.html</wfw:comment><comments>http://www.cppblog.com/littlesupersun/archive/2007/08/31/31299.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/littlesupersun/comments/commentRss/31299.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/littlesupersun/services/trackbacks/31299.html</trackback:ping><description><![CDATA[<p>Java与C#的事件处理都是实现了事件源-事件响应者机制，但又不完全相同。Java实现的是一种事件源与事件响应者两级实体对象方式，这里的事件响应者也是事件监听者，而C#实现的是一种事件源-代理-事件响应者三级实体对象方式。下面就这两种方式来具体说明。</p>
<p>　　Java事件处理</p>
<p>　　从概念上讲，事件是一种在"源对象"和"监听者对象"之间，某种状态发生变化的传递机制。事件有许多不同的用途，例如在Windows系统中常要处理的鼠标事件、窗口边界改变事件、键盘事件等。在Java中则是定义了一个普通的、可扩充的事件机制，这种机制能够：</p>
<p>　　对事件类型和传递的模型的定义和扩充提供一个公共框架，并适合于广泛的应用。</p>
<p>　　　与Java语言和环境有较高的集成度。</p>
<p>　　　事件能被描述环境捕获和触发。</p>
<p>　　　能使其它构造工具采取某种技术在设计时直接控制事件，以及事件源和事件监听者之间的联系。</p>
<p>　　　事件机制本身不依赖于复杂的开发工具。</p>
<p>　　事件从事件源到监听者的传递是通过对目标监听者对象的Java方法调用进行的。对每个明确的事件的发生，都相应地定义一个明确的Java方法。这些方法都集中定义在事件监听者（EventListener）接口中，这个接口要继承 java.util.EventListener。实现了事件监听者接口中一些或全部方法的类就是事件监听者。伴随着事件的发生，相应的状态通常都封装在事件状态对象中，该对象必须继承自java.util.EventObject。事件状态对象作为单参传递给应响应该事件的监听者方法中。发出某种特定事件的事件源的标识是：遵从规定的设计格式为事件监听者定义注册方法，并接受对指定事件监听者接口实例的引用。有时，事件监听者不能直接实现事件监听者接口，或者还有其它的额外动作时，就要在一个源与其它一个或多个监听者之间插入一个事件适配器类的实例，来建立它们之间的联系。</p>
<p>　　事件状态对象（Event State Object）<br>　<br>　　与事件发生有关的状态信息一般都封装在一个事件状态对象中，这种对象是java。util。EventObject的子类。按设计习惯，这种事件状态对象类的名应以Event结尾。例如：</p>
<p>public class MouseMovedExampleEvent extends java。util。EventObject<br>{ protected int x， y；<br>/*　创建一个鼠标移动事件MouseMovedExampleEvent */<br>　MouseMovedExampleEvent(java.awt.Component source， Point location) {<br>super(source);<br>x = location.x;<br>y = location.y;<br>}<br>/* 获取鼠标位置*/<br>public Point getLocation() {<br>return new Point(x, y);<br>}}</p>
<p>事件监听者接口（EventListener Interface）与事件监听者</p>
<p>　　由于Java事件模型是基于方法调用，因而需要一个定义并组织事件操纵方法的方式。事件操纵方法都被定义在继承了java。util。 EventListener类的EventListener接口中，按规定，EventListener接口的命名要以Listener结尾。任何一个类如果想操纵在EventListener接口中定义的方法都必须以实现这个接口方式进行。这个类也就是事件监听者。例如：</p>
<p>/*先定义了一个鼠标移动事件对象*/<br>　　public class MouseMovedExampleEvent extends java。util。EventObject {<br>　　 // 在此类中包含了与鼠标移动事件有关的状态信息<br>　　　　 ...<br>　　}<br>　　/*定义了鼠标移动事件的监听者接口*/<br>　　interface MouseMovedExampleListener extends java。util。EventListener {<br>/*在这个接口中定义了鼠标移动事件监听者所应支持的方法*/<br>void mouseMoved(MouseMovedExampleEvent mme);<br>}</p>
<p>　　在接口中只定义方法名，方法的参数和返回值类型。如：上面接口中的mouseMoved方法的具体实现是在下面的ArbitraryObject类中定义的。</p>
<p>class ArbitraryObject implements MouseMovedExampleListener {<br>　　　public void mouseMoved(MouseMovedExampleEvent mme)<br>　 { ... }<br>｝</p>
<p>　　ArbitraryObject就是MouseMovedExampleEvent事件的监听者。</p>
<p>　　事件监听者的注册与注销</p>
<p>　　为了各种可能的事件监听者把自己注册入合适的事件源中，建立源与事件监听者间的事件流，事件源必须为事件监听者提供注册和注销的方法。在前面的bound属性介绍中已看到了这种使用过程，在实际中，事件监听者的注册和注销要使用标准的设计格式：</p>
<p>public void add&lt; ListenerType&gt;(&lt; ListenerType&gt; listener)；<br>public void remove&lt; ListenerType&gt;(&lt; ListenerType&gt; listener)；</p>
<p>　　首先定义了一个事件监听者接口：</p>
<p>public interface ModelChangedListener extends java。util。EventListener {<br>void modelChanged(EventObject e);<br>}</p>
<p>　　接着定义事件源类：</p>
<p>public abstract class Model {<br>private Vector listeners = new Vector(); // 定义了一个储存事件监听者的数组<br>/*上面设计格式中的&lt; ListenerType&gt;在此处即是下面的ModelChangedListener*/</p>
<p>public synchronized void addModelChangedListener(ModelChangedListener mcl)<br>　　{ listeners.addElement(mcl); }//把监听者注册入listeners数组中<br>public synchronized void removeModelChangedListener(ModelChangedListener mcl)<br>　　　　{ listeners.removeElement(mcl); file://把监听者从listeners中注销<br>　　　　｝<br>　　/*以上两个方法的前面均冠以synchronized，是因为运行在多线程环境时，可能同时有几个对象同时要进行注册和注销操作，使用synchronized来确保它们之间的同步。开发工具或程序员使用这两个方法建立源与监听者之间的事件流*/</p>
<p>　　protected void notifyModelChanged() {/**事件源使用本方法通知监听者发生了modelChanged事件*/<br>　　　 Vector l;<br>　　　　EventObject e = new EventObject(this);<br>　　　　/* 首先要把监听者拷贝到l数组中，冻结EventListeners的状态以传递事件。这样来确保在事件传递到所有监听者之前，已接收了事件的目标监听者的对应方法暂不生效。*/<br>　　　　synchronized(this) {<br>　　　　　　l = (Vector)listeners.clone();<br>　　　　}<br>　　　　for (int i = 0; i &lt; l.size(); i++) {<br>　　　　 /* 依次通知注册在监听者队列中的每个监听者发生了modelChanged事件，<br>　　　　 并把事件状态对象e作为参数传递给监听者队列中的每个监听者*/<br>((ModelChangedListener)l.elementAt(i)).modelChanged(e);<br>　　　　}<br>　　　 }<br>　　　｝</p>
<p>　　在程序中可见事件源Model类显式地调用了接口中的modelChanged方法，实际是把事件状态对象e作为参数，传递给了监听者类中的modelChanged方法。</p>
<p>　　适配类</p>
<p>　　适配类是Java事件模型中极其重要的一部分。在一些应用场合，事件从源到监听者之间的传递要通过适配类来"转发"。例如：当事件源发出一个事件，而有几个事件监听者对象都可接收该事件，但只有指定对象做出反应时，就要在事件源与事件监听者之间插入一个事件适配器类，由适配器类来指定事件应该是由哪些监听者来响应。适配类成为了事件监听者，事件源实际是把适配类作为监听者注册入监听者队列中，而真正的事件响应者并未在监听者队列中，事件响应者应做的动作由适配类决定。目前绝大多数的开发工具在生成代码时，事件处理都是通过适配类来进行的。</p>
<p>C#事件处理</p>
<p>　　在。 NET应用程序开发中，不管是WEB Forms（ASP。NET）还是Windows Forms，都涉及到大量对象的事件响应及处理，比如客户在线提交一份订单、或是在Windows窗口上移动鼠标等都将有事件发生。那么在C#中，是怎样声明事件并为事件添加响应方法的呢？</p>
<p>　　在C#中，事件(Events)成员就是用来声明一个类事件的。在类中声明一个事件成员一般采用如下的语法形式：</p>
<p>　　public event 代表名 事件名。</p>
<p>　　如在Control类中声明了一个Click事件成员，其语法如下：</p>
<p>　　public event EventHandler Click;</p>
<p>　　在C#中，增加了一个新的数据类型delegate来解决事件处理问题。代表数据类型非常类似于C语言中的指针，其与指针不同的是，其是代码是安全的，可管理的。由于C#本身的简易性，对于没有使用过C及指针的程序来说，理解delegate也是非常容易的。</p>
<p>　　在C#中，通过使用delegate，你可以通过"+="操作符非常容易地为。Net对象中的一个事件添加一个甚至多个响应方法；还可以通过非常简单的"-="操作符取消这些响应方法。如下面为temp按钮添加Click事件的语句：</p>
<p>temp。Click+=new System.EventHandler(this.Test);//为test添加事件处理方法</p>
<p>　　在上面声明事件的语句中，Eventhandler是一个delegate(代表)类型，其在。Net类库中如下声明的：</p>
<p>public delegate void EventHandler(object sender，EventArgs e);</p>
<p>　　这样，所有形如:void 函娄名(object 参数名，EventArgs 参数名);的函数都可以作为Control类的Click事件响应方法了。如下面所定义的一个事件响应方法：</p>
<p>private void button1_Click(object sender， System.EventArgs e)</p>
<p>　　由于是通过delegate来处理事件，因此，可能通过累加使一个事件具有多个响应方法；与此同时，还可以使一个方法作为多个事件的响应方法(注意：在 C#语言类中的event成员后面只能出现"+="与"-="两个表示添加与取消事件响应函数的操作符)。不管是ASP。Net还是一般的Windows Forms 编程，在C#中，基本上我们遇到的事件响应方法都是说明成如下的形式：</p>
<p>private void button1_Click(object sender， System。EventArgs e)</p>
<p>　　那么，一个事件响应方法的存取权限、返回值类型、参数及类型甚至方法名称等是否都必须固定不变呢？答案是：不是！</p>
<p>　　一般情况下，事件的响应方法中都有两个参数，其中一个代表引发事件的对象即sender，由于引发事件的对象不可预知的，因此我们把其声明成为 object类型，所有的对象都适用。第二个参数代表引发事件的具体信息，各种类型的事件中可能不同，这要根据类中事件成员的说明决定。</p>
<p>　　我们知道，事件是通过delegate来处理的。假设将要表示事件说明成如下形式：</p>
<p>delegate int MyEventHandler(object sender， ToolBarButtonClickEventArgs e);</p>
<p>　　则当涉及上面的事件响应函数声明时，就须要声明成如下的形式：</p>
<p>private int MyTest(object sender，ToolBarButtonClickEventArgs e) {}</p>
<p>　　在给对象添加事件响应方法时就可以用如下的代码实现：</p>
<p>Control。Event+=new MyEventHandler(MyTest);</p>
<p>　　总的来说，Java事件处理更直接，简单。而C#事件处理由于引用代理，使得程序更灵活，更体现程序之间的松藕合性。美国神鸟（Stryon <a href="http://www.stryon.com.cn/">http://www.stryon.com.cn</a>）公司宣布在Java开发平台上实现微软的.NET，命名为iNET。并于近期推出iNET的 Beta3版本，其中就包括用Java实现了C#的三级事件处理机制。</p>
<p>&nbsp;</p>
<img src ="http://www.cppblog.com/littlesupersun/aggbug/31299.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/littlesupersun/" target="_blank">香心晓筑</a> 2007-08-31 14:12 <a href="http://www.cppblog.com/littlesupersun/archive/2007/08/31/31299.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>具体实现XML的三种方式</title><link>http://www.cppblog.com/littlesupersun/archive/2007/08/31/31296.html</link><dc:creator>香心晓筑</dc:creator><author>香心晓筑</author><pubDate>Fri, 31 Aug 2007 05:55:00 GMT</pubDate><guid>http://www.cppblog.com/littlesupersun/archive/2007/08/31/31296.html</guid><wfw:comment>http://www.cppblog.com/littlesupersun/comments/31296.html</wfw:comment><comments>http://www.cppblog.com/littlesupersun/archive/2007/08/31/31296.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/littlesupersun/comments/commentRss/31296.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/littlesupersun/services/trackbacks/31296.html</trackback:ping><description><![CDATA[1. 第一种方式为： 让XML文档和与其关联的XSL级联样表同时被传送到客户端（通常使用的是浏览器）,然后在客户端让XML文档根据XSL定义的显示格式显示其内容。<br>2. 第二种方式为：在服务端就使用XSL级联样表转换XML文档为其他的格式（通常为HTML格式）然后在把转换过的文档传送给客户端（一般使用浏览器）<br>3. 第三钟方式为：使用第三方的产品，在将XML文档放到服务端之前就将该文档转换成其他的格式（一般为HTML格式）。然后服务端和客户端就和平常处理HTML一样来处理了。
<img src ="http://www.cppblog.com/littlesupersun/aggbug/31296.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/littlesupersun/" target="_blank">香心晓筑</a> 2007-08-31 13:55 <a href="http://www.cppblog.com/littlesupersun/archive/2007/08/31/31296.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>深刻剖析经典面试题之一：堆和栈的区别</title><link>http://www.cppblog.com/littlesupersun/archive/2007/08/31/31291.html</link><dc:creator>香心晓筑</dc:creator><author>香心晓筑</author><pubDate>Fri, 31 Aug 2007 05:34:00 GMT</pubDate><guid>http://www.cppblog.com/littlesupersun/archive/2007/08/31/31291.html</guid><wfw:comment>http://www.cppblog.com/littlesupersun/comments/31291.html</wfw:comment><comments>http://www.cppblog.com/littlesupersun/archive/2007/08/31/31291.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/littlesupersun/comments/commentRss/31291.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/littlesupersun/services/trackbacks/31291.html</trackback:ping><description><![CDATA[<p>堆（heap）和栈(stack)的区别</p>
<p>一、预备知识—程序的内存分配<br>一个由c/C++编译的程序占用的内存分为以下几个部分<br>1、栈区（stack）—由编译器自动分配释放，存放函数的参数值，局部变量的值等。其操作方式类似于数据结构中的栈。<br>2、堆区（heap）—一般由程序员分配释放，若程序员不释放，程序结束时可能由OS回收。注意它与数据结构中的堆是两回事，分配方式倒是类</p>
<p>似于链表，呵呵。<br>3、全局区（静态区）（static）—全局变量和静态变量的存储是放在一块的，初始化的全局变量和静态变量在一块区域，未初始化的全局变量</p>
<p>和未初始化的静态变量在相邻的另一块区域。程序结束后由系统释放。<br>4、文字常量区—常量字符串就是放在这里的。程序结束后由系统释放。<br>5、程序代码区—存放函数体的二进制代码。</p>
<p><br>二、例子程序<br>这是一个前辈写的，非常详细<br>//main.cpp<br>&nbsp; int a=0;&nbsp;&nbsp;&nbsp; //全局初始化区<br>&nbsp; char *p1;&nbsp;&nbsp; //全局未初始化区<br>&nbsp; main()<br>&nbsp; {<br>&nbsp;&nbsp; intb;栈<br>&nbsp;&nbsp; char s[]="abc";&nbsp;&nbsp; //栈<br>&nbsp;&nbsp; char *p2;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //栈<br>&nbsp;&nbsp; char *p3="123456";&nbsp;&nbsp; //123456\0在常量区，p3在栈上。<br>&nbsp;&nbsp; static int c=0；&nbsp;&nbsp; //全局（静态）初始化区<br>&nbsp;&nbsp; p1 = (char*)malloc(10);<br>&nbsp;&nbsp; p2 = (char*)malloc(20);&nbsp;&nbsp; //分配得来得10和20字节的区域就在堆区。<br>&nbsp;&nbsp; strcpy(p1,"123456");&nbsp;&nbsp; //123456\0放在常量区，编译器可能会将它与p3所向"123456"优化成一个地方。<br>}</p>
<p><br>二、堆和栈的理论知识<br>2.1申请方式<br>stack:<br>由系统自动分配。例如，声明在函数中一个局部变量int b;系统自动在栈中为b开辟空间<br>heap:<br>需要程序员自己申请，并指明大小，在c中malloc函数<br>如p1=(char*)malloc(10);<br>在C++中用new运算符<br>如p2=(char*)malloc(10);<br>但是注意p1、p2本身是在栈中的。</p>
<p><br>2.2<br>申请后系统的响应<br>栈：只要栈的剩余空间大于所申请空间，系统将为程序提供内存，否则将报异常提示栈溢出。<br>堆：首先应该知道操作系统有一个记录空闲内存地址的链表，当系统收到程序的申请时，<br>会遍历该链表，寻找第一个空间大于所申请空间的堆结点，然后将该结点从空闲结点链表中删除，并将该结点的空间分配给程序，另外，对于</p>
<p>大多数系统，会在这块内存空间中的首地址处记录本次分配的大小，这样，代码中的delete语句才能正确的释放本内存空间。另外，由于找到</p>
<p>的堆结点的大小不一定正好等于申请的大小，系统会自动的将多余的那部分重新放入空闲链表中。</p>
<p>2.3申请大小的限制<br>栈：在Windows下,栈是向低地址扩展的数据结构，是一块连续的内存的区域。这句话的意思是栈顶的地址和栈的最大容量是系统预先规定好的</p>
<p>，在WINDOWS下，栈的大小是2M（也有的说是1M，总之是一个编译时就确定的常数），如果申请的空间超过栈的剩余空间时，将提示overflow。</p>
<p>因此，能从栈获得的空间较小。<br>堆：堆是向高地址扩展的数据结构，是不连续的内存区域。这是由于系统是用链表来存储的空闲内存地址的，自然是不连续的，而链表的遍历</p>
<p>方向是由低地址向高地址。堆的大小受限于计算机系统中有效的虚拟内存。由此可见，堆获得的空间比较灵活，也比较大。</p>
<p><br>2.4申请效率的比较：<br>栈:由系统自动分配，速度较快。但程序员是无法控制的。<br>堆:是由new分配的内存，一般速度比较慢，而且容易产生内存碎片,不过用起来最方便.<br>另外，在WINDOWS下，最好的方式是用Virtual Alloc分配内存，他不是在堆，也不是在栈,而是直接在进程的地址空间中保留一块内存，虽然用</p>
<p>起来最不方便。但是速度快，也最灵活。</p>
<p>2.5堆和栈中的存储内容<br>栈：在函数调用时，第一个进栈的是主函数中后的下一条指令（函数调用语句的下一条可执行语句）的地址，然后是函数的各个参数，在大多</p>
<p>数的C编译器中，参数是由右往左入栈的，然后是函数中的局部变量。注意静态变量是不入栈的。<br>当本次函数调用结束后，局部变量先出栈，然后是参数，最后栈顶指针指向最开始存的地址，也就是主函数中的下一条指令，程序由该点继续</p>
<p>运行。<br>堆：一般是在堆的头部用一个字节存放堆的大小。堆中的具体内容由程序员安排。</p>
<p>2.6存取效率的比较</p>
<p>char s1[]="aaaaaaaaaaaaaaa";<br>char *s2="bbbbbbbbbbbbbbbbb";<br>aaaaaaaaaaa是在运行时刻赋值的；<br>而bbbbbbbbbbb是在编译时就确定的；<br>但是，在以后的存取中，在栈上的数组比指针所指向的字符串(例如堆)快。<br>比如：<br>#include<br>voidmain()<br>{<br>char a=1;<br>char c[]="1234567890";<br>char *p="1234567890";<br>a = c[1];<br>a = p[1];<br>return;<br>}<br>对应的汇编代码<br>10:a=c[1];<br>004010678A4DF1movcl,byteptr[ebp-0Fh]<br>0040106A884DFCmovbyteptr[ebp-4],cl<br>11:a=p[1];<br>0040106D8B55ECmovedx,dwordptr[ebp-14h]<br>004010708A4201moval,byteptr[edx+1]<br>004010738845FCmovbyteptr[ebp-4],al<br>第一种在读取时直接就把字符串中的元素读到寄存器cl中，而第二种则要先把指针值读到edx中，在根据edx读取字符，显然慢了。</p>
<p><br>2.7小结：<br>堆和栈的区别可以用如下的比喻来看出：<br>使用栈就象我们去饭馆里吃饭，只管点菜（发出申请）、付钱、和吃（使用），吃饱了就走，不必理会切菜、洗菜等准备工作和洗碗、刷锅等</p>
<p>扫尾工作，他的好处是快捷，但是自由度小。<br>使用堆就象是自己动手做喜欢吃的菜肴，比较麻烦，但是比较符合自己的口味，而且自由度大。</p>
<img src ="http://www.cppblog.com/littlesupersun/aggbug/31291.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/littlesupersun/" target="_blank">香心晓筑</a> 2007-08-31 13:34 <a href="http://www.cppblog.com/littlesupersun/archive/2007/08/31/31291.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>