﻿<?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-xiaomage234-文章分类-Java Language</title><link>http://www.blogjava.net/xiaomage234/category/1689.html</link><description>行到水穷处,坐看云起时，才发现：其实人生最重要的是找到一些吃的东西；找到一些喝的东西；找到一些可以一起欢笑一起流泪的朋友和一个懂你的人！</description><language>zh-cn</language><lastBuildDate>Fri, 02 Mar 2007 07:36:44 GMT</lastBuildDate><pubDate>Fri, 02 Mar 2007 07:36:44 GMT</pubDate><ttl>60</ttl><item><title>(转)构建Hibernate基础代码</title><link>http://www.blogjava.net/xiaomage234/articles/5816.html</link><dc:creator>小马歌</dc:creator><author>小马歌</author><pubDate>Thu, 09 Jun 2005 07:33:00 GMT</pubDate><guid>http://www.blogjava.net/xiaomage234/articles/5816.html</guid><wfw:comment>http://www.blogjava.net/xiaomage234/comments/5816.html</wfw:comment><comments>http://www.blogjava.net/xiaomage234/articles/5816.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/xiaomage234/comments/commentRss/5816.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/xiaomage234/services/trackbacks/5816.html</trackback:ping><description><![CDATA[<P><FONT face=Arial size=4>1，POJO<BR>&nbsp;&nbsp;&nbsp;&nbsp; POJO在Hibernate语义中理解为数据库表所对应的Domain Object。这里的POJO就是所谓的"Plain Ordinary Java Object"，字面上讲就是无格式普通Java对象，简单的可以理解为一个不包含逻辑代码的值对象（Value Object---VO）。<BR>&nbsp;&nbsp; 一个典型的POJO：<BR>public class TUser implements Serializable {<BR>&nbsp; private String name;<BR>&nbsp; public User(String name) {<BR>&nbsp;&nbsp;&nbsp; this.name = name;<BR>&nbsp; }<BR>&nbsp; /** default constructor */<BR>&nbsp; public User() {<BR>&nbsp; }<BR>&nbsp; public String getName() {<BR>&nbsp;&nbsp;&nbsp; return this.name;<BR>&nbsp; }<BR>&nbsp; public void setName(String name) {<BR>&nbsp;&nbsp;&nbsp; this.name = name;<BR>&nbsp; }<BR>}</FONT></P>
<P><FONT face=Arial size=4>2，Hibernate映射文件<BR>&nbsp;&nbsp; Hibernate从本质上来讲是一种"对象-关系型数据映射"（Object Relational Mapping---ORM）。前面的POJO在这里体现的就是ORM中Object层的语义。而映射（Mapping）文件则是将对象（Object）与关系型数据库（Relational）相关联的纽带，在Hibernate中，映射文件通常以".hbm.xml"作为后缀。</FONT></P>
<P><FONT face=Arial size=4>由数据库产生基础代码<BR>&nbsp;&nbsp; 通过Hibernate官方提供的MiddleGen for Hibernate和Hibernate_Extension工具包，我们可以很方便的根据现有数据库，导出数据库表结构，生成ORM和POJO。</FONT></P>
<P><FONT face=Arial size=4>Hibernate配置<BR>&nbsp;&nbsp; 前面已经得到了映射文件和POJO，为了使Hibernate能真正运作起来，我们还需要一个配置文件。<BR>&nbsp;&nbsp; Hibernate同时支持XML格式的配置文件，以及传统的properties文件配置方式，不过这里建议采用XML型配置文件。XML配置文件提供了更易于读的结构和更强的配置能力，可以直接对映射文件加以配置，而在properties文件中则无法配置，必须通过代码中的Hard Coding加载对应的映射文件。<BR>&nbsp;&nbsp; 配置文件名默认为hibernate.cfg.xml（或者 hibernate.properties），Hibernate初始化期间会自动在CLASSPATH中寻找这个文件，并读取其中的配置信息，为后期数据库操作做好准备。<BR>&nbsp;&nbsp; 配置文件应部署在CLASSPATH中，对于WEB应用而言，配置文件应放置在/WEB-INF/classes目录下。<BR>&nbsp;&nbsp; 一个典型的hibernate.cfg.xml配置文件如下：<BR><!--l version="1.0" encoding="utf-8--><BR><!--CTYPE hibernate-configuration PUBLIC "-//hibernate/hibernate Configuration DTD//EN" "<a href="http://hibernate.sourceforge.net/hibernate-configuration-2.0.dt-->http://hibernate.sourceforge.net/hibernate-configuration-2.0.dtd"&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; jdbc:mysql://localhost/sample<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; org.gjt.mm.mysql.Driver&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; User<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Mypass<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; net.sf.hibernate.dialect.MySQLDialect<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; True<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; True<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; net.sf.hibernate.transaction.JDBCTransactionFactory<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<BR>&nbsp;&nbsp; 一个典型的hibernate.properties配置文件如下：<BR>&nbsp;&nbsp; hibernate.dialect net.sf.hibernate.dialect.MySQLDialect<BR>&nbsp;&nbsp; hibernate.connection.driver_class org.gjt.mm.mysql.Driver<BR>&nbsp;&nbsp; hibernate.connection.driver_class com.mysql.jdbc.Driver<BR>&nbsp;&nbsp; hibernate.connection.url jdbc:mysql:///sample<BR>&nbsp;&nbsp; hibernate.connection.username user<BR>&nbsp;&nbsp; hibernate.connection.password mypass</FONT></P>
<P><FONT face=Arial size=4>第一段代码<BR>&nbsp;&nbsp; 下面这段代码是一个JUnit TestCase，演示了Tuser对象的保存和读取。<BR>public class hiberanteTest extest TestCase {</FONT></P>
<P><FONT face=Arial size=4>&nbsp; Session session = null;<BR>&nbsp; <BR>&nbsp; /**<BR>&nbsp;&nbsp; *JUnit中setUp方法在TestCase初始化的时候会自动调用<BR>&nbsp;&nbsp; *一般用于初始化公有资源<BR>&nbsp;&nbsp; *此例中，用于初始化Hibernate Session<BR>&nbsp;&nbsp; */<BR>&nbsp; protected void setUp() {<BR>&nbsp;&nbsp;&nbsp; try {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /**<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *采用hibernate.properties配置文件的初始化代码：<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *Configuration config = new Configuration();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *config.addClass(TUser.class);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */</FONT></P>
<P><FONT face=Arial size=4>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //采用hibernate.cfg.xml配置文件<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //请注意初始化Configuration时的差异：<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //1，Configuration的初始化方式<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //2，xml文件中已经定义了Mapping文件，因此无需再Hard Coding导入POJO文件的定义。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Configuration config = new Configuration().configure();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SessionFactory sessionFactory = config.buildSesssionFactory();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; session = sessionFactory.openSession();<BR>&nbsp;&nbsp;&nbsp; }catch(HibernateException e) {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; e.printStackTrace();<BR>&nbsp;&nbsp;&nbsp; }<BR>&nbsp; }</FONT></P>
<P><FONT face=Arial size=4>&nbsp; /*<BR>&nbsp;&nbsp; *与setUp方法相对应，JUnit TestCase执行完毕时，会自动调用tearDown方法，一般用于资源释放<BR>&nbsp;&nbsp; *此例中，用于关闭在setUp方法中打开的Hibernate Session<BR>&nbsp;&nbsp; */<BR>&nbsp; protected void tearDown() {<BR>&nbsp;&nbsp;&nbsp; try {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; session.close();<BR>&nbsp;&nbsp;&nbsp; }catch(HibernateException e) {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; e.printStackTrace();<BR>&nbsp;&nbsp;&nbsp; }<BR>&nbsp; }</FONT></P>
<P><FONT face=Arial size=4>&nbsp; /**<BR>&nbsp;&nbsp; *对象持久化（Insert）测试方法<BR>&nbsp;&nbsp; *JUnit中，以"test"作为前缀的方法为测试方法，将被JUnit自动添加到测试计划中运行<BR>&nbsp;&nbsp; */<BR>&nbsp; public void testInsert() {<BR>&nbsp;&nbsp;&nbsp; try {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TUser user = new TUser();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; user.setName("Emma");<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; session.save(user);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; session.flush();<BR>&nbsp;&nbsp;&nbsp; }catch(HibernateException e) {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; e.printStackTrace();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Assert.fail(e.getMessage());<BR>&nbsp;&nbsp;&nbsp; }<BR>&nbsp; }</FONT></P>
<P><FONT face=Arial size=4>&nbsp; /**<BR>&nbsp;&nbsp; *对象读取（Select）测试<BR>&nbsp;&nbsp; *请保证运行之前数据库中已经存在name='Erica'的记录<BR>&nbsp;&nbsp; */<BR>&nbsp;&nbsp; public void testSelect() {<BR>&nbsp;&nbsp;&nbsp;&nbsp; String hql = " from TUser where name = 'Erica'";<BR>&nbsp;&nbsp;&nbsp;&nbsp; try {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; List userList = session.find(hql);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TUser user = (TUser)userList.get(0);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Asset.assertEquals(user.getName(),"Erica");<BR>&nbsp;&nbsp;&nbsp;&nbsp; }catch(HibernateException e) {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; e.printStackTrace();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Assert.fail(e.getMessage());<BR>&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp; }<BR>}<BR>&nbsp;&nbsp; 同时我们已经成功实现了一个简单的TUser实例的保存和读取。可以看到，程序中通过少量代码实现了Java对象和数据库数据的同步，同时借助Hibernate的有力支持，轻松实现了对象到关系型数据库的映射。<BR>&nbsp;&nbsp; 相对传统的JDBC数据访问模式，这样的实现无疑更符合面向对象的思想，同时也大大提高了开发效率。<BR>&nbsp;&nbsp; 上面的代码中引入了几个Hibernate基础语义：<BR>&nbsp;&nbsp; 1)Configuration<BR>&nbsp;&nbsp; 2)SessionFactory<BR>&nbsp;&nbsp; 3)Session<BR>&nbsp;&nbsp; 下面就这几个关键概念进行探讨。</FONT></P>
<P><FONT face=Arial size=4>Hibernate基础语义<BR>1，Configuration<BR>&nbsp;&nbsp; 正如其名，Configuration类负责管理Hibernate的配置信息。Hibernate运行时需要获取一些底层实现的基本信息，其中关键属性包括：<BR>&nbsp;&nbsp; 1）数据库URL<BR>&nbsp;&nbsp; 2）数据库用户<BR>&nbsp;&nbsp; 3）数据库用户密码<BR>&nbsp;&nbsp; 4）数据库JDBC驱动类<BR>&nbsp;&nbsp; 5）数据库dialect，用于对特定数据库提供支持，其中包括了针对特定数据库特性的实现，如Hibernate数据库类型到特定数据库数据类型的映射等。<BR>&nbsp;&nbsp; 当我们调用：Configuration config = new Configuration().configure();时，Hibernate会自动在当前的CLASSPATH中搜寻hibernate.cfg.xml文件并将其读取到内存中作为后续操作的基本配置。Configuration类一般只有在获取SessionFactory时需要涉及，当获取SessionFactory之后，由于配置信息已经由Hibernate维护并绑定在返回的SessionFactory之上，因此一般情况下无需再对其进行操作。<BR>&nbsp;&nbsp; 我们也可以指定配置文件名，如果不希望使用默认的hibernate.cfg.xml文件作为配置文件的话：<BR>&nbsp;&nbsp; File file = new File("c:samplemyhibernate.xml");<BR>&nbsp;&nbsp; Configuration config = new Configuration().configure(file);</FONT></P>
<P><FONT face=Arial size=4>SessionFactory<BR>&nbsp;&nbsp; SessionFactory负责创建Session实例。我们可以通过Configuration实例构建SessionFactory:<BR>&nbsp;&nbsp; Configuration config = new Configuration().configure();<BR>&nbsp;&nbsp; SessionFactory sessionFactory = config.buildSessionFactory();<BR>&nbsp;&nbsp; Configuration实例config会根据当前的配置信息，构造SessionFactory实例并返回。SessionFactory一旦构造完毕，即被赋予特定的配置信息。也就是说，之后config的任何变更将不会影响到已经创建的SessionFactory实例（sessionFactory）。如果需要使用基于改动后的config实例的sessionFactory，需要从config重新构建一个SessionFactory实例。</FONT></P>
<P><FONT face=Arial size=4>Session<BR>&nbsp;&nbsp; Session是持久层操作的基础，相当于JDBC中的Connection。<BR>&nbsp;&nbsp; Session实例通过SessionFactory实例构建：<BR>&nbsp;&nbsp; Configuration config = new Configuration().configure();<BR>&nbsp;&nbsp; SessionFactory sessionFactory = config.buildSessionFactory();<BR>&nbsp;&nbsp; Session session = sessionFactory.openSession();<BR>&nbsp;&nbsp; 之后我们就可以调用Session所提供的save,find,flush等方法完成持久层操作：<BR>&nbsp;&nbsp; 1）Find:<BR>&nbsp;&nbsp; String hql = " from TUser where name='Erica'";<BR>&nbsp;&nbsp; List userList = session.find(hql);<BR>&nbsp;&nbsp; 2）Save:<BR>&nbsp;&nbsp; TUser user = new TUser();<BR>&nbsp;&nbsp; user.setName("Emma");<BR>&nbsp;&nbsp; session.save(user);<BR>&nbsp;&nbsp; session.flush();<BR>&nbsp;&nbsp; 最后调用Session.flush方法强制数据库同步，这里即强制Hibernate将user实例立即同步到数据库中。如果在事务中则不需要flush方法，在事务提交的时候，hibernate自动会执行flush方法，另外当Session关闭时，也会自动执行flush方法。</FONT></P><img src ="http://www.blogjava.net/xiaomage234/aggbug/5816.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/xiaomage234/" target="_blank">小马歌</a> 2005-06-09 15:33 <a href="http://www.blogjava.net/xiaomage234/articles/5816.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>(转)java.lang.reflect</title><link>http://www.blogjava.net/xiaomage234/articles/5771.html</link><dc:creator>小马歌</dc:creator><author>小马歌</author><pubDate>Wed, 08 Jun 2005 11:19:00 GMT</pubDate><guid>http://www.blogjava.net/xiaomage234/articles/5771.html</guid><wfw:comment>http://www.blogjava.net/xiaomage234/comments/5771.html</wfw:comment><comments>http://www.blogjava.net/xiaomage234/articles/5771.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/xiaomage234/comments/commentRss/5771.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/xiaomage234/services/trackbacks/5771.html</trackback:ping><description><![CDATA[<P><FONT face=Arial size=4>java的反射是很有趣的东西。最近研究了一个这个包。</FONT></P>
<P><FONT face=Arial size=4>发现可以利用反射简化许多重复的代码。</FONT></P>
<P><FONT face=Arial size=4>例如我有一个简单的bean，结构如下：</FONT></P>
<P><FONT face=Arial size=4>class TestBean {</FONT></P>
<P><FONT face=Arial size=4>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; private String userid;</FONT></P>
<P><FONT face=Arial size=4>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; private String password;</FONT></P>
<P><FONT face=Arial size=4>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; private String year;</FONT></P>
<P><FONT face=Arial size=4>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public getXXX();</FONT></P>
<P><FONT face=Arial size=4>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public setXXX();</FONT></P>
<P><FONT face=Arial size=4>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .........</FONT></P>
<P><FONT face=Arial size=4>}</FONT></P>
<P><FONT face=Arial size=4>通常调用者要具体为这个类填充值的时候往往会不厌其烦，怎么有那么多getXXX()和setXXX()要写，其实如果使用反射，这个问题很好解决。</FONT></P>
<P><FONT face=Arial size=4>以通常使用的反射类Method这个类为例子：</FONT></P>
<P><FONT face=Arial size=4>首先我定义一个数组，来存放数据库的表的字段名和类型：</FONT></P>
<P><FONT face=Arial size=4>&nbsp;private final static String[][] fieldNames= {&nbsp; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {"mq_userid","int"},<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {"mq_username","string"},<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {"mq_inbox_name","string"},<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {"mq_outbox_name","string"},<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {"mq_response_name","string"}<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;};</FONT></P>
<P><FONT face=Arial size=4>然后在方法里调用：</FONT></P>
<P><FONT face=Arial size=4>ResultSet rs ;</FONT></P>
<P><FONT face=Arial size=4>&nbsp;&nbsp;if (rs.next()) {<BR>&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp;Method intMethod = ResultSet.class.getMethod("getInt",new Class[]{String.class});<BR>&nbsp;&nbsp;&nbsp;Method strMethod = ResultSet.class.getMethod("getString",new Class[]{String.class});<BR>&nbsp;&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp;//循环用反射方法来取对应字段的值<BR>&nbsp;&nbsp;&nbsp;for (int i=0;i&lt;fieldNames.length;i++) {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (fieldNames[i][1].equals("int")) {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;strValue = (intMethod.invoke(rs,new Object[]{fieldNames[i][0]})).toString();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (fieldNames[i][1].equals("string")) {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;strValue = (String)strMethod.invoke(rs,new Object[]{fieldNames[i][0]});<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp;}</FONT></P>
<P><FONT face=Arial size=4>}</FONT></P><img src ="http://www.blogjava.net/xiaomage234/aggbug/5771.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/xiaomage234/" target="_blank">小马歌</a> 2005-06-08 19:19 <a href="http://www.blogjava.net/xiaomage234/articles/5771.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>(转)Effective Java读书笔记之六</title><link>http://www.blogjava.net/xiaomage234/articles/5757.html</link><dc:creator>小马歌</dc:creator><author>小马歌</author><pubDate>Wed, 08 Jun 2005 09:23:00 GMT</pubDate><guid>http://www.blogjava.net/xiaomage234/articles/5757.html</guid><wfw:comment>http://www.blogjava.net/xiaomage234/comments/5757.html</wfw:comment><comments>http://www.blogjava.net/xiaomage234/articles/5757.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/xiaomage234/comments/commentRss/5757.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/xiaomage234/services/trackbacks/5757.html</trackback:ping><description><![CDATA[<P><FONT size=4>我们接下来讨论一下Java语言的细节，包括局部变量的处理，库的使用，以及两种不是语言本身提供的机制的使用等等一些大家平时可能忽略的问题。</FONT></P>
<P><FONT size=4>Item 29:将局部变量的作用域最小化</FONT></P>
<P><FONT size=4>和C语言要求局部变量必须被生命在代码的开始处相比，Java程序设计语言宽松得多，它允许你在代码的任何位置声明。要想使一个局部变量的作用域最小化，最高小的技术是在第一次需要使用它的地方声明，变量的作用域是从声明它的地方开始到这个声明做在的代码块的结束位止，如果我们把变量的声明和代码的使用位置分开的过大，那么对于读这段代码的人来说，是很不幸的。</FONT></P>
<P><FONT size=4>我们几乎都是在一个局部变量声明的地方同时给它初始化，注意这是很重要的，甚至有时候，如果我们的初始化应该推迟到下一个代码的位置，我们同时应该把声明也往后延迟。这条规则唯一的例外是try-catch这个语句，因为如果一个变量被方法初始化，那么这个方法很有可能抛出一个异常，那我们最常用的方法就是把它置于try块的内部去进行初始化。由此我们可以得出，for循环优于while循环，我们在能使用for循环的地方尽量使用for而不使用while，因为for循环是完全独立的，所以重用循环变量名字不会有任何伤害。</FONT></P>
<P><FONT size=4>最后我们要记住的是尽量把我们的函数写的小而集中，这样才能真正组做到”最小化局部变量的作用域”这一要旨。</FONT></P>
<P><FONT size=4>Item 30：了解和使用库</FONT></P>
<P><FONT size=4>使用标准库，我们可以充分利用编写这些库的Java专家的知识，以及在你之前其他人的使用经验，这就是所谓站在巨人的肩膀上看世界吧~</FONT></P>
<P><FONT size=4>在每一个Java平台的发行版本里面，都会有许多新的包的加入，和这些更新保持一直是值得的，比如说我们J2ME的开发，在MIDP 1.0的时代，我们要写个Game还要自己动手写工具类，现在MIDP2.0推出之后，大多数写游戏的人都觉得方便了很多，因为在这个版本里面加入了游戏包，为我们的开发节省了大量的人力物力。</FONT></P>
<P><FONT size=4>&nbsp;&nbsp;&nbsp;&nbsp; Item 31：如果想要知道精确的答案，就要避免使用double和float</FONT></P>
<P><FONT size=4>&nbsp;&nbsp;&nbsp;&nbsp; 对于金融行业来说，对数据的严整性要求是很高的，不容半点马虎，那大家都知道再我们的Java语言里面有两个浮点数类型的变量float和double，可能大家会认为他们的精度对于金融行业这样对数字敏感的行业来说，已经够用了，但是在开发当中，我们要尽量少使用double和float，因为让他们精确的表达0.1是不可能的。那我们如何解决这个问题呢，答案是使用BigDecimal,int或者long进行货币计算。在这里对大家的忠告是：对于商务运算，我们尽量使用BigDecimal，对于性能要求较高的地方，我们有能力自己处理十进制的小数点，数值不太大的时候，我们可以使用int或者long，根据自己的需要来判定具体使用哪一个，如果范围超过了18位数，那我们必须使用BigDecimal。&nbsp;</FONT></P>
<P><FONT size=4>&nbsp;&nbsp;&nbsp;&nbsp; Item 32：如果其他类型更适合，则尽量避免使用字符串</FONT></P>
<P><FONT size=4>&nbsp;&nbsp;&nbsp;&nbsp; 在偶看到这条建议之前，我就很喜欢用字符串，不管在什么场合下，先String了再说，但是实际上很多情况下，我们要根据实际情况来判定到底使用什么类型，而且字符串不适合替代枚举类型，类型安全枚举类型和int值都比字符串更适合用来表示枚举类型的常量。字符串也不适合替代聚集类型，有一个更好的方法就是简单的写一个类来描述这个数据集，通常是一个私有的静态成员类最好。字符串也不适合代替能力表，总而言之，如果可以适合更加适合的数据类型，或者可以编写更加适当的数据类型，那么应该避免使用字符串来表示对象。&nbsp;</FONT></P>
<P><FONT size=4>Item 33：了解字符串的连接功能</FONT></P>
<P><FONT size=4>我们经常在使用System.out.println()的时候，往括号里写一串用“+”连接起来的字符串，这是我们最常见的，但是这个方法并不适合规模较大的情形，为连接N个字符串而重复地使用字符串连接操作符，要求N的平方级的时间，这是因为字符串是非可变的，这就导致了在字符串进行连接的时候，前后两者都要拷贝，这个时候我们就提倡使用StingBuffer替代String。&nbsp;</FONT></P>
<P><FONT size=4>Item 34：通过接口引用对象</FONT></P>
<P><FONT size=4>通俗的说就是尽量优先使用接口而不是类来引用对象，如果有合适的接口存在那么对使用参数，返回值，变量域都应该使用接口类型养成使用接口作为对象的习惯，会使程序变得更加灵活。</FONT></P>
<P><FONT size=4>如果没有合适的接口，那么，用类而不是接口来引用一个对象，是完全合适的。</FONT></P>
<P><FONT size=4>Item 35：接口优先于映像机制</FONT></P>
<P><FONT size=4>java.lang.relect提供了“通过程序来访问关于已装载的类的信息”，由此，我们可以通过一个给定的Class实例，获得Constructor,Method和Field实例。</FONT></P>
<P><FONT size=4>映像机制允许一个类使用另一个类，即使当前编译的时候后者还不存在，但是这种能力也要付出代价：</FONT></P>
<P><FONT size=4>我们损失了了编译时类型检查的好处，而且要求执行映像访问的代码非常笨拙和冗长，并且在性能上大大损失。</FONT></P>
<P><FONT size=4>通常，普通应用在运行时刻不应以映像方式访问对象。</FONT></P>
<P><FONT size=4>Item 36：谨慎的使用本地方法</FONT></P>
<P><FONT size=4>JNI允许Java应用程序调用本地方法，所谓本地方法是指用本地程序设计语言（如C，C++）来编写的特殊方法，本地方法可以在本地语言执行任何计算任务，然后返回到Java程序设计语言中。但是随着JDK1.3及后续版本的推出这种通过使用本地方法来提高性能的方法已不值得提倡，因为现在的JVM越来越快了，而且使用本地方法有一些严重的缺点，比如使Java原本引以为傲的安全性荡然无存，总之在使用本地方法的时候要三思。</FONT></P>
<P><FONT size=4>Item 37：谨慎使用优化</FONT></P>
<P><FONT size=4>不要因为性能而牺牲合理的代码结构，努力编写好的程序而不是快的程序，但是避免那些限制性能的设计决定，同时考虑自己设计的API决定的性能后果，为了获得更好的性能而对API进行修改这也是一个非常不好的想法，通常我们在做优化之后，都应该对优化的程度进行一些测量。</FONT></P>
<P><FONT size=4>Item 38：遵守普遍接受的命名惯例</FONT></P>
<P><FONT size=4>Java有一套比较完善的命名惯例机制，大部分包含在《The Java Language Specification》，严格得讲这些惯例分成两类，字面的和语法的。</FONT></P>
<P><FONT size=4>字面涉及包，类，接口，方法和域，语法的命名惯例比较灵活，所以争议更大，字面惯例是非常直接和明确的，而语法惯例则相对复杂，也很松散。但是有一个公认的做法是：“如果长期养成的习惯用法与此不同的话，请不要盲目遵从.</FONT></P><img src ="http://www.blogjava.net/xiaomage234/aggbug/5757.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/xiaomage234/" target="_blank">小马歌</a> 2005-06-08 17:23 <a href="http://www.blogjava.net/xiaomage234/articles/5757.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>(转)Effective Java读书笔记之五</title><link>http://www.blogjava.net/xiaomage234/articles/5755.html</link><dc:creator>小马歌</dc:creator><author>小马歌</author><pubDate>Wed, 08 Jun 2005 09:21:00 GMT</pubDate><guid>http://www.blogjava.net/xiaomage234/articles/5755.html</guid><wfw:comment>http://www.blogjava.net/xiaomage234/comments/5755.html</wfw:comment><comments>http://www.blogjava.net/xiaomage234/articles/5755.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/xiaomage234/comments/commentRss/5755.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/xiaomage234/services/trackbacks/5755.html</trackback:ping><description><![CDATA[<P><FONT face=Arial size=4>下面我们来讨论一下有关方法设计的几个方面，下面说的几个要点大多数都是应用在构造函数中，当然也使用于普通方法，我们追求的依然是程序的可用性，健壮性和灵活性。&nbsp;</FONT></P>
<P><FONT face=Arial size=4>Item 23：检查参数的有效性</FONT></P>
<P><FONT face=Arial size=4>非公有的方法我们应该用断言的方法来检查它的参数，而不是使用通常大家所熟悉的检查语句来检测。如果我们使用的开发平台是JDK1.4或者更高级的平台，我们可以使用assert结构；否则我们应该使用一种临时的断言机制。</FONT></P>
<P><FONT face=Arial size=4>有些参数在使用过程中是先保存起来，然后在使用的时候再进行调用，构造函数正是这种类型的一种体现，所以我们通常对构造函数参数的有效性检查是非常仔细的。</FONT></P>
<P><FONT face=Arial size=4>Item 24：需要时使用保护性拷贝</FONT></P>
<P><FONT face=Arial size=4>众所周知，JAVA在代码安全性方面较C/C++有显著的提高，缓冲区溢出，数组越界，非法指针等等，我们的JAVA都有一个很完善的机制来进行免疫，但是这并不代表我们不必去考虑JAVA的安全性，即便在安全的语言，如果不采取措施，还是无法使自己与其他类隔开。假设类的客户会尽一切手段来破坏这个类的约束条件，在这样的前提下，你必须从保护性的方面来考虑设计程序。通过大量的程序代码研究我们得出这样的结论：对于构造性函数的每个可变参数进行保护性拷贝是必要的。需要注意的是，保护性拷贝是在检查参数的有效性之前 进行的，并且有效性检查是针对拷贝之后的对象，而不是原始的对象。对于“参数类型可以被不可信方子类化”的情况，不要用clone方法来进行参数的保护性拷贝。</FONT></P>
<P><FONT face=Arial size=4>对于参数的保护性拷贝并不仅仅在于非可变类，当我们编写一个函数或者一个构造函数的时候，如果它要接受客户提供的对象，允许该对象进入到内部数据结构中，则有必要考虑一下，客户提供的对象是否是可变的，如果是，则要考虑其变化的范围是否在你的程序所能容纳的范围内，如果不是，则要对对象进行保护性拷贝，并且让拷贝之后的对象而不是原始对象进入到数据结构中去。当然最好的解决方法是使用非可变的对象作为你的对象内部足见，这样你就可以不必关心保护性拷贝问题了。）：</FONT></P>
<P><FONT face=Arial size=4>Item 25：谨慎使用设计方法的原型</FONT></P>
<P><FONT face=Arial size=4>（1）谨慎的选择方法的名字：即要注意首先要是易于理解的，其次还要与该包中的其他方法的命名风格相一致，最后当然要注意取一个大众所认可的名字。</FONT></P>
<P><FONT face=Arial size=4>（2）不要追求提供便利的方法：每一个方法都应该提供其应具备的功能点，对于接口和类来方法不要过多，否则会对学习使用维护等等方面带来许多不必要的麻烦，对于每一个类型所支持的每一个动作，都提供一个功能完全的方法，只有一个方法过于频繁的使用时，才考虑为它提供一个快捷方法。</FONT></P>
<P><FONT face=Arial size=4>（3）避免过长的参数列表：通常在实践中，我们以三个参数作为最大值，参数越少越好，类型相同的长参数列尤其影响客户的使用，两个方法可以避免过长的参数这样的情况发生，一是把一个方法分解成多个，每一个方法只要求使用这些参数的一个子集；二是创建辅助类，用来保存参数的聚集，这些辅助类的状态通常是静态的。</FONT></P>
<P><FONT face=Arial size=4>对于参数类型，优先使用接口而不是类。</FONT></P>
<P><FONT face=Arial size=4>这样做的目的是避免影响效能的拷贝操作。</FONT></P>
<P><FONT face=Arial size=4>谨慎的使用函数对象。</FONT></P>
<P><FONT face=Arial size=4>创建函数对象最容易的方法莫过于使用匿名类，但是那样会带来语法上混乱，并且与内联的控制结构相比，这样也会导致功能上的局限性。&nbsp;</FONT></P>
<P><FONT face=Arial size=4>Item 26：谨慎的使用重载</FONT></P>
<P><FONT face=Arial size=4>到底是什么造成了重载机制的混淆算法，这是个争论的话题，一个安全而保守的方法是，永远不要导出两个具有相同参数数目的重载方法。而对于构造函数来说，一个类的多个构造函数总是重载的，在某些情况下，我们可以选择静态工厂，但是对于构造函数来说这样做并不总是切合实际的。</FONT></P>
<P><FONT face=Arial size=4>当涉及到构造函数时，遵循这条建议也许是不可能的，但我们应该极力避免下面的情形：</FONT></P>
<P><FONT face=Arial size=4>同一组参数只需要经过类型的转换就可以传递给不同的重载方法。如果这样做也不能避免的话，我们至少要保证一点：当传递同样的参数时，所有的重载方法行为一致。如果不能做到这一点，程序员就不能有效的使用方法或者构造函数。&nbsp;</FONT></P>
<P><FONT face=Arial size=4>Item 27：返回零长度的数组而不是null</FONT></P>
<P><FONT face=Arial size=4>因为这样做的原因是编写客户程序的程序员可能忘记写这种专门的代码来处理null返回值。没有理由从一个取数组值的方法中返回null，而不是返回一个零长度数组。</FONT></P>
<P><FONT face=Arial size=4>Item 28：为所有导出的API元素编写文档注释</FONT></P>
<P><FONT face=Arial size=4>不爱写注释可能是大多数程序员新手的通病（包括偶哈~），但是如果想要一个API真正可用，就必须写一个文档来说明它，保持代码和文档的同步是一件比较烦琐的事情，JAVA语言环境提供了javadoc工具，从而使这个烦琐的过程变得容易，这个工具可以根据源代码自动产生API文档。</FONT></P>
<P><FONT face=Arial size=4>为了正确得编写API文档，我们必须每一个被导出的类，接口，构造函数，方法和域声明之前加一个文档注释。</FONT></P>
<P><FONT face=Arial size=4>每一个方法的文档注释应该见解的描述它和客户之间的约定。<BR></FONT></P><img src ="http://www.blogjava.net/xiaomage234/aggbug/5755.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/xiaomage234/" target="_blank">小马歌</a> 2005-06-08 17:21 <a href="http://www.blogjava.net/xiaomage234/articles/5755.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>(转)Effective Java读书笔记之四</title><link>http://www.blogjava.net/xiaomage234/articles/5754.html</link><dc:creator>小马歌</dc:creator><author>小马歌</author><pubDate>Wed, 08 Jun 2005 09:17:00 GMT</pubDate><guid>http://www.blogjava.net/xiaomage234/articles/5754.html</guid><wfw:comment>http://www.blogjava.net/xiaomage234/comments/5754.html</wfw:comment><comments>http://www.blogjava.net/xiaomage234/articles/5754.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/xiaomage234/comments/commentRss/5754.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/xiaomage234/services/trackbacks/5754.html</trackback:ping><description><![CDATA[<TABLE class=main_tdbg_575 style="WORD-BREAK: break-all" cellSpacing=0 cellPadding=0 width="100%" align=center border=0>
<TBODY>
<TR align=middle bgColor=#eeeeee>
<TD colSpan=2 height=24><FONT face=Arial color=#000000 size=4><STRONG>作者：夏彦端 </STRONG></FONT></TD></TR>
<TR>
<TD background=http://www.j2medev.com/Skin/adv43/ad_bx1.gif colSpan=2 height=6><FONT face=Arial color=#000000 size=4><STRONG></STRONG></FONT></TD></TR>
<TR>
<TD colSpan=2><FONT face=Arial color=#000000 size=4><STRONG></STRONG></FONT></TD></TR>
<TR>
<TD id=fontzoom style="WORD-BREAK: break-all" vAlign=top colSpan=2 height=600>
<P><FONT color=#000000 size=4>看了mingjava在网站上的前三篇文章，觉得这本书确实值得大家认真的读，后来跟mingjava说想接着他的写，于是就有了这接下来的文章，希望不是狗尾续貂，写得不好，大家多多给我提意见，我会努力去改进的。</FONT></P>
<P><FONT color=#000000 size=4>&nbsp;&nbsp;&nbsp;&nbsp; 由于以前学过C语言，所以对C还是蛮有感情，而JAVA和C又有很多相似之处，很多从C转过来学习JAVA的兄弟，可能一开始都不是很适应，因为很多在C里面的结构在JAVA里面都不能使用了，所以下面我们来介绍一下C语言结构的替代。</FONT></P>
<P><FONT color=#000000 size=4>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Item 19:用类代替结构</FONT></P>
<P><FONT color=#000000 size=4>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; JAVA刚面世的时候，很多C程序员都认为用类来代替结构现在太复杂，代价太大了，但是实际上，如果一个JAVA的类退化到只包含一个数据域的话，这样的类与C语言的结构大致是等价的。</FONT></P>
<P><FONT color=#000000 size=4>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 比方说下面两个程序片段：</FONT></P>
<P><FONT color=#000000 size=4>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; class Point</FONT></P>
<P><FONT color=#000000 size=4>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</FONT></P>
<P><FONT color=#000000 size=4>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; private float x;</FONT></P>
<P><FONT color=#000000 size=4>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; private float y;</FONT></P>
<P><FONT color=#000000 size=4>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</FONT></P>
<P><FONT color=#000000 size=4>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 实际上这段代码和C语言的结构基本上没什么区别，但是这段代码恐怕是众多OO设计Fans所不齿的，因为它没有体现封装的优异性，没有体现面向对象设计的优点，当一个域被修改的时候，你不可能再采取任何辅助的措施了，那我们再来看一看采用包含私有域和共有访问方法的OO设计代码段：</FONT></P>
<P><FONT color=#000000 size=4>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; class Point</FONT></P>
<P><FONT color=#000000 size=4>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; private float x;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; private float y;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public Point(float x,float y)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.x=x;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.y=y;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public float getX(){retrun x;}</FONT></P>
<P><FONT color=#000000 size=4>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public float getY(){return y;}</FONT></P>
<P><FONT color=#000000 size=4>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public void setX(float x){this.x=x;}</FONT></P>
<P><FONT color=#000000 size=4>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public void setY(float y){this.y=y;}</FONT></P>
<P><FONT color=#000000 size=4>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</FONT></P>
<P><FONT color=#000000 size=4>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 单从表面上看，这段代码比上面那个多了很多行，还多了很多函数，但是仔细想一下，这样的OO设计，似乎更人性化，我们可以方面的对值域进行提取，修改等操作，而不直接和值域发生关系，这样的代码不仅让人容易读懂，而且很安全，还吸取了面向对象程序设计的灵活性，试想一下，如果一个共有类暴露它的值域，那么想要在将来的版本中进行修改是impossible的，因为共有类的客户代码已经遍布各处了。</FONT></P>
<P><FONT color=#000000 size=4>需要提醒一点的是，如果一个类是包级私有的，或者是一个私有的嵌套类，则直接暴露其值域并无不妥之处。</FONT></P>
<P><FONT color=#000000 size=4>&nbsp;</FONT></P>
<P><FONT color=#000000 size=4>Item 20：用类层次来代替联合</FONT></P>
<P><FONT color=#000000 size=4>我们在用C语言来进行开发的时候，经常会用到联合这个概念，比如：</FONT></P>
<P><FONT color=#000000 size=4>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; typedef struct{</FONT></P>
<P><FONT color=#000000 size=4>&nbsp;&nbsp;&nbsp;&nbsp; double length;</FONT></P>
<P><FONT color=#000000 size=4>&nbsp;&nbsp;&nbsp;&nbsp; double width;&nbsp;&nbsp;&nbsp;&nbsp; </FONT></P>
<P><FONT color=#000000 size=4>}rectangleDimensions_t;</FONT></P>
<P><FONT color=#000000 size=4>那我们在JAVA里面没有联合这个概念，那我们用什么呢？对！用继承，这也是JAVA最吸引我的地方之一，它可以使用更好的机制来定义耽搁数据类型，在Bruce Eckel的Thinking in java里面也多次提到了一个和形状有关的例子，我们可以先笼统的定义一个抽象类，即我们通常所指的超类，每个操作定义一个抽象的方法，其行为取决于标签的值，如果还有其他的操作不依赖于标签的值，则把操作变成根类（继承的类）中的具体方法。</FONT></P>
<P><FONT color=#000000 size=4>这样做的最重要的优点是：类层次提供了类型的安全性。</FONT></P>
<P><FONT color=#000000 size=4>其次代码非常明了，这也是OO设计的优点。</FONT></P>
<P><FONT color=#000000 size=4>而且它很容易扩展，即使是面向多个方面的工作，能够同样胜任。</FONT></P>
<P><FONT color=#000000 size=4>最后它可以反映这些类型之间本质上的层次关系，从而允许更强的灵活性，以便编译时类型检查。<BR>&nbsp;</FONT></P>
<P><FONT color=#000000 size=4>Item 21：用类来代替enum结构</FONT></P>
<P><FONT color=#000000 size=4>Java程序设计语言提出了类型安全枚举的模式来替代enum结构，它的基本思想很简单：定义一个类来代表枚举类型的单个元素，并且不提供任何公有的构造函数，相反，提供公有静态final类，使枚举类型中的每一个常量都对应一个域。</FONT></P>
<P><FONT color=#000000 size=4>类型安全枚举类型的一个缺点是，装载枚举类的和构造常量对象时，需要一定的时间和空间开销，除非是在资源很受限制的设备比如蜂窝电哈和烤面包机上，否则在实际中这个问题不会被考虑。</FONT></P>
<P><FONT color=#000000 size=4>&nbsp;总之，类型安全枚举类型明显优于int类型，除非实在一个枚举类型主要被用做一个集合元素，或者主要用在一个资源非常不受限的环境下，否则类型安全枚举类型的缺点都不成问题，依次，在要求使用一个枚举类型的环境下，我们首先应考虑类型安全枚举类型模式。</FONT></P>
<P><FONT color=#000000 size=4>&nbsp;</FONT></P>
<P><FONT color=#000000 size=4>Item 22：用类和接口来代替函数指针</FONT></P>
<P><FONT color=#000000 size=4>众所周知，JAVA语言和C的最大区别在于，前者去掉了指针，小生第一次接触JAVA的时候觉得好不习惯，因为突然一下子没了指针，觉得好不方面啊，C语言的精髓在于其指针的运用，而JAVA却把它砍掉了，让人好生郁闷，不过随着时间的推移，我渐渐明白了用类和接口的应用也同样可以提供同样的功能，我们可以直接定义一个这样一个类，他的方法是执行其他方法上的操作，如果一个类仅仅是导出这样一个方法，那么它实际上就是一个指向该方法的指针，举个例子：</FONT></P>
<P><FONT color=#000000 size=4>&nbsp;class StringLengthComprator{</FONT></P>
<P><FONT color=#000000 size=4>public int compare(String s1,String s2)</FONT></P>
<P><FONT color=#000000 size=4>{</FONT></P>
<P><FONT color=#000000 size=4>return s1.length()-s2.length();</FONT></P>
<P><FONT color=#000000 size=4>}</FONT></P>
<P><FONT color=#000000 size=4>}</FONT></P>
<P><FONT color=#000000 size=4>这个类导出一个带两个字符串的方法，它是一个用于字符串比较的具体策略。它是无状态的，没有域，所以，这个类的所有实例在功能上都是等价的，可以节省不必要的对象创建开销。但是我们不好直接把这个类传递给可户使用，因为可户无法传递任何其他的比较策略。相反，我们可以定义一个接口，即我们在设计具体策略类的时候还需要定义一个策略接口：</FONT></P>
<P><FONT color=#000000 size=4>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public interface Comparator{</FONT></P>
<P><FONT color=#000000 size=4>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public int compare(Object o1,Object o2);</FONT></P>
<P><FONT color=#000000 size=4>}</FONT></P>
<P><FONT color=#000000 size=4>&nbsp; 我们完全可以依照自己的需要来定义它。</FONT></P>
<P><FONT color=#000000 size=4>具体的策略类往往使用匿名类声明。</FONT></P>
<P><FONT color=#000000 size=4>在JAVA中，我们为了实现指针的模式，声明一个接口来表示该策略，并且为每个具体策略声明一个实现了该接口的类，如果一个具体策略只被使用一次的话，那么通常使用匿名类来声明和实例化这个具体策略类，如果一个策略类反复使用，那么它的类通常是一个私有的的静态成员类。<BR></FONT></P></TD></TR></TBODY></TABLE><img src ="http://www.blogjava.net/xiaomage234/aggbug/5754.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/xiaomage234/" target="_blank">小马歌</a> 2005-06-08 17:17 <a href="http://www.blogjava.net/xiaomage234/articles/5754.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>(转)Effective Java读书笔记之三</title><link>http://www.blogjava.net/xiaomage234/articles/5753.html</link><dc:creator>小马歌</dc:creator><author>小马歌</author><pubDate>Wed, 08 Jun 2005 09:16:00 GMT</pubDate><guid>http://www.blogjava.net/xiaomage234/articles/5753.html</guid><wfw:comment>http://www.blogjava.net/xiaomage234/comments/5753.html</wfw:comment><comments>http://www.blogjava.net/xiaomage234/articles/5753.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/xiaomage234/comments/commentRss/5753.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/xiaomage234/services/trackbacks/5753.html</trackback:ping><description><![CDATA[<FONT face=Arial size=4>越来越发现这是一本难得的好书，Java程序员不看这本书的话真是很遗憾。本章讲述的是类和接口相关的问题。这几个Item都非常重要. </FONT>
<P><STRONG><FONT face=Arial size=4>Item 12：把类和成员的可访问范围降到最低</FONT></STRONG></P>
<P><FONT face=Arial size=4>&nbsp;&nbsp;&nbsp;&nbsp;好的模块设计应该尽最大可能封装好自己的内部信息，这样可以把模块之间的耦合程度降到最低。开发得以并行，无疑这将加快开发的速度，便于系统地维护。Java中通过访问控制符来解决这个问题。</FONT></P>
<OL>
<LI><FONT face=Arial size=4>public表示这个类在任何范围都可用。 </FONT>
<LI><FONT face=Arial size=4>protected表示只有子类和包内的类可以使用 </FONT>
<LI><FONT face=Arial size=4>private-package(default)表示在包内可用 </FONT>
<LI><FONT face=Arial size=4>private表示只有类内才可以用</FONT></LI></OL>
<P><FONT face=Arial size=4>你在设计一个类的时候应该尽量的按照4321得顺序设计。如果一个类只是被另一个类使用，那么应该考虑把它设计成这个类的内部类。通常public的类不应该有public得字段，不过我们通常会用一个类来定义所有的常量，这是允许的。不过必须保证这些字段要么是基本数据类型要么引用指向的对象是不可修改的。不然他们将可能被修改。例如下面的定义中data就是不合理的，后面两个没有问题。<BR>public class Con<BR>{<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;public static final int[] data = {1,2,3};// it is bad<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;public static final String hello = "world";<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;public static final int i = 1;<BR>}</FONT></P>
<P><STRONG><FONT face=Arial size=4>Item 13:不可修改的类更受青睐</FONT></STRONG></P>
<P><FONT face=Arial size=4>&nbsp;&nbsp;&nbsp;&nbsp;不可修改的类意思是他们一经创建就不会改变，例如String类。他们的设计、实现都很方便，安全性高——它们是线程安全的。设计不可修改类有几点规则：</FONT></P>
<OL>
<LI><FONT face=Arial size=4>不要提供任何可以修改对象的方法 </FONT>
<LI><FONT face=Arial size=4>确保没有方法能够被覆盖，可以通过把它声明为final </FONT>
<LI><FONT face=Arial size=4>所有字段设计成final </FONT>
<LI><FONT face=Arial size=4>所有字段设计成private </FONT>
<LI><FONT face=Arial size=4>确保外部不能访问到类的可修改的组件<BR>不可修改类也有个缺点就是创建不同值得类的时候要创建不同的对象，String就是这样的。通常有个解决的办法就是提供一个帮助类来弥补，例如StringBuffer类。</FONT></LI></OL>
<P><STRONG><FONT face=Arial size=4>Item 14:化合(合成）比继承更值得考虑</FONT></STRONG></P>
<P><FONT face=Arial size=4>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;实现代码重用最重要的办法就是继承，但是继承破坏了封装，导致软件的键壮性不足。如果子类继承了父类，那么它从父类继承的方法就依赖父类的实现，一旦他改变了会导致不可预测的结果。作者介绍了InstrumentedHashSet作为反例进行说明，原因就是没有明白父类的方法实现。作者给出的解决办法是通过化合来代替继承，用包装类和转发方法来解决问题。把想扩展的类作为本类的一个private final得成员变量。把方法参数传递给这个成员变量并得到返回值。这样做的缺点是这样的类不适合回掉框架。继承虽然好，我们却不应该滥用，只有我们能确定它们之间是is-a得关系的时候才使用。</FONT></P>
<P><STRONG><FONT face=Arial size=4>Item 15:如果要用继承那么设计以及文档都要有质量保证，否则就不要用它</FONT></STRONG></P>
<P><FONT face=Arial size=4>&nbsp;&nbsp;&nbsp;&nbsp;为了避免继承带来的问题，你必须提供精确的文档来说明覆盖相关方法可能出现的问题。在构造器内千万不要调用可以被覆盖的方法，因为子类覆盖方法的时候会出现问题。<BR>import java.util.*;</FONT></P>
<P><FONT face=Arial size=4>public class SubClass extends SuperClass<BR>{<BR>&nbsp;private final Date date;<BR>&nbsp;<BR>&nbsp;public SubClass()<BR>&nbsp;{<BR>&nbsp;&nbsp;date = new Date();&nbsp;<BR>&nbsp;}<BR>&nbsp;<BR>&nbsp;public void m()<BR>&nbsp;{<BR>&nbsp;&nbsp;System.out.println(date);&nbsp;<BR>&nbsp;}<BR>&nbsp;<BR>&nbsp;public static void main(String[] args)<BR>&nbsp;{<BR>&nbsp;&nbsp;SubClass s = new SubClass();<BR>&nbsp;&nbsp;s.m();&nbsp;<BR>&nbsp;}<BR>&nbsp;<BR>}</FONT></P>
<P><FONT face=Arial size=4>class SuperClass<BR>{<BR>&nbsp;public SuperClass()<BR>&nbsp;{<BR>&nbsp;&nbsp;m();&nbsp;<BR>&nbsp;}&nbsp;<BR>&nbsp;<BR>&nbsp;public void m()<BR>&nbsp;{<BR>&nbsp;&nbsp;<BR>&nbsp;}<BR>}<BR>由于在date被初始化之前super（）已经被调用了，所以第一次输出null而不是当前的时间。<BR>由于在Clone()或者序列化的时候非常类似构造器的功能，因此readObject()和clone（）方法内最好也不要包括能被覆盖的方法。</FONT></P>
<P><STRONG><FONT face=Arial size=4>Item 16:在接口和抽象类之间优先选择前者</FONT></STRONG></P>
<P><FONT face=Arial size=4>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;接口和抽象类都用来实现多态，不过我们应该优先考虑用接口。知道吗？James说过如果要让他重新设计java的话他会把所有都设计成接口的。抽象类的优点是方便扩展，因为它是被继承的，并且方法可以在抽象类内实现，接口则不行。</FONT></P>
<P><STRONG><FONT face=Arial size=4>Item 17：接口只应该用来定义类型</FONT></STRONG></P>
<P><FONT face=Arial size=4>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;接口可以这样用的 Collection c = new xxxx();这是我们最常用的。不要把接口用来做其他的事情，比如常量的定义。你应该定义一个类，里面包含public final static 得字段。</FONT></P>
<P><STRONG><FONT face=Arial size=4>Item 18: 在静态和非静态内部类之间选择前者</FONT></STRONG></P>
<P><FONT face=Arial size=4>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;如果一个类被定义在其他的类内部那么它就是嵌套类，可以分为静态内部类、非静态内部类和匿名类。<BR>&nbsp;&nbsp;&nbsp;static member class 得目的是为enclosing class服务，如果还有其他的目的，就应该把它设计成top-level class。nonstatic member class是和enclosing class instance关联的，如果不需要访问enclosing class instance的话应该把它设计成static得，不然会浪费时间和空间。anonymous class是声明和初始化同时进行的。可以放在代码的任意位置。典型应用是Listener 和process object例如Thread。</FONT></P><img src ="http://www.blogjava.net/xiaomage234/aggbug/5753.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/xiaomage234/" target="_blank">小马歌</a> 2005-06-08 17:16 <a href="http://www.blogjava.net/xiaomage234/articles/5753.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>(转)Effective Java读书笔记之二</title><link>http://www.blogjava.net/xiaomage234/articles/5752.html</link><dc:creator>小马歌</dc:creator><author>小马歌</author><pubDate>Wed, 08 Jun 2005 09:15:00 GMT</pubDate><guid>http://www.blogjava.net/xiaomage234/articles/5752.html</guid><wfw:comment>http://www.blogjava.net/xiaomage234/comments/5752.html</wfw:comment><comments>http://www.blogjava.net/xiaomage234/articles/5752.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/xiaomage234/comments/commentRss/5752.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/xiaomage234/services/trackbacks/5752.html</trackback:ping><description><![CDATA[<DIV class=postText>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN><STRONG><FONT face=Arial size=4>Methods Common to All Objects</FONT></STRONG></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN><?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /><o:p><FONT face=Arial size=4>&nbsp;</FONT></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><STRONG><FONT size=4><FONT face=Arial><SPAN lang=EN>item 7:</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">当你覆盖</SPAN><SPAN lang=EN>equals</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">方法的时候一定要遵守</SPAN><SPAN lang=EN>general contact</SPAN></FONT></FONT></STRONG></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><STRONG><SPAN lang=EN><FONT face=Arial size=4></FONT></SPAN></STRONG>&nbsp;</P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><FONT size=4><FONT face=Arial><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">&nbsp;&nbsp;&nbsp;覆盖</SPAN><SPAN lang=EN>equals</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">的时候一定要加倍的小心，其实最好的办法就是不覆盖这个方法。比如在下面的情况下就可以不覆盖</SPAN></FONT></FONT></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><FONT size=4><FONT face=Arial><SPAN lang=EN>&nbsp;&nbsp;&nbsp;1</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">这个类的每个实例都是唯一的，例如</SPAN><SPAN lang=EN>Thread</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">类</SPAN></FONT></FONT></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><FONT size=4><FONT face=Arial><SPAN lang=EN>&nbsp;&nbsp;&nbsp;2 </SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">如果你不关心这个类是否该提供一个测试逻辑相等的方法</SPAN></FONT></FONT></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><FONT size=4><FONT face=Arial><SPAN lang=EN>&nbsp;&nbsp;&nbsp;3</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">超类已经覆盖了</SPAN><SPAN lang=EN>equals</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">方法，并且它合适子类使用</SPAN></FONT></FONT></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><FONT size=4><FONT face=Arial><SPAN lang=EN>&nbsp;&nbsp;&nbsp;4</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">如果这个类是</SPAN><SPAN lang=EN>private</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">或者是</SPAN><SPAN lang=EN>package-private</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">的，并且你确信他不会被调用</SPAN></FONT></FONT></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'"><FONT face=Arial size=4></FONT></SPAN>&nbsp;</P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><FONT size=4><FONT face=Arial><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">&nbsp;&nbsp;&nbsp;但是当我们要为这个类提供区分逻辑相等和引用相等的方法的时候，我们就必须要覆盖这个方法了。例如</SPAN><SPAN lang=EN>String</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">类，</SPAN><SPAN lang=EN>Date</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">类等，覆盖的时候我们一定要遵从</SPAN><SPAN lang=EN>general contact</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">，说白了就是一个合同。合同的主要内容是</SPAN></FONT></FONT></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><FONT size=4><FONT face=Arial><SPAN lang=EN>&nbsp;&nbsp;&nbsp;1</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">．</SPAN><SPAN lang=EN>x.equals(x)</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">必须返回</SPAN><SPAN lang=EN>true</SPAN></FONT></FONT></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><FONT size=4><FONT face=Arial><SPAN lang=EN>&nbsp;&nbsp;&nbsp;2</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">．</SPAN><SPAN lang=EN>x.equals</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">（</SPAN><SPAN lang=EN>y</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">）当且仅当</SPAN><SPAN lang=EN>y.equals(x)</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">返回</SPAN><SPAN lang=EN>true</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">的时候返回</SPAN><SPAN lang=EN>true</SPAN></FONT></FONT></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><FONT size=4><FONT face=Arial><SPAN lang=EN>&nbsp;&nbsp;&nbsp;3</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">．</SPAN><SPAN lang=EN>x.equals(y)</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">返回</SPAN><SPAN lang=EN>true</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">，</SPAN><SPAN lang=EN>y.equals(z)</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">返回</SPAN><SPAN lang=EN>true,</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">那么</SPAN><SPAN lang=EN>x.equals(z)</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">必须返回</SPAN><SPAN lang=EN>true</SPAN></FONT></FONT></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><FONT size=4><FONT face=Arial><SPAN lang=EN>&nbsp;&nbsp;&nbsp;4.</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">如果没有任何修改得话</SPAN> <SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">那么多次调用</SPAN><SPAN lang=EN>x.equals(y)</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">的返回值应该不变</SPAN></FONT></FONT></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><FONT size=4><FONT face=Arial><SPAN lang=EN>&nbsp;&nbsp;&nbsp;5</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">．任何时候非空的对象</SPAN><SPAN lang=EN>x,x.equals(null)</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">必须返回</SPAN><SPAN lang=EN>false</SPAN></FONT></FONT></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><FONT size=4><FONT face=Arial><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">下面是作者的建议如何正确的覆盖</SPAN><SPAN lang=EN>equals</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">方法</SPAN></FONT></FONT></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt 18pt; TEXT-INDENT: -18pt; mso-list: l0 level1 lfo1; tab-stops: list 18.0pt"><FONT size=4><FONT face=Arial><SPAN lang=EN style="mso-fareast-font-family: 'Times New Roman'"><SPAN style="mso-list: Ignore">1．<SPAN style="FONT: 7pt 'Times New Roman'">&nbsp; </SPAN></SPAN></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">用</SPAN><SPAN lang=EN>==</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">检查是否参数就是这个对象的引用</SPAN></FONT></FONT></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt 18pt; TEXT-INDENT: -18pt; mso-list: l0 level1 lfo1; tab-stops: list 18.0pt"><FONT size=4><FONT face=Arial><SPAN lang=EN style="mso-fareast-font-family: 'Times New Roman'"><SPAN style="mso-list: Ignore">2．<SPAN style="FONT: 7pt 'Times New Roman'">&nbsp; </SPAN></SPAN></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">用</SPAN><SPAN lang=EN>instanceof</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">判断参数的类型是否正确</SPAN></FONT></FONT></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt 18pt; TEXT-INDENT: -18pt; mso-list: l0 level1 lfo1; tab-stops: list 18.0pt"><FONT size=4><FONT face=Arial><SPAN lang=EN style="mso-fareast-font-family: 'Times New Roman'"><SPAN style="mso-list: Ignore">3．<SPAN style="FONT: 7pt 'Times New Roman'">&nbsp; </SPAN></SPAN></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">把参数转换成合适的类型</SPAN></FONT></FONT></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt 18pt; TEXT-INDENT: -18pt; mso-list: l0 level1 lfo1; tab-stops: list 18.0pt"><FONT size=4><FONT face=Arial><SPAN lang=EN style="mso-fareast-font-family: 'Times New Roman'"><SPAN style="mso-list: Ignore">4．<SPAN style="FONT: 7pt 'Times New Roman'">&nbsp; </SPAN></SPAN></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">比较类的字段是不是匹配</SPAN></FONT></FONT></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'"><FONT face=Arial size=4>例如：</FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN><FONT face=Arial size=4>public boolean equals(Object o)</FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN><FONT face=Arial size=4>{</FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN><FONT size=4><FONT face=Arial><SPAN style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>if(o== this) return true;</FONT></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN><FONT size=4><FONT face=Arial><SPAN style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>if(!(o instanceof xxxx) return false;</FONT></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN><FONT size=4><FONT face=Arial><SPAN style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>xxx in = (xxx)o;</FONT></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN><FONT size=4><FONT face=Arial><SPAN style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>return ……..</FONT></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN><FONT face=Arial size=4>}</FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><FONT size=4><FONT face=Arial><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">最后一点要注意的时候不要提供这样的方法</SPAN><SPAN lang=EN>public boolean equals(MyClass o)</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">这样是重载并不是覆盖</SPAN><SPAN lang=EN>Object</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">的</SPAN><SPAN lang=EN>equals</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">方法</SPAN></FONT></FONT></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><STRONG><FONT size=4><FONT face=Arial><SPAN lang=EN>item 8 :</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">当你覆盖</SPAN><SPAN lang=EN>equals</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">的时候必须覆盖</SPAN><SPAN lang=EN>hashCode</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">方法</SPAN></FONT></FONT></STRONG></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><FONT size=4><FONT face=Arial><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">&nbsp;&nbsp;&nbsp; 这点必须切忌，不然在你和</SPAN><SPAN lang=EN>hash-based</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">集合打交道的时候，错误就会出现了。关键问题在于一定要满足相等的对象必须要有相等的</SPAN><SPAN lang=EN>hashCode</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">。如果你在</SPAN><SPAN lang=EN>PhoneNumber</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">类中覆盖了</SPAN><SPAN lang=EN>equals</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">方法，但是没有覆盖</SPAN><SPAN lang=EN>hashCode</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">方法，那么当你做如下操作的时候就会出现问题了。</SPAN></FONT></FONT></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN><FONT face=Arial size=4>Map m = new HashMap();</FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><FONT size=4><FONT face=Arial><SPAN lang=EN>m.put(new PhoneNumber(408,863,3334),”ming”)<BR></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">当你调用</SPAN><SPAN lang=EN>m.get(new PhoneNumber(408,863,3334))</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">的时候你希望得到</SPAN><SPAN lang=EN>ming</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">但是你却得到了</SPAN><SPAN lang=EN>null,</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">为什么呢因为在整个过程中有两个</SPAN><SPAN lang=EN>PhoneNumber</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">的实例，一个是</SPAN><SPAN lang=EN>put</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">一个是</SPAN><SPAN lang=EN>get</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">，但是他们两个逻辑相等的实例却得到不同的</SPAN><SPAN lang=EN>hashCode</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">那么怎么可以取得以前存入的</SPAN><SPAN lang=EN>ming</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">呢。</SPAN></FONT></FONT></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'"><FONT face=Arial size=4></FONT></SPAN>&nbsp;</P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><STRONG><FONT size=4><FONT face=Arial><SPAN lang=EN>Item 9:</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">永远覆盖</SPAN><SPAN lang=EN>toString</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">方法</SPAN></FONT></FONT></STRONG></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><FONT size=4><FONT face=Arial><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">&nbsp;&nbsp;&nbsp; 在</SPAN><SPAN lang=EN>Object</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">的</SPAN><SPAN lang=EN>toString</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">方法返回的形式是</SPAN><SPAN lang=EN>Class</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">的类型加上</SPAN><SPAN lang=EN>@</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">加上</SPAN><SPAN lang=EN>16</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">进制的</SPAN><SPAN lang=EN>hashcode</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">。你最好在自己的类中提供</SPAN><SPAN lang=EN>toString</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">方法更好的表述实例的信息，不然别人怎么看得明白呢。</SPAN></FONT></FONT></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'"><FONT face=Arial size=4></FONT></SPAN>&nbsp;</P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><STRONG><FONT size=4><FONT face=Arial><SPAN lang=EN>Item 10:</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">覆盖</SPAN><SPAN lang=EN>clone()</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">方法的时候一定要小心</SPAN></FONT></FONT></STRONG></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><FONT size=4><FONT face=Arial><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">&nbsp;&nbsp;&nbsp; 一个对象要想被</SPAN><SPAN lang=EN>Clone</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">，那么要实现</SPAN><SPAN lang=EN>Clone()</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">接口，这个接口没有定义任何的方法，但是如果你不实现这个接口的话，调用</SPAN><SPAN lang=EN>clone</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">方法的时候会出现</SPAN><SPAN lang=EN>CloneNotSupportedException</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">，这就是作者叫做</SPAN><SPAN lang=EN>mixin</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">的接口类型。通常</SPAN><SPAN lang=EN>clone()</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">方法可以这样覆盖</SPAN></FONT></FONT></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN><FONT face=Arial size=4>public Object clone()</FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN><FONT face=Arial size=4>{</FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt 21pt"><SPAN lang=EN><FONT face=Arial size=4>try<BR>{</FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN><FONT size=4><FONT face=Arial><SPAN style="mso-tab-count: 2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>return super.clone();</FONT></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt"><SPAN lang=EN><FONT face=Arial size=4>}</FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt 21pt"><SPAN lang=EN><FONT face=Arial size=4>catch(CloneNotSupportedException e)<BR>{}</FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN><FONT face=Arial size=4>}</FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><FONT size=4><FONT face=Arial><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">但是当你要</SPAN><SPAN lang=EN>clone</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">的类里面含有可修改的引用字段的时候，那么你一定要把整个类的蓝图进行复制，如果对你</SPAN><SPAN lang=EN>clone</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">得到的对象进行修改的时候还会影响到原来的实例，那么这是不可取的。所以应该这样</SPAN><SPAN lang=EN>clone()</SPAN></FONT></FONT></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN><FONT face=Arial size=4>public Object clone() throws CloneNotSupportedException</FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN><FONT face=Arial size=4>{</FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN><FONT size=4><FONT face=Arial><SPAN style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>Stack Result<SPAN style="mso-spacerun: yes">&nbsp; </SPAN>= (Stack)super.clone();</FONT></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN><FONT size=4><FONT face=Arial><SPAN style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>Result.elements = (Object[])elements.clone();</FONT></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN><FONT size=4><FONT face=Arial><SPAN style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>Return result;</FONT></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN><FONT face=Arial size=4>}</FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><FONT size=4><FONT face=Arial><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">其中</SPAN><SPAN lang=EN>elements</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">是</SPAN><SPAN lang=EN>stack</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">类中可修改的引用字段，注意如果</SPAN><SPAN lang=EN>elements</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">是</SPAN><SPAN lang=EN>final</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">的话我们就无能为力了，因为不能给他重新赋值了</SPAN><SPAN lang=EN>.</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">其实如果不是必须的话，根本就不用它最好。</SPAN></FONT></FONT></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'"><FONT face=Arial size=4></FONT></SPAN>&nbsp;</P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><STRONG><FONT size=4><FONT face=Arial><SPAN lang=EN>Item 11:</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">考虑适当的时候覆盖</SPAN><SPAN lang=EN>Comparable</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">接口</SPAN></FONT></FONT></STRONG></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><FONT size=4><FONT face=Arial><SPAN lang=EN><SPAN style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN>Thinking in java</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">上说的更清楚，这里不多少了。</SPAN><SPAN lang=EN><o:p></o:p></SPAN></FONT></FONT></P></DIV><img src ="http://www.blogjava.net/xiaomage234/aggbug/5752.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/xiaomage234/" target="_blank">小马歌</a> 2005-06-08 17:15 <a href="http://www.blogjava.net/xiaomage234/articles/5752.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>(转)Effective Java读书笔记之一</title><link>http://www.blogjava.net/xiaomage234/articles/5751.html</link><dc:creator>小马歌</dc:creator><author>小马歌</author><pubDate>Wed, 08 Jun 2005 09:13:00 GMT</pubDate><guid>http://www.blogjava.net/xiaomage234/articles/5751.html</guid><wfw:comment>http://www.blogjava.net/xiaomage234/comments/5751.html</wfw:comment><comments>http://www.blogjava.net/xiaomage234/articles/5751.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/xiaomage234/comments/commentRss/5751.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/xiaomage234/services/trackbacks/5751.html</trackback:ping><description><![CDATA[<P>
<TABLE class=main_tdbg_575 style="WORD-BREAK: break-all" cellSpacing=0 cellPadding=0 width="100%" align=center border=0>
<TBODY>
<TR align=middle bgColor=#eeeeee>
<TD colSpan=2 height=24><FONT face=Arial size=4>作者：mingjava </FONT></TD></TR>
<TR>
<TD background=http://www.j2medev.com/Skin/adv43/ad_bx1.gif colSpan=2 height=6><FONT face=Arial size=4></FONT></TD></TR>
<TR>
<TD colSpan=2><FONT face=Arial size=4></FONT></TD></TR>
<TR>
<TD id=fontzoom style="WORD-BREAK: break-all" vAlign=top colSpan=2 height=600><FONT face=Arial size=4>&nbsp;&nbsp;&nbsp;&nbsp;终于翻开这本James都称赞的java经典书籍了，发现比一般的英语书籍要难懂一些。但是里面的Item都是非常实用的，是java程序员应该理解的。 </FONT>
<P><STRONG><FONT face=Arial size=4>Creating and Destroying Object</FONT></STRONG></P>
<P><FONT face=Arial><FONT size=4><STRONG>Item 1:考虑用静态工厂方法替代构造器</STRONG><BR>例如：public static Boolean valueOf(boolean b)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return (b?Boolean.TRUE:Boolean.FALSE);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<BR>这样的好处是方法有名字，并且它可以复用对象，不像构造器每次调用都产生新的对象。其次它还可以返回返回类型的子类。不好的地方是如果没有public or protected构造器的类将不能被继承。还有就是静态工厂方法的名字和其他的静态方法名字不容易区分。</FONT></FONT></P>
<P><FONT face=Arial><FONT size=4><STRONG>Item 2:通过添加私有构造器来加强单例属性（singletom property)</STRONG><BR>例如：public class Hello<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;private static final Hello Instance = new Hell();</FONT></FONT></P>
<P><FONT face=Arial size=4>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;private Hello()<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{}<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;public static Hello getInstance()<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return Instance;</FONT></P>
<P><FONT face=Arial size=4>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<BR>这个私有构造器只能在内部被使用，确保了单例模式！<BR><STRONG>Item 3:避免创建重复的对象</STRONG><BR>对不可修改的对象尽量进行复用，这样效率和性能都会提高。例如如果循环100次String s = new String("hello")将创建100个对象 循环100次String s = "hello";则只创建了一个对象。很好的进行了复用。</FONT></P>
<P><STRONG><FONT face=Arial size=4>Item 4:用私有构造器来避免被实例化</FONT></STRONG></P>
<P><FONT face=Arial size=4>例如public UtilityClass<BR>{<BR>&nbsp;&nbsp;&nbsp;private UtilityClass()<BR>&nbsp;&nbsp; {}</FONT></P>
<P><FONT face=Arial size=4>///<BR>}<BR>通常那些工具类是这么设计的</FONT></P>
<P><STRONG><FONT face=Arial size=4>Item 5:消除绝对的对象引用</FONT></STRONG></P>
<P><FONT face=Arial size=4>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;虽然java中使用gc来管理内存，但是如果不注意的话也会产生“内存泄漏”。例如下面的程序<BR>public class Stack<BR>{<BR>&nbsp;private Object[] elements;<BR>&nbsp;private int size = 0;<BR>&nbsp;<BR>&nbsp;public Stack(int i)<BR>&nbsp;{<BR>&nbsp;&nbsp;this.elements = new Object[i];&nbsp;<BR>&nbsp;}&nbsp;<BR>&nbsp;<BR>&nbsp;public void push(Object e)<BR>&nbsp;{<BR>&nbsp;&nbsp;ensure();<BR>&nbsp;&nbsp;elements[size++] = e;&nbsp;<BR>&nbsp;}<BR>&nbsp;<BR>&nbsp;public Object pop()<BR>&nbsp;{<BR>&nbsp;&nbsp;if(size == 0)<BR>&nbsp;&nbsp;{<BR>&nbsp;&nbsp;&nbsp;////&nbsp;<BR>&nbsp;&nbsp;}&nbsp;<BR>&nbsp;&nbsp;<BR>&nbsp;&nbsp;return elements[size--];<BR>&nbsp;}<BR>&nbsp;<BR>&nbsp;private void ensure()<BR>&nbsp;{<BR>&nbsp;&nbsp;////&nbsp;<BR>&nbsp;}<BR>}<BR>标记的地方存在着内存泄漏的问题，因为当他被弹出栈的时候，它也没有成为可回收的垃圾对象，Stack维护着他们的绝对的引用。将不能更改。改进的方法是如下的写法<BR>&nbsp;public Object pop()<BR>&nbsp;{<BR>&nbsp;&nbsp;if(size == 0)<BR>&nbsp;&nbsp;{<BR>&nbsp;&nbsp;&nbsp;////&nbsp;<BR>&nbsp;&nbsp;}&nbsp;<BR>&nbsp;&nbsp;Object obj = elements[--size];<BR>&nbsp;&nbsp;elements[size] = null;<BR>&nbsp;&nbsp;<BR>&nbsp;&nbsp;return obj;<BR>&nbsp;}<BR>&nbsp;但是切忌不要滥用null。</FONT></P>
<P><FONT face=Arial><FONT size=4><STRONG>Item 6:避免finalizer</STRONG><BR>垃圾回收器是低线程级别运行的且不能被强迫执行。System.gc()只是建议垃圾回收器收集垃圾，它可不一定马上运行，而且垃圾回收器运行的时候会挂起其他线程导致程序停止响应。推荐使用的方法类似于<BR>InputStream is = null;</FONT></FONT></P>
<P><FONT face=Arial size=4>try<BR>{<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;is = /////;<BR>}<BR>finally<BR>{<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;is.close();<BR>}</FONT></P></TD></TR></TBODY></TABLE></P><img src ="http://www.blogjava.net/xiaomage234/aggbug/5751.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/xiaomage234/" target="_blank">小马歌</a> 2005-06-08 17:13 <a href="http://www.blogjava.net/xiaomage234/articles/5751.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>