什么是对象引用的引用

&&&&&&&&&&&&
JSP内置对象之session对象简介及调用方法
  application对象不同。application对象用于在多个程序之间保存信息,application对象只有一个,它可以绑定若干个相当于全局变量的参数或者Java对象,每个JSP程序所访问的都是application对象的一个同步副本,都是一样的,而且application对象的生命周期贯穿服务器的整个运行周期。但是,服务器上的session对象却可以有多个,不同的用户所面临的session对象一般来说是不同的,当用户登录网站,系统将为他生成一个独一无二的session对象,用以记录该用户的个人信息,一旦该用户退出网站,那么该session对象将会被注销。session对象也可以绑定若干个参数或者Java对象,这些参数或者Java对象就相当于局部变量,不同session对象间的同名变量是不会相互干扰的。应用session对象的功能,可以十分简单地实现购物车等功能。
  但是我们仅能获取原session对象的一个同步副本,这一点上,session对象和application对象是一致的。application对象和session对象并非不能被创建,但是,他们只能够由JSP引擎自动创建。application对象在服务器启动的时候被创建,在服务器关闭时被删除,session对象在新的HTTP连接产生时被创建,在HTTP连接中断或者超时的时候被删除,同时,JSP程序员也可以调用invalidate()方法强行删除session对象,中断HTTP连接。这是application对象和session对象的不同点之一。
  session对象概要其主要关键点是:
  ?&& HTTP是无状态(stateless)协议;
  ?&& Web Server 对每一个客户端请求都没有历史记忆;
  ?&& Session用来保存客户端状态信息;
  ?&& 由Web Server 写入;存于客户端;
  ?&& 客户端的每次访问都把上次的session记录传递给Web Server;
  ?&& Web Server读取客户端提交的session来获取客户端的
  状态信息;
  Session对象的获取方法:
  1)使用session关键字直接引用session对象
  session.Method();
  2)使用request对象的getSession()方法
  使用request对象的getSession()方法可以返回HttpSession接口的实例对象,也就是session对象,注意,这个新获得的HttpSession对象不能够被命名为session,因为session是JSP引擎自动创建的当前session对象的一个同步副本。
  HttpSession mysession=request.getSession(true);
  out.println(mysession.getId());
  out.println(“&br&”);
  out.println(session.getId());
  首先使用getSession()方法获取HttpSession对象――mysession,然后输出它的id,同时也输出session的id,程序4-18的运行结果证明了这两个id是一样的,要注意的是每个用户的session对象的id是不同的(服务器就靠不同的id鉴别不同的session对象),而且每个用户只能够有一个session对象,无论mysession还是session,都是当前session对象的一个同步副本。
  3)使用PageContext对象的getSession()方法
  使用pageContext对象的getServletContext()方法可以获得application对象的副本,同样,使用pageContext对象的getSession()方法也可以获取session对象的一个副本。
  HttpSession mysession=request.getSession();
  HttpSession mysession2=pageContext.getSession();
  out.println(mysession.getId()+”&br&”);
  out.println(session.getId()+”&br&”);
  out.println(mysession2.getId()+”&br&”);
  程序段得到的三个结果都是相同的。
            
博客推荐 
计算机等级考试图书推荐
免责声明:
① 凡本站注明“稿件来源:中国教育在线”的所有文字、图片和音视频稿件,版权均属本网所有,任何媒体、网站或个人未经本网协议授权不得转载、链接、转贴或以其他方式复制发表。已经本站协议授权的媒体、网站,在下载使用时必须注明“稿件来源:中国教育在线”,违者本站将依法追究责任。
② 本站注明稿件来源为其他媒体的文/图等稿件均为转载稿,本站转载出于非商业性的教育和科研之目的,并不意味着赞同其观点或证实其内容的真实性。如转载稿涉及版权等问题,请作者在两周内速来电或来函联系。
京公网安备号天极传媒:天极网全国分站
您现在的位置:
& &&C++箴言:必须返回对象时别返回引用
C++箴言:必须返回对象时别返回引用
csdn blog 09:44
  一旦程序员抓住对象传值的效率隐忧,很多人就会成为狂热的圣战分子,誓要根除传值的罪恶,无论它隐藏多深。他们不屈不挠地追求传引用的纯度,但他们全都犯了一个致命的错误:他们开始传递并不存在的对象的引用。这可不是什么好事。
  考虑一个代表有理数的类,包含一个将两个有理数相乘的函数:
class Rational { public:  Rational(int numerator = 0, // see Item 24 for why this  int denominator = 1); // ctor isn’t declared explicit  ... private:  int n, // numerator and denominator friend:  const Rational // see Item 3 for why the  operator*(const Rational& lhs, // return type is const  const Rational& rhs);};  operator* 的这个版本以传值方式返回它的结果,而且如果你没有担心那个对象的构造和析构的代价,你就是在推卸你的专业职责。如果你不是迫不得已,你不应该为这样的一个对象付出成本。所以问题就在这里:你是迫不得已吗?  哦,如果你能用返回一个引用来作为代替,你就不是迫不得已。但是,请记住一个引用仅仅是一个名字,一个实际存在的对象的名字。无论何时只要你看到一个引用的声明,你应该立刻问自己它是什么东西的另一个名字,因为它必定是某物的另一个名字。在这个 operator* 的情况下,如果函数返回一个引用,它必须返回某个已存在的而且其中包含两个对象相乘的产物的 Rational 对象的引用。  当然没有什么理由期望这样一个对象在调用 operator* 之前就存在。也就是说,如果你有
Rational a(1, 2); // a = 1/2Rational b(3, 5); // b = 3/5Rational c = a * // c should be 3/10  似乎没有理由期望那里碰巧已经存在一个值为十分之三的有理数。不是这样的,如果 operator* 返回这样一个数的引用,它必须自己创建那个数字对象。  一个函数创建一个新对象仅有两种方法:在栈上或者在堆上。栈上的生成物通过定义一个局部变量而生成。使用这个策略,你可以用这种方法试写 operator*:
const Rational& operator*(const Rational& lhs, // warning! bad code!const Rational& rhs){ Rational result(lhs.n * rhs.n, lhs.d * rhs.d); }  你可以立即否决这种方法,因为你的目标是避免调用构造函数,而 result 正像任何其它对象一样必须被构造。一个更严重的问题是这个函数返回一个引向 result 的引用,但是 result 是一个局部对象,而局部对象在函数退出时被销毁。那么,这个 operator* 的版本不会返回引向一个 Rational 的引用――它返回引向一个前 Rational;一个曾经的 Rational;一个空洞的、恶臭的、腐败的,从前是一个 Rational 但永不再是的尸体的引用,因为它已经被销毁了。任何调用者甚至于没有来得及匆匆看一眼这个函数的返回值就立刻进入了未定义行为的领地。这是事实,任何返回一个引向局部变量的引用的函数都是错误的。(对于任何返回一个指向局部变量的指针的函数同样成立。)  那么,让我们考虑一下在堆上构造一个对象并返回引向它的引用的可能性。基于堆的对象通过使用 new 而开始存在,所以你可以像这样写一个基于堆的 operator*:
const Rational& operator*(const Rational& lhs, // warning! more badconst Rational& rhs) // code!{ Rational *result = new Rational(lhs.n * rhs.n, lhs.d * rhs.d); return *}  哦,你还是必须要付出一个构造函数调用的成本,因为通过 new 分配的要通过调用一个适当的构造函数进行初始化,但是现在你有另一个问题:谁是删除你用 new 做出来的对象的合适人选?  即使调用者尽职尽责且一心向善,它们也不太可能是用这样的方案来合理地预防泄漏:
Rational w, x, y,w = x * y * // same as operator*(operator*(x, y), z)  这里,在同一个语句中有两个 operator* 的调用,因此 new 被使用了两次,这两次都需要使用 delete 来销毁。但是 operator* 的客户没有合理的办法进行那些调用,因为他们没有合理的办法取得隐藏在通过调用 operator* 返回的引用后面的指针。这是一个早已注定的资源泄漏。  但是也许你注意到无论是在栈上的还是在堆上的方法,为了从 operator* 返回的每一个 result,我们都不得不容忍一次构造函数的调用。也许你想起我们最初的目标是避免这样的构造函数调用。也许你认为你知道一种方法能避免除一次以外几乎全部的构造函数调用。也许下面这个实现是你做过的,一个基于 operator* 返回一个引向 static Rational 对象的引用的实现,而这个 static Rational 对象定义在函数内部:
const Rational& operator*(const Rational& lhs, // warning! yet moreconst Rational& rhs) // bad code!{ static R // static object to which a // reference will be returned result = ... ; // multiply lhs by rhs and put the // product inside result }  就像所有使用了 static 对象的设计一样,这个也会立即引起我们的线程安全(thread-safety)的混乱,但那是它的比较明显的缺点。为了看到它的更深层的缺陷,考虑这个完全合理的客户代码:
bool operator==(const Rational& lhs, // an operator==const Rational& rhs); // for RationalsRational a, b, c,...if ((a * b) == (c * d)) { do whatever’s appropriate when th} else { do whatever’s appropriate when they’}  猜猜会怎么样?不管 a,b,,d 的值是什么,表达式 ((a*b) == (c*d)) 总是等于 true!  如果代码重写为功能完全等价的另一种形式,这一启示就很容易被理解了:
if (operator==(operator*(a, b), operator*(c, d)))  注意,当 operator== 被调用时,将同时存在两个起作用的对 operator* 的调用,每一个都将返回引向 operator* 内部的 static Rational 对象的引用。因此,operator== 将被要求比较 operator* 内部的 static Rational 对象的值和 operator* 内部的 static Rational 对象的值。如果它们不是永远相等,那才真的会令人大惊失色了。  这些应该足够让你信服试图从类似 operator* 这样的函数中返回一个引用纯粹是浪费时间,但是你们中的某些人可能会这样想“好吧,就算一个 static 不够用,也许一个 static 的数组是一个窍门……”  我无法拿出示例代码来肯定这个设计,但我可以概要说明为什么这个想法应该让你羞愧得无地自容。首先,你必须选择一个 n 作为数组的大小。如果 n 太小,你可能会用完存储函数返回值的空间,与刚刚名誉扫地的 single-static 设计相比,在任何一个方面你都不会得到更多的东西。但是如果 n 太大,就会降低你的程序的性能,因为在函数第一次被调用的时候数组中的每一个对象都会被构造。即使这个我们正在讨论的函数仅被调用了一次,也将让你付出 n 个构造函数和 n 个析构函数的成本。如果“优化”是提高软件效率的过程,对于这种东西也只能是“悲观主义”的。最后,考虑你怎样将你所需要的值放入数组的对象中,以及你做这些需要付出什么。在两个对象间移动值的最直接方法就是通过赋值,但是一次赋值将要付出什么?对于很多类型,这就大约相当于调用一次析构函数(销毁原来的值)加上调用一次构造函数(把新值拷贝过去)。但是你的目标是避免付出构造和析构成本!面对的结果就是:这个方法绝对不会成功。(不,用一个 vector 代替数组也不会让事情有多少改进。)  写一个必须返回一个新对象的函数的正确方法就是让那个函数返回一个新对象。对于 Rational 的 operator*,这就意味着下面这些代码或在本质上与其相当的某些东西:
inline const Rational operator*(const Rational& lhs, const Rational& rhs){ return Rational(lhs.n * rhs.n, lhs.d * rhs.d);}  当然,你可能付出了构造和析构 operator* 的返回值的成本,但是从长远看,这只是为正确行为付出的很小的代价。除此之外,这种令你感到恐怖的账单也许永远都不会到达。就像所有的程序设计语言,C++ 允许编译器的实现者在不改变生成代码的可观察行为的条件下使用优化来提升它的性能,在某些条件下会产生如下结果:operator* 的返回值的构造和析构能被安全地消除。如果编译器利用了这一点(编译器经常这样做),你的程序还是在它假定的方法上继续运行,只是比你期待的要快。 全部的焦点在这里:如果需要在返回一个引用和返回一个对象之间做出决定,你的工作就是让那个选择能提供正确的行为。让你的编译器厂商去绞尽脑汁使那个选择尽可能地廉价。###adv###  Things to Remember  ?绝不要返回一个局部栈对象的指针或引用,绝不要返回一个被分配的堆对象的引用,如果存在需要一个以上这样的对象的可能性时,绝不要返回一个局部 static 对象的指针或引用。
(作者:fatalerror99责任编辑:方舟)
欢迎在新浪微博上关注我们
* 网友发言均非本站立场,本站不在评论栏推荐任何网店、经销商,谨防上当受骗!
Win8系统突破性地增加了全新界面、内置Windows Store、支持ARM架构等诸多全新设计。
手机整机DIY企业级
pc软件手机软件
document.write("");基于SOAP的分布式对象调用机制的研究
扫扫二维码,随身浏览文档
手机或平板扫扫即可继续访问
基于SOAP的分布式对象调用机制的研究
举报该文档为侵权文档。
举报该文档含有违规或不良信息。
反馈该文档无法正常浏览。
举报该文档为重复文档。
推荐理由:
将文档分享至:
分享完整地址
文档地址:
粘贴到BBS或博客
flash地址:
支持嵌入FLASH地址的网站使用
html代码:
&embed src='/DocinViewer-4.swf' width='100%' height='600' type=application/x-shockwave-flash ALLOWFULLSCREEN='true' ALLOWSCRIPTACCESS='always'&&/embed&
450px*300px480px*400px650px*490px
支持嵌入HTML代码的网站使用
您的内容已经提交成功
您所提交的内容需要审核后才能发布,请您等待!
3秒自动关闭窗口您所在的位置: &
第6条:消除过期的对象引用
第6条:消除过期的对象引用
机械工业出版社
《Effective Java中文版(第2版)》第2章 创建和销毁对象,本章的主题是创建和销毁对象:何时以及如何创建对象,何时以及如何避免创建对象,如何确保它们能够被适时地销毁,以及如何管理销毁之前必须进行的所有清除动作。本节为大家介绍的是消除过期的对象引用。
第6条:消除过期的对象引用
当你从手工管理内存的语言(比如C或C++)转换到具有垃圾回收功能的语言的时候,程序员的工作会变得更加容易,因为当你用完了对象之后,它们会被自动回收。当你第一次经历对象回收功能的时候,会觉得这简直有点不可思议。这很容易给你留下这样的印象,认为自己不再需要考虑内存管理的事情了。其实不然。
考虑下面这个简单的栈实现的例子:
// Can you spot the "memory leak"?public class Stack {private Object[]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++] =}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);}}
这段程序(它的泛型版本请见第26条)中并没有很明显的错误。无论如何测试,它都会成功地通过每一项测试,但是这个程序中隐藏着一个问题。不严格地讲,这段程序有一个"内存泄漏(Memory Leak)",随着垃圾回收器活动的增加,或者由于内存占用的不断增加,程序性能的降低会逐渐表现出来。在极端的情况下,这种内存泄漏会导致磁盘分页,甚至导致程序失败,而出现OutOfMemoryError错误,但是这种失败情形相对比较少见。
那么,程序中哪里发生了内存泄漏呢?如果一个栈先是增长,然后再收缩,那么,从栈中弹出来的对象将不会被当作垃圾回收,即使使用栈的程序不再引用这些对象,它们也不会被回收。这是因为,栈内部维护着对这些对象的过期引用(obsolete reference)。所谓的过期引用,是指永远也不会再被解除的引用。在本例中,凡是在elements数组的"活动部分(active portion)"之外的任何引用都是过期的。活动部分是指elements中下标小于size的那些元素。
在支持垃圾回收的语言中,内存泄漏是很隐蔽的(称这类内存泄漏为"无意识的对象保持(unintentional object retention)"更为恰当)。如果一个对象引用被无意识地保留起来了,那么,垃圾回收机制不仅不会处理这个对象,而且也不会处理被这个对象所引用的所有其他对象。即使只有少量的几个对象引用被无意识地保留下来,也会有许许多多的对象被排除在垃圾回收机制之外,从而对性能造成潜在的重大影响。
这类问题的修复方法很简单:一旦对象引用已经过期,只需清空这些引用即可。对于上述例子中的Stack类而言,只要一个单元被弹出栈,指向它的引用就过期了。pop方法的修订版本如下所示:
public Object pop() {if (size == 0)throw new EmptyStackException();Object result = elements[--size];elements[size] = // Eliminate obsolete reference}
清空过期引用的另一个好处是,如果它们以后又被错误地解除引用,程序就会立即抛出NullPointerException异常,而不是悄悄地错误运行下去。尽快地检测出程序中的错误总是有益的。
当程序员第一次被类似这样的问题困扰的时候,他们往往会过分小心:对于每一个对象引用,一旦程序不再用到它,就把它清空。其实这样做既没必要,也不是我们所期望的,因为这样做会把程序代码弄得很乱。清空对象引用应该是一种例外,而不是一种规范行为。消除过期引用最好的方法是让包含该引用的变量结束其生命周期。如果你是在最紧凑的作用域范围内定义每一个变量(见第45条),这种情形就会自然而然地发生。
那么,何时应该清空引用呢?Stack类的哪方面特性使它易于遭受内存泄漏的影响呢?简而言之,问题在于,Stack类自己管理内存(manage its own memory)。存储池(storage pool)包含了elements数组(对象引用单元,而不是对象本身)的元素。数组活动区域(同前面的定义)中的元素是已分配的(allocated),而数组其余部分的元素则是自由的(free)。但是垃圾回收器并不知道这一点;对于垃圾回收器而言,elements数组中的所有对象引用都同等有效。只有程序员知道数组的非活动部分是不重要的。程序员可以把这个情况告知垃圾回收器,做法很简单:一旦数组元素变成了非活动部分的一部分,程序员就手工清空这些数组元素。
一般而言,只要类是自己管理内存,程序员就应该警惕内存泄漏问题。一旦元素被释放掉,则该元素中包含的任何对象引用都应该被清空。
内存泄漏的另一个常见来源是缓存。一旦你把对象引用放到缓存中,它就很容易被遗忘掉,从而使得它不再有用之后很长一段时间内仍然留在缓存中。对于这个问题,有几种可能的解决方案。如果你正好要实现这样的缓存:只要在缓存之外存在对某个项的键的引用,该项就有意义,那么就可以用WeakHashMap代表缓存;当缓存中的项过期之后,它们就会自动被删除。记住只有当所要的缓存项的生命周期是由该键的外部引用而不是由值决定时,WeakHashMap才有用处。
更为常见的情形则是,"缓存项的生命周期是否有意义"并不是很容易确定,随着时间的推移,其中的项会变得越来越没有价值。在这种情况下,缓存应该时不时地清除掉没用的项。这项清除工作可以由一个后台线程(可能是Timer或者ScheduledThreadPoolExecutor)来完成,或者也可以在给缓存添加新条目的时候顺便进行清理。LinkedHashMap类利用它的removeEldestEntry方法可以很容易地实现后一种方案。对于更加复杂的缓存,必须直接使用java.lang.ref。
内存泄漏的第三个常见来源是监听器和其他回调。如果你在实现的是客户端注册回调却没有显式地取消注册的API,除非你采取某些动作,否则它们就会积聚。确保回调立即被当作垃圾回收的最佳方法是只保存它们的弱引用(weak reference),例如,只将它们保存成WeakHashMap中的键。
由于内存泄漏通常不会表现成明显的失败,所以它们可以在一个系统中存在很多年。往往只有通过仔细检查代码,或者借助于调试工具(称为Heap Profiler)才能发现内存泄漏问题。因此,如果能够在内存泄漏发生之前就知道如何预测此类问题,并阻止它们发生,那是最好不过的了。【责任编辑: TEL:(010)】&&&&&&
关于&&&&&&的更多文章
又是一周匆匆而过。上周五、周六两天,2013年51CTO云计算架构师
本书描述了黑客用默默无闻的行动为数字世界照亮了一条道路的故事。
本书定位很明确,内容有趣易懂。本书不同于大多数"伪
电商圈第一本自媒体著作《做自己--鬼脚七自媒体第一季
中国对冲基金经理风云录是对冲网阿尔法研究中心组编的
本书从一个网站制作过程入手,详细介绍基于ASP技术建设网站的全过程。全书共10章。第1章,网站制作规划与流程;第2章,IIS安装与
51CTO旗下网站AS3.0中:定义的对象名只是真正对象的一个引用.这句话的含义是什么?var myobj1 :object=(a:123,b:456);var myobj2 :myobj2=myobj1;myobj2.a++;trace(&myobj1.a=&,myobj1.a,&myobj2.a=&,myobj2.a);输出结果是:myobj1.a=124 myobj2.a=124为什么myobj1的_百度作业帮
AS3.0中:定义的对象名只是真正对象的一个引用.这句话的含义是什么?var myobj1 :object=(a:123,b:456);var myobj2 :myobj2=myobj1;myobj2.a++;trace("myobj1.a=",myobj1.a,"myobj2.a=",myobj2.a);输出结果是:myobj1.a=124 myobj2.a=124为什么myobj1的值不是123呢?跟上面的句子有什么关系?
我来回答这个问题吧,这就涉及到对象的引用问题了,什么是引用?其实在AS3.0中,一切皆引用,只是对象在内存中的存在方式不一样,决定了是值引用还是对象引用的关系,一般来说,基本数据类型比如数字,字符布尔值之类的,都是值引用,值引用的最大特点是不可变的,就是固定值,如果想变化,就得重新创建一个值,而所有相同值都是引用同一个对象.比如var a:uint=5;那么就是先在内存中创建一个5的对象,现在我们这样操作a++;那么现在计算机就又要重新创建了一个对象6用于a的引用.那么这个5如何了呢,如果这个5没有其它对象引用它的话,就符合垃圾回收机制,会自动清除掉的.这是简单数据类型的处理方式,那么复杂数据类型的处理方式就与此不同,复杂数据类型在内存中,不是固定不变的值,它是可变的,因此凡是引用这个复杂数据类型的对象,殾对这个内存中的对象具有可操作性,也就是说,如果两个对象同时指向内存中的同一个对象,那么其中如果有一个修改值,都会影响所有指向它的对象的值,以上的例子就是一个.在var myobj1中,它指向了内存中的{a:123,b :456}现在又有myobj2同样也指向了这个对象,因为是同时指向了一个对象,现在对myobj2进行操作,其实是对内存中的对象{a:123,b:456}进行了操作.自然内存中的对象的值发生了改变,现在内存中的对象值变成了{a:124,b:456}那么因为myobj1指向这个对象,自然myobj1也变成了{a:123,b:456};这是编程中很重要的基础知识,如果这方面你搞不明白,那么将来你要提高编程水平会有很大障碍.希望我的解释对你有用,这也是我的理解.祝你成功. 再补充一下:var a:uint=5;var b:uint=a;b++;trace(a);//输出5,因为数字在内存中是常量,为固定值,所以改变b的值是不会改变a的值的.b引用了在内存中新创建的6,而5因为有a在引用,所以内存中现在存在了两个数字对象5和6.现在我们再创建一个对象var c:uint=5;这个时候内存中并没新增加一个对象5而是直接引用了原来的5,现在我们来测试一下trace(a===c);//输出trace(a==c);//输出说明内存中并没有新的对象生成.这是基本数据类型在内存中的特点. 其实对引用这个东西,够写一章了,在这里只能写这么多,要是你有不懂的地方,我们可以交流,总之这部分很重要.

我要回帖

更多关于 对象引用 的文章

 

随机推荐