﻿<?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>BlogJava-谈笑有鸿儒，往来无白丁-文章分类-JAVA好文</title><link>http://www.blogjava.net/badboyryan/category/15086.html</link><description>&lt;hr color=red&gt;
&lt;marquee  direction=left bgcolor= aaaaee behavior=scroll scrollamount=2 onmouseover="this.stop();" onmouseout="this.start();" width=500&gt;
&lt;font color=green&gt; 在恰当的时间、地点以恰当的方式表达给恰当的人...&lt;/font&gt;&amp;nbsp;&amp;nbsp;&lt;font color=blue&gt;阅读的时候请注意分类，佛曰我日里面是谈笑文章，其他是各个分类的文章，积极的热情投入到写博的队伍中来，支持blogjava做大做强！向dudu站长致敬&gt;&gt; &gt;  （qq群侠客岛:26858781）&lt;/font&gt;
&lt;/marquee&gt; 
&lt;hr color=blue&gt;
&lt;marquee  direction=right bgcolor= aabbee behavior=scroll scrollamount=2 onmouseover="this.stop();" onmouseout="this.start();" width=500&gt;
&lt;font color=green&gt;精品推荐:&lt;/font&gt;&lt;a href="http://www.blogjava.net/badboyryan/category/13259.html"&gt;谈笑有鸿儒&lt;/a&gt;
&amp;nbsp;&amp;nbsp;&lt;font color=green&gt;&lt;a href="http://www.blogjava.net/badboyryan/category/14653.html"&gt;&lt;font color=red&gt;资源整合，门户网站&lt;/font&gt;&lt;/a&gt;&lt;/font&gt;&amp;nbsp;&amp;nbsp;
&lt;a href="http://www.blogjava.net/badboyryan/category/15148.html"&gt;JAVA名人堂&lt;/a&gt;
&lt;/marquee&gt; 
&lt;hr color=red&gt;</description><language>zh-cn</language><lastBuildDate>Tue, 27 Feb 2007 11:24:49 GMT</lastBuildDate><pubDate>Tue, 27 Feb 2007 11:24:49 GMT</pubDate><ttl>60</ttl><item><title>基础才是最重要的</title><link>http://www.blogjava.net/badboyryan/articles/91896.html</link><dc:creator>谈笑有鸿儒</dc:creator><author>谈笑有鸿儒</author><pubDate>Fri, 05 Jan 2007 01:40:00 GMT</pubDate><guid>http://www.blogjava.net/badboyryan/articles/91896.html</guid><wfw:comment>http://www.blogjava.net/badboyryan/comments/91896.html</wfw:comment><comments>http://www.blogjava.net/badboyryan/articles/91896.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/badboyryan/comments/commentRss/91896.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/badboyryan/services/trackbacks/91896.html</trackback:ping><description><![CDATA[
		<span id="post1" style="FONT-SIZE: 12px; COLOR: #000000">基础才是最重要的<br /><br />对于这个系列里的问题，每个学Java的人都应该搞懂。当然，如果只是学Java玩玩就无所谓了。如果你认为自己已经超越初学者了，却不很懂这些问题，请将你自己重归初学者行列。内容均来自于CSDN的经典老贴。 <br /><br />问题一：我声明了什么！ <br /><br />String s = "Hello world!"; <br /><br />许多人都做过这样的事情，但是，我们到底声明了什么？回答通常是：一个String，内容是“Hello world!”。这样模糊的回答通常是概念不清的根源。如果要准确的回答，一半的人大概会回答错误。 <br />这个语句声明的是一个指向对象的引用，名为“s”，可以指向类型为String的任何对象，目前指向"Hello world!"这个String类型的对象。这就是真正发生的事情。我们并没有声明一个String对象，我们只是声明了一个只能指向String对象的引用变量。所以，如果在刚才那句语句后面，如果再运行一句： <br /><br />String string = s; <br /><br />我们是声明了另外一个只能指向String对象的引用，名为string，并没有第二个对象产生，string还是指向原来那个对象，也就是，和s指向同一个对象。 <br /><br />问题二："=="和equals方法究竟有什么区别？ <br /><br />==操作符专门用来比较变量的值是否相等。比较好理解的一点是： <br />int a=10; <br />int b=10; <br />则a==b将是true。 <br />但不好理解的地方是： <br />String a=new String("foo"); <br />String b=new String("foo"); <br />则a==b将返回false。 <br /><br />根据前一帖说过，对象变量其实是一个引用，它们的值是指向对象所在的内存地址，而不是对象本身。a和b都使用了new操作符，意味着将在内存中产生两个内容为"foo"的字符串，既然是“两个”，它们自然位于不同的内存地址。a和b的值其实是两个不同的内存地址的值，所以使用"=="操作符，结果会是false。诚然，a和b所指的对象，它们的内容都是"foo"，应该是“相等”，但是==操作符并不涉及到对象内容的比较。 <br />对象内容的比较，正是equals方法做的事。 <br /><br />看一下Object对象的equals方法是如何实现的： <br />boolean equals(Object o){ <br /><br />return this==o; <br /><br />} <br />Object对象默认使用了==操作符。所以如果你自创的类没有覆盖equals方法，那你的类使用equals和使用==会得到同样的结果。同样也可以看出，Object的equals方法没有达到equals方法应该达到的目标：比较两个对象内容是否相等。因为答案应该由类的创建者决定，所以Object把这个任务留给了类的创建者。 <br /><br />看一下一个极端的类： <br />Class Monster{ <br />private String content; <br />... <br />boolean equals(Object another){ return true;} <br /><br />} <br />我覆盖了equals方法。这个实现会导致无论Monster实例内容如何，它们之间的比较永远返回true。 <br /><br />所以当你是用equals方法判断对象的内容是否相等，请不要想当然。因为可能你认为相等，而这个类的作者不这样认为，而类的equals方法的实现是由他掌握的。如果你需要使用equals方法，或者使用任何基于散列码的集合（HashSet,HashMap,HashTable），请察看一下java doc以确认这个类的equals逻辑是如何实现的。 <br /><br />问题三：String到底变了没有？ <br /><br />没有。因为String被设计成不可变(immutable)类，所以它的所有对象都是不可变对象。请看下列代码： <br /><br />String s = "Hello"; <br />s = s + " world!"; <br /><br />s所指向的对象是否改变了呢？从本系列第一篇的结论很容易导出这个结论。我们来看看发生了什么事情。在这段代码中，s原先指向一个String对象，内容是"Hello"，然后我们对s进行了+操作，那么s所指向的那个对象是否发生了改变呢？答案是没有。这时，s不指向原来那个对象了，而指向了另一个String对象，内容为"Hello world!"，原来那个对象还存在于内存之中，只是s这个引用变量不再指向它了。 <br />通过上面的说明，我们很容易导出另一个结论，如果经常对字符串进行各种各样的修改，或者说，不可预见的修改，那么使用String来代表字符串的话会引起很大的内存开销。因为String对象建立之后不能再改变，所以对于每一个不同的字符串，都需要一个String对象来表示。这时，应该考虑使用StringBuffer类，它允许修改，而不是每个不同的字符串都要生成一个新的对象。并且，这两种类的对象转换十分容易。 <br />同时，我们还可以知道，如果要使用内容相同的字符串，不必每次都new一个String。例如我们要在构造器中对一个名叫s的String引用变量进行初始化，把它设置为初始值，应当这样做： <br />public class Demo { <br />private String s; <br />... <br />public Demo { <br />s = "Initial value"; <br />} <br />... <br />} <br />而非 <br />s = new String("Initial value"); <br />后者每次都会调用构造器，生成新对象，性能低下且内存开销大，并且没有意义，因为String对象不可改变，所以对于内容相同的字符串，只要一个String对象来表示就可以了。也就说，多次调用上面的构造器创建多个对象，他们的String类型属性s都指向同一个对象。 <br />上面的结论还基于这样一个事实：对于字符串常量，如果内容相同，Java认为它们代表同一个String对象。而用关键字new调用构造器，总是会创建一个新的对象，无论内容是否相同。 <br />至于为什么要把String类设计成不可变类，是它的用途决定的。其实不只String，很多Java标准类库中的类都是不可变的。在开发一个系统的时候，我们有时候也需要设计不可变类，来传递一组相关的值，这也是面向对象思想的体现。不可变类有一些优点，比如因为它的对象是只读的，所以多线程并发访问也不会有任何问题。当然也有一些缺点，比如每个不同的状态都要一个对象来代表，可能会造成性能上的问题。所以Java标准类库还提供了一个可变版本，即StringBuffer。 <br /><br />问题四：final关键字到底修饰了什么？ <br /><br />final使得被修饰的变量"不变"，但是由于对象型变量的本质是“引用”，使得“不变”也有了两种含义：引用本身的不变，和引用指向的对象不变。 <br /><br />引用本身的不变： <br />final StringBuffer a=new StringBuffer("immutable"); <br />final StringBuffer b=new StringBuffer("not immutable"); <br />a=b;//编译期错误 <br /><br />引用指向的对象不变： <br />final StringBuffer a=new StringBuffer("immutable"); <br />a.append(" broken!"); //编译通过 <br /><br />可见，final只对引用的“值”(也即它所指向的那个对象的内存地址)有效，它迫使引用只能指向初始指向的那个对象，改变它的指向会导致编译期错误。至于它所指向的对象的变化，final是不负责的。这很类似==操作符：==操作符只负责引用的“值”相等，至于这个地址所指向的对象内容是否相等，==操作符是不管的。 <br /><br />理解final问题有很重要的含义。许多程序漏洞都基于此----final只能保证引用永远指向固定对象，不能保证那个对象的状态不变。在多线程的操作中,一个对象会被多个线程共享或修改，一个线程对对象无意识的修改可能会导致另一个使用此对象的线程崩溃。一个错误的解决方法就是在此对象新建的时候把它声明为final，意图使得它“永远不变”。其实那是徒劳的。 <br /><br />问题五：到底要怎么样初始化！ <br /><br />本问题讨论变量的初始化，所以先来看一下Java中有哪些种类的变量。 <br />1. 类的属性，或者叫值域 <br />2. 方法里的局部变量 <br />3. 方法的参数 <br /><br />对于第一种变量，Java虚拟机会自动进行初始化。如果给出了初始值，则初始化为该初始值。如果没有给出，则把它初始化为该类型变量的默认初始值。 <br /><br />int类型变量默认初始值为0 <br />float类型变量默认初始值为0.0f <br />double类型变量默认初始值为0.0 <br />boolean类型变量默认初始值为false <br />char类型变量默认初始值为0(ASCII码) <br />long类型变量默认初始值为0 <br />所有对象引用类型变量默认初始值为null，即不指向任何对象。注意数组本身也是对象，所以没有初始化的数组引用在自动初始化后其值也是null。 <br /><br />对于两种不同的类属性，static属性与instance属性，初始化的时机是不同的。instance属性在创建实例的时候初始化，static属性在类加载，也就是第一次用到这个类的时候初始化，对于后来的实例的创建，不再次进行初始化。这个问题会在以后的系列中进行详细讨论。 <br /><br />对于第二种变量，必须明确地进行初始化。如果再没有初始化之前就试图使用它，编译器会抗议。如果初始化的语句在try块中或if块中，也必须要让它在第一次使用前一定能够得到赋值。也就是说，把初始化语句放在只有if块的条件判断语句中编译器也会抗议，因为执行的时候可能不符合if后面的判断条件，如此一来初始化语句就不会被执行了，这就违反了局部变量使用前必须初始化的规定。但如果在else块中也有初始化语句，就可以通过编译，因为无论如何，总有至少一条初始化语句会被执行，不会发生使用前未被初始化的事情。对于try-catch也是一样，如果只有在try块里才有初始化语句，编译部通过。如果在catch或finally里也有，则可以通过编译。总之，要保证局部变量在使用之前一定被初始化了。所以，一个好的做法是在声明他们的时候就初始化他们，如果不知道要出事化成什么值好，就用上面的默认值吧！ <br /><br />其实第三种变量和第二种本质上是一样的，都是方法中的局部变量。只不过作为参数，肯定是被初始化过的，传入的值就是初始值，所以不需要初始化。 <br /><br />问题六：instance of是什么东东？ <br /><br />instance of是Java的一个二元操作符，和==，&gt;，&lt;是同一类东东。由于它是由字母组成的，所以也是Java的保留关键字。它的作用是测试它左边的对象是否是它右边的类的实例，返回boolean类型的数据。举个例子： <br /><br />String s = "I AM an Object!"; <br />boolean is Object = s instance of Object; <br /><br />我们声明了一个String对象引用，指向一个String对象，然后用instanc of来测试它所指向的对象是否是Object类的一个实例，显然，这是真的，所以返回true，也就是isObject的值为True。 <br />instance of有一些用处。比如我们写了一个处理账单的系统，其中有这样三个类： <br /><br />public class Bill {//省略细节} <br />public class PhoneBill extends Bill {//省略细节} <br />public class GasBill extends Bill {//省略细节} <br /><br />在处理程序里有一个方法，接受一个Bill类型的对象，计算金额。假设两种账单计算方法不同，而传入的Bill对象可能是两种中的任何一种，所以要用instanceof来判断： <br /><br />public double calculate(Bill bill) { <br />if (bill instanceof PhoneBill) { <br />//计算电话账单 <br />} <br />if (bill instanceof GasBill) { <br />//计算燃气账单 <br />} <br />... <br />} <br />这样就可以用一个方法处理两种子类。 <br /><br />然而，这种做法通常被认为是没有好好利用面向对象中的多态性。其实上面的功能要求用方法重载完全可以实现，这是面向对象变成应有的做法，避免回到结构化编程模式。只要提供两个名字和返回值都相同，接受参数类型不同的方法就可以了： <br /><br />public double calculate(PhoneBill bill) { <br />//计算电话账单 <br />} <br /><br />public double calculate(GasBill bill) { <br />//计算燃气账单 <br />} <br /><br />所以，使用instanceof在绝大多数情况下并不是推荐的做法，应当好好利用多态。<br /></span>
<img src ="http://www.blogjava.net/badboyryan/aggbug/91896.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/badboyryan/" target="_blank">谈笑有鸿儒</a> 2007-01-05 09:40 <a href="http://www.blogjava.net/badboyryan/articles/91896.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>金蝶中间件袁红岗:Java EE 5.0是另一次震撼(1)</title><link>http://www.blogjava.net/badboyryan/articles/69282.html</link><dc:creator>谈笑有鸿儒</dc:creator><author>谈笑有鸿儒</author><pubDate>Wed, 13 Sep 2006 00:45:00 GMT</pubDate><guid>http://www.blogjava.net/badboyryan/articles/69282.html</guid><wfw:comment>http://www.blogjava.net/badboyryan/comments/69282.html</wfw:comment><comments>http://www.blogjava.net/badboyryan/articles/69282.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/badboyryan/comments/commentRss/69282.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/badboyryan/services/trackbacks/69282.html</trackback:ping><description><![CDATA[CNET科技资讯网 4月29日 北京消息：被业界称为“中国Java第一人”的金蝶中间件首席科学家袁红岗认为，Java EE 5.0 来得并不晚，可能是J2EE诞生以来比较重量级的一次震撼。<br />　　 在中国Java技术界，袁红岗是一个不能忽视的名字。他的观点，及对中间件趋势的看法，是很多人感兴趣的。日前，在金蝶Apusic于广州花园酒店举办的“Java俱乐部”上，记者和这位极少露面的金蝶中间件首席科学家就集群、Java EE5.0等热门话题展开了直率的深入对话。果然，袁红岗出语惊人，带来了很多独特的视角和精彩的观点。<br />　　 记者：不管是一般的技术观点，还是在平时打单过程中，我们似乎可以感觉到，集群功能一直是国外中间件厂商攻击国内中间件的弱点。而据我们所知，你们金蝶中间件在去年下半年推出了自己的集群功能，并且在宣传中提及，在国家质检总局全行业这个大单中和几个主要国外产品同等测试，测试结果甚至排在前面，这是否表示Apusic的集群功能已经能满足客户的需求？你对集群功能又怎么看，你认为中J2EE集群的本质是什么？<br />　　 袁红岗：首先我可以向你证实，在国家质检总局的核心电子业务系统“大通关”项目中，金蝶Apusic中间件与三家世界主要中间件厂商的产品，在同一平台和环境下用国际测试工具进行了全方位的性能测试，经过三轮严苛的点对点、兼容性和性能测试，结果我们成功夺标。在测试结果中，Apusic在集群性能上并不逊色国外同类产品。<br />　　 集群是中间件厂商经常热捧的一个概念，说只有采取集群策略你的应用系统的性能才能提高。不明就里的用户在付出了数倍的价钱去购买集群设备和软件以后，却往往得不到所应该得到的效果。<br />　　 Apusic作为一家负责任的公司，应当向大家来澄清所谓的“集群悖论”。所谓集群，只有在细粒度计算中其效果才会明显，也就是将计算过程以一定的并行算法进行细分，将计算分布到多个处理机运行，最后再将计算结果合并。有一个很有名计划叫做SETI@home，是一项利用全球联网的闲置计算机共同搜索地外文明的科学实验计划，只需要下载一个小程序就可以对从射点望远镜得到数据进行分析。这就是一个典型的细粒度计算，所有的参与计划的计算机并行地计算浩如烟海的庞大数据库中的一小段数据，再将计算的结果汇总，从而发现可能的智能信号。<br />　　 而反过来我们看到在J2EE应用中大多数计算都是粗粒度的，再加上事务处理需要在分布式计算中进行协调，更降低了集群的整体处理能力。因此集群并不是解决性能问题的最佳途径，在单机低并发的情况下如果你认为性能不理想，那么请不要指望集群能给你带来性能的提升，相反你会发现性能反而还会有所下降。<br />　　 那么，集群仅是厂商宣传的噱头吗？在以下两种情况下集群是有用的：<br />　　 1. 高并发超负荷运行的主机，例如google这样的网站，它的访问量是相当大的，因此google会采取集群策略来分散客户的请求，以提高整体响应能力。我们接触的很多J2EE应用负荷量都不大，其实每秒访问量在500以下的应用都没有必要采取集群策略。<br />　　 2. 失效转移，其实我认为这才是集群真正有用的地方，使用一台低成本计算设备作为主设备的备份，在主设备发生故障时及时接替，以保证7x24小时不间断服务。综上所述，在准备采用集群之前，一定要仔细分析具体的应用环境，以避免不必要的浪费。<br />　　 作为一种选择，Apusic同样实现了集群技术，但我们并没有沿用大多数应用服务器厂商所采取的内存复制技术(in-memory replication)，我们知道在集群中需要在各结点之间同步一些状态信息，如果采用内存复制技术，将耗费大量的网络带宽，对性能也有很大影响。这是因为每当一个结点的状态发生变化时，都需要通过多播等方式向其他结点传递状态信息，随着集群内部结点的增多，内存复制将会非常频繁，从而造成广播风暴，严重阻塞带宽。Apusic所采取的技术是客户端缓存，即直接将状态信息保存在客户端，当服务器失效时将状态转移到可用服务器。<br />　　 记者：其实直到现在，还有人对中国人能做出中间件不相信、对产品不信任。你在去年曾说“大家在同一个标准下开发，Apusic和IBM、BEA的产品没什么本质区别”、对于这句话，你今天能否再解释一下？<br />　　 袁红岗：这个问题其实不需要证明，没有人认为神舟飞船和阿波罗飞船在本质上有什么区别，都是为载人航天而制造出来的工具，并不会因为一个是中国制造、另一个是美国制造，在用途上就存在什么区别。诚然，我们和国外产品还存在一些差距，但在J2EE标准框架之下，我们提供了完全可供用户使用的产品，用户的选择是对我们产品最大的肯定。中国软件起步较晚，基础较薄弱，但在中间件领域我们是及时跟进的，当时站在同一条起跑线上，现在仍然没有被淘汰出局，相反差距还在逐步缩小。我相信凭我们的技术实力，我们完全有资格和国外产品同台竞技。<br />　　 记者：许多技术人员都反映Apusic的启动速度非常快，很快就启动了，和同类产品相比非常突出。看来使用者们对它快速启动的特点非常喜爱。据我了解，Apusic的代码只是其它产品的几分之一，是因为这个原因吗？你设计时是怎么想的？<br />　　 袁红岗：很多人不理解，为什么Apusic和其他产品比起来代码规模上要小很多，但使用起来并没有感觉到有什么功能缺失呢？这里要涉及到软件使用上的一个“二八原则”，即80%的使用者通常只会用到一个软件20%的功能。象微软的产品个个都是巨无霸，但对某个产品真正做到完全精通的可以说寥寥无几。以Word为例，平时我们只是用它来写写文档，很多高级功能其实根本用不上。在Apusic应用服务器的开发上我们也是遵循同样的原则，我们将尽可能地将整个软件产品最重要的20%的功能做好、做完善，以保证大多数用户的需求，剩下的80%功能将根据需要逐步增加。<br />　　 譬如国外产品很早就有的集群功能我们最近才推出来，并不是我们没有能力实现集群功能，而是在我们看来，集群并不是解决性能问题的最好方案，只有在真正大并发请求下集群才会展现它的优势。因此，我们把集群功能归结为低优先级需求，只有在其他方面的性能和稳定性有了很大提高后再来考虑集群。<br />　　 另一个使Apusic运行轻便的重要原因在于软件架构的设计。(未完)
<script language="javascript" src="/inc/content_2.js"></script><img src ="http://www.blogjava.net/badboyryan/aggbug/69282.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/badboyryan/" target="_blank">谈笑有鸿儒</a> 2006-09-13 08:45 <a href="http://www.blogjava.net/badboyryan/articles/69282.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>