Java基础知识小结


Java基础知识小结 作者: nything http://nything.javaeye.com getPath()、getAbsolutePath()、getCanonicalPath()的区别<br> file的getPath getAbsolutePath和getCanonicalPath的不同 <br> int String 互转的多种方法<br> JAVA注释方法及格式 <br> JAVA注释具体实现 <br> http://www.javaeye.com - 做最棒的软件开发交流社区 第 1 / 42 页 Java 6中的性能优化 <br> java 参数的应用 -verbose <br> Java关闭窗体的六种方法 <br> jdk1.6环境变量设置 <br> Java集合框架使用总结 <br> 抽象类与接口的区别 <br> http://nything.javaeye.com 第 2 / 42 页 目 录 1. Java基础 1.1 getPath()、getAbsolutePath()、getCanonicalPath()的区别 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4 1.2 file的getPath getAbsolutePath和getCanonicalPath的不同 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5 1.3 int String 互转的多种方法 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10 1.4 JAVA注释方法及格式 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11 1.5 JAVA注释具体实现 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13 1.6 Java 6中的性能优化 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18 1.7 java 参数的应用 -verbose . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20 1.8 Java关闭窗体的六种方法 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21 1.9 jdk1.6环境变量设置 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25 1.10 Java集合框架使用总结 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26 1.11 抽象类与接口的区别 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29 1.12 面向对象设计61点经验原则 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37 http://nything.javaeye.com 第 3 / 42 页 1.1 getPath()、getAbsolutePath()、getCanonicalPath()的区别 发表时间: 2009-06-19 getPath() 将此抽象路径名转换为一个路径名字符串。所得字符串使用默认名称分隔符分隔名称序列中的名称。 getAbsolutePath() 返回此抽象路径名的绝对路径名字符串。 如果此抽象路径名已经是绝对路径名,则返回该路径名字符串,这与 getPath() 方法一样。如果此抽象路径名是空抽象路径名,则返回当前用户目录的路径名字符串,该目录由系统属性 user.dir 指定。否则,使用与系统有关的方式解析此路径名。在 UNIX 系统上,根据当前用户目录解析相对路径名,可使该路径名成为绝对路径名。在 Microsoft Windows 系统上,根据路径名指定的当前驱动器目录(如果有)解析相对路径名,可使该路径名成为绝对路径名;否则,可以根据当前用户目录解析它。 getCanonicalPath(): 返回此抽象路径名的规范路径名字符串。 规范路径名是绝对路径名,并且是惟一的。规范路径名的准确定义与系统有关。如有必要,此方法首先将路径名转换为绝对路径名,这与调用 getAbsolutePath() 方法的效果一样,然后用与系统相关的方式将它映射到其惟一路径名。这通常涉及到从路径名中移除多余的名称(比如 "." 和 "..")、解析符号连接(对于 UNIX 平台),以及将驱动器号转换为标准大小写形式(对于 Microsoft Windows 平台)。 每个表示现存文件或目录的路径名都有一个惟一的规范形式。每个表示不存在文件或目录的路径名也有一个惟一的规范形式。不存在文件或目录路径名的规范形式可能不同于创建文件或目录之后同一路径名的规范形式。同样,现存文件或目录路径名的规范形式可能不同于删除文件或目录之后同一路径名的规范形式。 http://nything.javaeye.com 1.1 getPath()、getAbsolutePath()、getCanonicalPath()的区别 第 4 / 42 页 1.2 file的getPath getAbsolutePath和getCanonicalPath的不同 发表时间: 2009-06-19 概念上的区别:(内容来自jdk,个人感觉这个描述信息,只能让明白的人明白,不明白的人看起来还是有点难 度(特别试中文版,英文版稍好些)所以在概念之后我会举例说明。如果感觉看概念很累就跳过直接看例子吧。 看完例子回来看概念会好些。 getPath public String getPath()将此抽象路径名转换为一个路径名字符串。所得到的字符串使用默认名称分隔符来分隔名称序列中的 名称。 返回: 此抽象路径名的字符串形式 getAbsolutePath public String getAbsolutePath()返回抽象路径名的绝对路径名字符串。 如果此抽象路径名已经是绝对路径名,则返回该路径名字符串,这与 getPath() 方法一样。如果此抽象路径名是空的抽象路径 名,则返回当前用户目录的路径名字符串,该目录由系统属性 user.dir 指定。否则,使用与系统有关的方式分析此路径名。在 UNIX 系统上,通过根据当前用户目录分析某一相对路径名,可使该路径名成为绝对路径名。在 Microsoft Windows 系统 上,通过由路径名指定的当前驱动器目录(如果有)来分析某一相对路径名,可使该路径名成为绝对路径名;否则,可以根据 当前用户目录来分析它。 返回: 绝对路径名字符串,它与此抽象路径名表示相同的文件或目录的 抛出: SecurityException - 如果无法访问所需的系统属性值。 另请参见: isAbsolute() http://nything.javaeye.com 1.2 file的getPath getAbsolutePath和getCanonicalPath的不同 第 5 / 42 页 getCanonicalPath public String getCanonicalPath() throws IOException返回抽象路径名的规范路径名字符串。 规范路径名是绝对路径名,并且是惟一的。规范路径名的准确定义与系统有关。如有必要,此方法首先将路径名转换成绝对路 径名,这与调用 getAbsolutePath() 方法的效果一样,然后用与系统相关的方式将它映射到其惟一路径名。这通常涉及到从路 径名中移除多余的名称(比如 "." 和 "..")、分析符号连接(对于 UNIX 平台),以及将驱动器名转换成标准大小写形式(对 于 Microsoft Windows 平台)。 表示现有文件或目录的每个路径名都有一个惟一的规范形式。表示非存在文件或目录的每个路径名也有一个惟一的规范形式。 非存在文件或目录路径名的规范形式可能不同于创建文件或目录之后同一路径名的规范形式。同样,现有文件或目录路径名的 规范形式可能不同于删除文件或目录之后同一路径名的规范形式。 返回: 表示与此抽象路径名相同的文件或目录的规范路径名字符串 抛出: IOException - 如果发生 I/O 错误(可能是因为构造规范路径名需要进行文件系统查询) SecurityException - 如果无法访问所需的系统属性值,或者存在安全管理器,且其 SecurityManager.checkRead(java.io.FileDescriptor) 方法拒绝对该文件进行读取访问 从以下版本开始: JDK1.1 二、例子: 1,getPath()与getAbsolutePath()的区别 public static void test1(){ File file1 = new File(".\\test1.txt"); File file2 = new File("D:\\workspace\\test\\test1.txt"); System.out.println("-----默认相对路径:取得路径不同------"); System.out.println(file1.getPath()); System.out.println(file1.getAbsolutePath()); System.out.println("-----默认绝对路径:取得路径相同------"); System.out.println(file2.getPath()); System.out.println(file2.getAbsolutePath()); } http://nything.javaeye.com 1.2 file的getPath getAbsolutePath和getCanonicalPath的不同 第 6 / 42 页 得到的结果: -----默认相对路径:取得路径不同------ .\test1.txt D:\workspace\test\.\test1.txt -----默认绝对路径:取得路径相同------ D:\workspace\test\test1.txt D:\workspace\test\test1.txt 因为getPath()得到的是构造file的时候的路径。 getAbsolutePath()得到的是全路径 如果构造的时候就是全路径那直接返回全路径 如果构造的时候试相对路径,返回当前目录的路径+构造file时候的路径 2,getAbsolutePath()和getCanonicalPath()的不同 public static void test2() throws Exception{ File file = new File("..\\src\\test1.txt"); System.out.println(file.getAbsolutePath()); System.out.println(file.getCanonicalPath()); } 得到的结果 D:\workspace\test\..\src\test1.txt D:\workspace\src\test1.txt 可以看到CanonicalPath不但是全路径,而且把..或者.这样的符号解析出来。 3,getCanonicalPath()和自己的不同。 就是解释这段话: 表示现有文件或目录的每个路径名都有一个惟一的规范形式。表示非存在文件或目录的每个路径名也有一个惟一的规范形式。 非存在文件或目录路径名的规范形式可能不同于创建文件或目录之后同一路径名的规范形式。同样,现有文件或目录路径名的 规范形式可能不同于删除文件或目录之后同一路径名的规范形式。 单下边这段代码是看不到结果的,要配合一定的操作来看。下边操作步骤,同时讲解 http://nything.javaeye.com 1.2 file的getPath getAbsolutePath和getCanonicalPath的不同 第 7 / 42 页 public static void test3() throws Exception{ File file = new File("D:\\Text.txt"); System.out.println(file.getCanonicalPath()); } 步骤: 确定你的系统是Windows系统。 (1),确定D盘下没有Text.txt这个文件,直接执行这段代码,得到的结果是: D:\Text.txt 注意这里试大写的Text.txt (2)在D盘下建立一个文件,名叫text.txt,再次执行代码,得到结果 D:\text.txt 同样的代码得到不同的结果。 同时可以对比getAbsolutePath()看看,这个得到的结果是一样的。 原因: window是大小写不敏感的,也就是说在windows上test.txt和Test.txt是一个文件,所以在windows上当文件不 存在时,得到的路径就是按照输入的路径。但当文件存在时,就会按照实际的情况来显示。这也就是建立文件 后和删除文件后会有不同的原因。文件夹和文件类似。 三、最后: 1,尝试在linux下执行上边的步骤,两次打印的结果是相同的,因为linux是大小写敏感的系统。 2,手动删掉test.txt,然后尝试执行下边代码 public static void test4() throws Exception{ File file = new File("D:\\Text.txt"); System.out.println(file.getCanonicalPath()); File file1 = new File("D:\\text.txt"); file1.createNewFile(); file = new File("D:\\Text.txt"); System.out.println(file.getCanonicalPath()); } http://nything.javaeye.com 1.2 file的getPath getAbsolutePath和getCanonicalPath的不同 第 8 / 42 页 public static void test3() throws Exception{ File file1 = new File("D:\\text.txt"); file1.createNewFile(); File file = new File("D:\\Text.txt"); System.out.println(file.getCanonicalPath()); } 执行上边两个函数,看看结果,然后思考一下为什么? 1,的结果是两个大写, 2,的结果试两个小写 连续两个大写的,是否跟上边的矛盾 ? 这是因为虚拟机的缓存机制造成的。第一次File file = new File("D:\\Text.txt");决定了结果. http://nything.javaeye.com 1.2 file的getPath getAbsolutePath和getCanonicalPath的不同 第 9 / 42 页 1.3 int String 互转的多种方法 发表时间: 2009-06-25 1 如何将字串 String 转换成整数 int? A. 有两个方法: 1). int i = Integer.parseInt([String]); 或 i = Integer.parseInt([String],[int radix]); 2). int i = Integer.valueOf(my_str).intValue(); 注: 字串转成 Double, Float, Long 的方法大同小异. 2 如何将整数 int 转换成字串 String ? A. 有叁种方法: 1.) String s = String.valueOf(i); 2.) String s = Integer.toString(i); 3.) String s = "" + i; 注: Double, Float, Long 转成字串的方法大同小异. http://nything.javaeye.com 1.3 int String 互转的多种方法 第 10 / 42 页 1.4 JAVA注释方法及格式 发表时间: 2009-06-28 关键字: 单行注释 文档注释 javadoc注释 1、单行(single-line)--短注释://…… 单独行注释:在代码中单起一行注释, 注释前最好有一行空行,并与其后的代码具有一样的缩进层级。如果单行无法完成,则应采用块注释。 注释格式:/* 注释内容 */ 行头注释:在代码行的开头进行注释。主要为了使该行代码失去意义。 注释格式:// 注释内容 行尾注释:尾端(trailing)--极短的注释,在代码行的行尾进行注释。一般与代码行后空8(至少4)个格,所有注释必须对齐。 注释格式:代码 + 8(至少4)个空格 + // 注释内容 2、块(block)--块注释:/*……*/ 注释若干行,通常用于提供文件、方法、数据结构等的意义与用途的说明,或者算法的描述。一般位于一个文件或者一个方法的前面,起到引导的作用,也可以根据需要放在合适的位置。这种域注释不会出现在HTML报告中。注释格式通常写成: /* * 注释内容 */ 3、文档注释:/**……*/ 注释若干行,并写入javadoc文档。每个文档注释都会被置于注释定界符 /**......*/之中,注释文档将用来生成HTML格式的代码报告,所以注释文 档必须书写在类、域、构造函数、方法,以及字段(field)定义之前。注释文档由两部分组成——描述、块标记。注释文档的格式如下: /** * The doGet method of the servlet. * This method is called when a form has its tag value method * equals to get. * @param request * the request send by the client to the server * @param response * the response send by the server to the client * @throws ServletException * if an error occurred * @throws IOException * if an error occurred */ http://nything.javaeye.com 1.4 JAVA注释方法及格式 第 11 / 42 页 public void doGet (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doPost(request, response); } 前两行为描述,描述完毕后,由@符号起头为块标记注释。更多有关文档注 释和javadoc的详细资料,参见javadoc的主页: http://java.sun.com/javadoc/index.html 4、javadoc注释标签语法 @author 对类的说明 标明开发该类模块的作者 @version 对类的说明 标明该类模块的版本 @see 对类、属性、方法的说明 参考转向,也就是相关主题 @param 对方法的说明 对方法中某参数的说明 @return 对方法的说明 对方法返回值的说明 @exception 对方法的说明 对方法可能抛出的异常进行说明 http://nything.javaeye.com 1.4 JAVA注释方法及格式 第 12 / 42 页 1.5 JAVA注释具体实现 发表时间: 2009-06-28 关键字: java注释 注释规范 文档注释 类注释 1、源文件注释 源文件注释采用 /** …… */,在每个源文件的头部要有必要的注释信息,包括:文件名;文件编号;版本号;作 者;创建时间;文件描述包括本文件历史修改记录等。中文注释模版: /** * 文 件 名 : * CopyRright (c) 2008-xxxx: * 文件编号: * 创 建 人: * 日 期: * 修 改 人: * 日 期: * 描 述: * 版 本 号: */ 2、类(模块)注释: 类(模块)注释采用 /** …… */,在每个类(模块)的头部要有必要的注释信息,包括:工程名;类(模块)编 号;命名空间;类可以运行的JDK版本;版本号;作者;创建时间;类(模块)功能描述(如功能、主要算法、 内部各部分之间的关系、该类与其类的关系等,必要时还要有一些如特别的软硬件要求等说明);主要函数或 过程清单及本类(模块)历史修改记录等。 英文注释模版: /** * CopyRright (c)2008-xxxx: <展望软件Forsoft > * Project: <项目工程名 > * Module ID: <(模块)类编号,可以引用系统设计中的类编号> * Comments: <对此类的描述,可以引用系统设计中的描述> * JDK version used: http://nything.javaeye.com 1.5 JAVA注释具体实现 第 13 / 42 页 * Namespace: <命名空间> * Author: <作者中文名或拼音缩写> * Create Date: <创建日期,格式:YYYY-MM-DD> * Modified By: <修改人中文名或拼音缩写> * Modified Date: <修改日期,格式:YYYY-MM-DD> * Why & What is modified <修改原因描述> * Version: <版本号> */ 如果模块只进行部分少量代码的修改时,则每次修改须添加以下注释: //Rewriter //Rewrite Date:<修改日期:格式YYYY-MM-DD> Start1: /* 原代码内容*/ //End1: 将原代码内容注释掉,然后添加新代码使用以下注释: //Added by //Add date:<添加日期,格式:YYYY-MM-DD> Start2: //End2: 如果模块输入输出参数或功能结构有较大修改,则每次修改必须添加以下 注释: //Log ID: //Depiction:<对此修改的描述> //Writer:修改者中文名 //Rewrite Date:<模块修改日期,格式:YYYY-MM-DD> 3、接口注释: 接口注释采用 /** …… */,在满足类注释的基础之上,接口注释应该包含描述接口的目的、它应如何被使用以及 如何不被使用,块标记部分必须注明作者和版本。在接口注释清楚的前提下对应的实现类可以不加注释。 http://nything.javaeye.com 1.5 JAVA注释具体实现 第 14 / 42 页 4、构造函数注释: 构造函数注释采用 /** …… */,描述部分注明构造函数的作用,不一定有块标记部分。 注释模版一: /** * 默认构造函数 */ 注释模版二: /** * Description : 带参数构造函数, * 初始化模式名,名称和数据源类型 * @param schema: 模式名 * @param name: 名称 * @param type: 数据源类型 */ 5、函数注释: 函数注释采用 /** ……*/,在每个函数或者过程的前面要有必要的注释信息,包括:函数或过程名称;功能描 述;输入、输出及返回值说明;调用关系及被调用关系说明等。函数注释里面可以不出现版本号 (@version)。 注释模版一: /** * 函 数 名 : * 功能描述: * 输入参数: <按照参数定义顺序> * <@param后面空格后跟着参数的变量名字 * (不是类型),空格后跟着对该参数的描述。> * * 返 回 值: - 类型 <说明> * <返回为空(void)的构造函数或者函数, * @return可以省略; 如果返回值就是输入参数,必须 * 用与输入参数的@param相同的描述信息; 必要的时* 候注明特殊条件写的返回值。> http://nything.javaeye.com 1.5 JAVA注释具体实现 第 15 / 42 页 * 异 常:<按照异常名字的字母顺序> * 创 建 人: * 日 期: * 修 改 人: * 日 期: */ 注释模版二: /** * FunName: getFirstSpell * Description : 获取汉字拼音首字母的字符串, * 被生成百家姓函数调用 * @param: str the String是包含汉字的字符串 * @return String:汉字返回拼音首字母字符串; * 英文字母返回对应的大写字母; * 其他非简体汉字返回 '0'; * @Author: ghc * @Create Date: 2008-07-02 */ 6、方法注释: 方法注释采用 /** …… */,对于设置 (Set 方法 ) 与获取 (Get 方法 ) 成员的方法,在成员变量已有说明的情况 下,可以不加注释;普通成员方法要求说明完成什么功能,参数含义是什么且返回值什么;另外方法的创建时 间必须注释清楚,为将来的维护和阅读提供宝贵线索。 7、方法内部注释: 控制结构,代码做了些什么以及为什么这样做,处理顺序等,特别是复杂的逻辑处理部分,要尽可能的给出详 细的注释。 http://nything.javaeye.com 1.5 JAVA注释具体实现 第 16 / 42 页 8、 全局变量注释: 要有较详细的注释,包括对其功能、取值范围、哪些函数或者过程存取以及存取时注意事项等的说明。 9、局部(中间)变量注释: 主要变量必须有注释,无特别意义的情况下可以不加注释。 10、实参/参数注释: 参数含义、及其它任何约束或前提条件。 11、字段/属性注释: 字段描述,属性说明。 12、常量:常量通常具有一定的实际意义,要定义相应说明。 http://nything.javaeye.com 1.5 JAVA注释具体实现 第 17 / 42 页 1.6 Java 6中的性能优化 发表时间: 2009-06-29 J2SE 6(代号:Mustang野马)主要设计原则之一就是提升J2SE的性能和扩展能力,主要通过最大程度提升运行 效率,更好的垃圾收集和一些客户端性能来达到。 1、偏向锁(Biased locking) Java 6以前加锁操作都会导致一次原子CAS(Compare-And-Set)操作,CAS操作是比较耗时的,即使这个锁 上实际上没有冲突,只被一个线程拥有,也会带来较大开销。为解决这一问题,Java 6中引入偏向锁技术,即一 个锁偏向于第一个加锁的线程,该线程后续加锁操作不需要同步。大概的实现如下:一个锁最初为NEUTRAL状 态,当第一个线程加锁时,将该锁的状态修改为BIASED,并记录线程ID,当这一线程进行后续加锁操作时,若 发现状态是BIASED并且线程ID是当前线程ID,则只设置一下加锁标志,不需要进行CAS操作。其它线程若要加 这个锁,需要使用CAS操作将状态替换为REVOKE,并等待加锁标志清零,以后该锁的状态就变成 DEFAULT, 常用旧的算法处理。这一功能可用-XX:-UseBiasedLocking命令禁止。 2、锁粗化(Lock coarsening) 如果一段代码经常性的加锁和解锁,在解锁与下次加锁之间又没干什么事情,则可以将多次加加锁解锁操作合 并成一对。这一功能可用-XX:-EliminateLocks禁止。 3、自适应自旋(Adaptive spinning) 一般在多CPU的机器上加锁实现都会包含一个短期的自旋过程。自旋的次数不太好决定,自旋少了会导致线程 被挂起和上下文切换增加,自旋多了耗CPU。为此Java 6中引入自适应自旋技术,即根据一个锁最近自旋加锁 成功概率动态调整自旋次数。 4、常用大内存分布的堆(large page heap) 在大内分页是x86/amd64架构上用来减小TLB(虚拟地址到物理地址翻译缓存)大小的TLB失配率。Java 6中的 内存堆可以使用这一技术。 5、提高数组拷贝性能 对每种类型大小写一个定制的汇编数组拷贝程序。 6、后台进行代码优化 Background Compilation in HotSpot™ Client Compiler: 后台进行代码优化 7、线性扫描寄存器分配算法(Linear Scan Register Allocation): 一种新的寄存器分配策略,基于SSA(static single assignment),性能提高10%左右。常用的寄存器分配算 法将寄存器分配看作图着色问题,时间复杂度是O(n^4),不适用于Java的JIT编译。原来的JVM里是根据一些本 http://nything.javaeye.com 1.6 Java 6中的性能优化 第 18 / 42 页 地启发式规则来分配寄存器,效果不太好,Java 6中使用的线性扫描寄存器算法能够达到与图颜色算法相似的效 果,并且时间复杂度是线性的。 8、并行缩并垃圾收集器(Parallel Compaction Collector) 进行Full GC时使用并行垃圾收集(JDK 5里原来非Full GC是并行的但Full GC是串行的),使用- XX:+UseParallelOldGC开启这一功能 9、并行低停顿垃圾收集器(Concurrent Low Pause Collector) 显式调用gc(如System.gc)时也可以并行进行标记-清扫式垃圾收集,使用- XX:+ExplicitGCInvokesConcurrent开启。 10、Ergonomics in the 6.0 Java Virtual Machine 自动调整垃圾收集策略、堆大小等配置,这一功能在JDK 5中加入,JDK 6中得到显著增强,SPECjbb2005性能 提高70%。 11、boot类装载器的优化 jre中增加一个描述package所在jar文件的元索引文件,加快classloader加载类性能,提高桌面Java应用启动速 度(+15%)。内存占用也减少了10% 12、图形程序优化 在jvm启动之前显示splash。 Swing程序中每个窗口有一个后台显示缓存,当该窗口原来被遮挡,现在要显示时直接从该缓存拷贝数据进行渲 染,即使该窗口的绘制线程被阻塞也可以完成这一渲染. http://java.sun.com/performance/reference/whitepapers/6_performance.html http://nything.javaeye.com 1.6 Java 6中的性能优化 第 19 / 42 页 1.7 java 参数的应用 -verbose 发表时间: 2009-06-29 java -verbose[:class|gc|jni] -verbose 显示所有加载的jar包的信息 -verbose:gc 显示垃圾回收的信息 http://nything.javaeye.com 1.7 java 参数的应用 -verbose 第 20 / 42 页 1.8 Java关闭窗体的六种方法 发表时间: 2009-06-29 1.使用JFrame的enableEvents和processWindowEvent //Frame1.java import java.awt.*; import java.awt.event.*; import javax.swing.*; public class Frame1 extends JFrame { public Frame1() { enableEvents(AWTEvent.WINDOW_EVENT_MASK); this.setSize(new Dimension(400, 300)); this.setTitle("Frame1"); } protected void processWindowEvent(WindowEvent e) { super.processWindowEvent(e); if (e.getID() == WindowEvent.WINDOW_CLOSING) { System.exit(0); } } } 2.直接实现WindowListener接口 //Frame1.java import java.awt.*; import java.awt.event.*; public class Frame1 extends Frame implements WindowListener { public Frame1() { this.setSize(new Dimension(400, 300)); this.setTitle("Frame1"); this.addWindowListener(this); } public void windowClosing(WindowEvent windowEvent) { System.exit(0); } public void windowOpened(WindowEvent windowEvent) { } public void windowClosed(WindowEvent windowEvent) { } public void windowIconified(WindowEvent windowEvent) { } http://nything.javaeye.com 1.8 Java关闭窗体的六种方法 第 21 / 42 页 public void windowDeiconified(WindowEvent windowEvent) { } public void windowActivated(WindowEvent windowEvent) { } public void windowDeactivated(WindowEvent windowEvent) { } } 3.直接继承窗体适配器WindowAdapter //Frame1.java import java.awt.*; import java.awt.event.*; public class Frame1 extends WindowAdapter { public Frame1() { Frame f=new Frame(); f.setSize(new Dimension(400, 300)); f.setTitle("Frame1"); f.addWindowListener(this); f.setVisible(true); } public static void main(String[] s){ new Frame1(); } public void windowClosing(WindowEvent windowEvent) { System.exit(0); } } 4.间接继承窗体适配器WindowAdapter //Frame1.java import java.awt.*; import java.awt.event.*; public class Frame1 extends Frame { public Frame1() { this.setSize(new Dimension(400, 300)); this.setTitle("Frame1"); this.addWindowListener(new winAdapter()); this.setVisible(true); } public static void main(String[] s){ new Frame1(); } http://nything.javaeye.com 1.8 Java关闭窗体的六种方法 第 22 / 42 页 } class winAdapter extends WindowAdapter{ public void windowClosing(WindowEvent windowEvent) { System.exit(0); } } 5.间接实现WindowListener接口 //Frame1.java import java.awt.*; import java.awt.event.*; public class Frame1 extends Frame { public Frame1() { this.setSize(new Dimension(400, 300)); this.setTitle("Frame1"); this.addWindowListener(new winEventHandle()); this.setVisible(true); } public static void main(String[] s){ new Frame1(); } } class winEventHandle implements WindowListener { public void windowClosing(WindowEvent windowEvent) { System.exit(0); } public void windowOpened(WindowEvent windowEvent) { } public void windowClosed(WindowEvent windowEvent) { } public void windowIconified(WindowEvent windowEvent) { } public void windowDeiconified(WindowEvent windowEvent) { } public void windowActivated(WindowEvent windowEvent) { } public void windowDeactivated(WindowEvent windowEvent) { } } 6.使用Inner Class //Frame1.java import java.awt.*; import java.awt.event.*; public class Frame1{ http://nything.javaeye.com 1.8 Java关闭窗体的六种方法 第 23 / 42 页 public Frame1(){ Frame f=new Frame(); f.addWindowListener(new WindowAdapter(){ public void windowClosing(WindowEvent e){ System.exit(0); } }); f.setSize(new Dimension(400, 300)); f.setVisible(true); } public static void main(String[] s){ new Frame1(); } } Jframe的关闭方法: setDefaultCloseOperation(EXIT_ON_CLOSE); frame的关闭方法如下: this.addWindowListener(new java.awt.event.WindowAdapter() { public void windowClosing(java.awt.event.WindowEvent e) { System.exit(0); } }); 本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/wjq3714/archive/2009/06/20/4284280.aspx http://nything.javaeye.com 1.8 Java关闭窗体的六种方法 第 24 / 42 页 1.9 jdk1.6环境变量设置 发表时间: 2009-07-01 关键字: jdk1.6 环境变量 安装完jdk6_update14.exe后,打开控制台,输入“java”,会正确显示;但是输入“javac”显示不正确,原 来是安装jdk时jre会将java.exe拷贝到C:\WINDOWS\system32目录下,但是javac.exe属于jdk里,所以不会被 拷贝! 其实不用管这些,安装完毕,直接按照以下配置即可: 1、配置JAVA安装路径 JAVA_HOME D:\develop\java\jdk6u14 2、配置path变量,控制台输入某个命令会先在path变量里制定的路径依次查找并运行,如java、javac命令 PATH %JAVA_HOME%\bin 3、设置Classpath的目的就是让Java执行环境找到指定的Java程序(也就是.class文件)。“.”代表当前路径。 CLASSPATH .;%JAVA_HOME%\lib 另外安装java时,jdk目录与jre目录最好分开,防止两者的lib目录覆盖 http://nything.javaeye.com 1.9 jdk1.6环境变量设置 第 25 / 42 页 1.10 Java集合框架使用总结 发表时间: 2009-07-08 前言: 本文是对Java集合框架做了一个概括性的解说,目的是对Java集合框架体系有个总体认识,如果你想学习具体 的接口和类的使用方法,请参看Java API文档。 一、概述 数据结构对程序设计有着深远的影响,在面向过程的C语言中,数据库结构用struct来描述,而在面向对象的编 程中,数据结构是用类来描述的,并且包含有对该数据结构操作的方法。 在Java语言中,Java语言的设计者对常用的数据结构和算法做了一些规范(接口)和实现(具体实现接口的 类)。所有抽象出来的数据结构和操作(算法)统称为Java集合框架(Java Collection Framework)。 Java程序员在具体应用时,不必考虑数据结构和算法实现细节,只需要用这些类创建出来一些对象,然后直接 应用就可以了。这样就大大提高了编程效率。 二、集合框架的层次结构 Collection是集合接口 |————Set子接口:无序,不允许重复。 |————List子接口:有序,可以有重复元素。 区别:Collections是集合类 Set和List对比: Set:检索元素效率低下,删除和插入效率高,插入和删除不会引起元素位置改变。 List:和数组类似,List可以动态增长,查找元素效率高,插入删除元素效率低,因为会引起其他元素位置改 变。 Set和List具体子类: Set |————HashSet:以哈希表的形式存放元素,插入删除速度很快。 List |————ArrayList:动态数组 |————LinkedList:链表、队列、堆栈。 Array和java.util.Vector http://nything.javaeye.com 1.10 Java集合框架使用总结 第 26 / 42 页 Vector是一种老的动态数组,是线程同步的,效率很低,一般不赞成使用。 三、Iterator迭代器(接口) Iterator是获取集合中元素的过程,实际上帮助获取集合中的元素。 迭代器代替了 Java Collections Framework 中的 Enumeration。迭代器与枚举有两点不同: 迭代器允许调用方利用定义良好的语义在迭代期间从迭代器所指向的集合移除元素。 方法名称得到了改进。 Iterator仅有一个子接口ListIterator,是列表迭代器,允许程序员按任一方向遍历列表、迭代期间修改列表,并 获得迭代器在列表中的当前位置。ListIterator 没有当前元素;它的光标位置 始终位于调用 previous() 所返回 的元素和调用 next() 所返回的元素之间。在长度为 n 的列表中,有 n+1 个有效的索引值,从 0 到 n(包 含)。 四、集合框架之外的Map接口 Map将键映射到值的对象。一个映射不能包含重复的键;每个键最多只能映射一个值。 Map接口是Dictionary(字典)抽象类的替代品。 Map 接口提供三种collection 视图,允许以键集、值集合或键-值映射关系集的形式查看某个映射的内容。映射 的顺序 定义为迭代器在映射的 collection 视图中返回其元素的顺序。某些映射实现可明确保证其顺序,如 TreeMap 类;某些映射实现则不保证顺序,如 HashMap 类。 有两个常见的已实现的子类: HashMap:基于哈希表的 Map 接口的实现。此实现提供所有可选的映射操作,并允许使用 null 值和 null 键。(除了不同步和允许使用 null 之外,HashMap 类与 Hashtable 大致相同。)此类不保证映射的顺序,特 别是它不保证该顺序恒久不变。 TreeMap:它实现SortedMap 接口的基于红黑树的实现。此类保证了映射按照升序顺序排列关键字,根据使用 的构造方法不同,可能会按照键的类的自然顺序 进行排序(参见 Comparable),或者按照创建时所提供的比 较器进行排序。 Hashtable:此类实现一个哈希表,该哈希表将键映射到相应的值。任何非 null 对象都可以用作键或值。 五、线程安全类 在集合框架中,有些类是线程安全的,这些都是JDK1.1中的出现的。在JDK1.2之后,就出现许许多多非线程安 全的类。 下面是这些线程安全的同步的类: Vector:就比ArrayList多了个同步化机制(线程安全)。 Statck:堆栈类,先进后出。 http://nything.javaeye.com 1.10 Java集合框架使用总结 第 27 / 42 页 Hashtable:就比HashMap多了个线程安全。 Enumeration:枚举,相当于迭代器。 除了这些之外,其他的都是非线程安全的类和接口。 线程安全的类其方法是同步的,每次只能一个访问。是重量级对象,效率较低。对于非线程安全的类和接口, 在多线程中需要程序员自己处理线程安全问题。 六、其他一些接口和类介绍 Dictionary和Hashtable类: Dictionary提供键值映射的功能,是个抽象类。一般使用它的子类HashTable类。遍历Hashtable类要用到枚 举。 Properties类 Properties 继承于 Hashtable,Properties 类表示了一个持久的属性集。Properties 可保存在流中或从流中加 载。属性列表中每个键及其对应值都是一个字符串。一般可以通过读取properties配置文件来填充Properties对 象。 本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/nihao_201104/archive/2008/11/21/ 3345127.aspx http://nything.javaeye.com 1.10 Java集合框架使用总结 第 28 / 42 页 1.11 抽象类与接口的区别 发表时间: 2009-07-10 abstract class和interface是Java语言中对于抽象类定义进行支持的两种机制, 正是由于这两种机制的存在,才赋予了Java强大的面向对象能力。abstract class和 interface之间在对于抽象类定义的支持方面具有很大的相似性,甚至可以相互替 换,因此很多开发者在进行抽象类定义时对于abstract class和interface的选择显得 比较随意。 其实,两者之间还是有很大的区别的,对于它们的选择甚至反映出对于问题领域 本质的理解、对于设计意图的理解是否正确、合理。本文将对它们之间的区别进行一 番剖析,试图给开发者提供一个在二者之间进行选择的依据。 一、理解抽象类 abstract class和interface在Java语言中都是用来进行抽象类(本文中的抽象类 并非从abstract class翻译而来,它表示的是一个抽象体,而abstract class为Java语 言中用于定义抽象类的一种方法,请读者注意区分)定义的,那么什么是抽象类,使 用抽象类能为我们带来什么好处呢? 在面向对象的概念中,我们知道所有的对象都是通过类来描绘的,但是反过来却 不是这样。并不是所有的类都是用来描绘对象的,如果一个类中没有包含足够的信息 来描绘一个具体的对象,这样的类就是抽象类。抽象类往往用来表征我们在对问题领 域进行分析、设计中得出的抽象概念,是对一系列看上去不同,但是本质上相同的具 体概念的抽象。 比如:如果我们进行一个图形编辑软件的开发,就会发现问题领域存在着圆、三 角形这样一些具体概念,它们是不同的,但是它们又都属于形状这样一个概念,形状 这个概念在问题领域是不存在的,它就是一个抽象概念。正是因为抽象的概念在问题 领域没有对应的具体概念,所以用以表征抽象概念的抽象类是不能够实例化的。 在面向对象领域,抽象类主要用来进行类型隐藏。我们可以构造出一个固定的一 组行为的抽象描述,但是这组行为却能够有任意个可能的具体实现方式。这个抽象描 述就是抽象类,而这一组任意个可能的具体实现则表现为所有可能的派生类。模块可 以操作一个抽象体。由于模块依赖于一个固定的抽象体,因此它可以是不允许修改 http://nything.javaeye.com 1.11 抽象类与接口的区别 第 29 / 42 页 的;同时,通过从这个抽象体派生,也可扩展此模块的行为功能。熟悉OCP的读者 一定知道,为了能够实现面向对象设计的一个最核心的原则OCP(Open-Closed Principle),抽象类是其中的关键所在。 二、从语法定义层面看abstract class和interface 在语法层面,Java语言对于abstract class和interface给出了不同的定义方式, 下面以定义一个名为Demo的抽象类为例来说明这种不同。使用abstract class的方 式定义Demo抽象类的方式如下: abstract class Demo { abstract void method1(); abstract void method2(); … } 使用interface的方式定义Demo抽象类的方式如下: interface Demo { void method1(); void method2(); … } http://nything.javaeye.com 1.11 抽象类与接口的区别 第 30 / 42 页 在abstract class方式中,Demo可以有自己的数据成员,也可以有非abstarct 的成员方法,而在interface方式的实现中,Demo只能够有静态的不能被修改的数 据成员(也就是必须是static final的,不过在interface中一般不定义数据成员),所 有的成员方法都是abstract的。从某种意义上说,interface是一种特殊形式的 abstract class。 从编程的角度来看,abstract class和interface都可以用来实现"design by contract"的思想。但是在具体的使用上面还是有一些区别的。 首先,abstract class在Java语言中表示的是一种继承关系,一个类只能使用一 次继承关系。但是,一个类却可以实现多个interface。也许,这是Java语言的设计 者在考虑Java对于多重继承的支持方面的一种折中考虑吧。 其次,在abstract class的定义中,我们可以赋予方法的默认行为。但是在 interface的定义中,方法却不能拥有默认行为,为了绕过这个限制,必须使用委 托,但是这会 增加一些复杂性,有时会造成很大的麻烦。 在抽象类中不能定义默认行为还存在另一个比较严重的问题,那就是可能会造成 维护上的麻烦。因为如果后来想修改类的界面(一般通过abstract class或者 interface来表示)以适应新的情况(比如,添加新的方法或者给已用的方法中添加 新的参数)时,就会非常的麻烦,可能要花费很多的时间(对于派生类很多的情况, 尤为如此)。但是如果界面是通过abstract class来实现的,那么可能就只需要修改 定义在abstract class中的默认行为就可以了。 同样,如果不能在抽象类中定义默认行为,就会导致同样的方法实现出现在该抽 象类的每一个派生类中,违反了"one rule,one place"原则,造成代码重复,同样 不利于以后的维护。因此,在abstract class和interface间进行选择时要非常的小 心。 三、从设计理念层面看abstract class和interface 上面主要从语法定义和编程的角度论述了abstract class和interface的区别,这 些层面的区别是比较低层次的、非本质的。本文将从另一个层面:abstract class和 interface所反映出的设计理念,来分析一下二者的区别。作者认为,从这个层面进 行分析才能理解二者概念的本质所在。 前面已经提到过,abstarct class在Java语言中体现了一种继承关系,要想使得 继承关系合理,父类和派生类之间必须存在"is a"关系,即父类和派生类在概念本质 上应该是相同的。对于interface 来说则不然,并不要求interface的实现者和 http://nything.javaeye.com 1.11 抽象类与接口的区别 第 31 / 42 页 interface定义在概念本质上是一致的,仅仅是实现了interface定义的契约而已。为 了使论述便于理解,下面将通过一个简单的实例进行说明。 考虑这样一个例子,假设在我们的问题领域中有一个关于Door的抽象概念,该 Door具有执行两个动作open和close,此时我们可以通过abstract class或者 interface来定义一个表示该抽象概念的类型,定义方式分别如下所示: 使用abstract class方式定义Door: abstract class Door { abstract void open(); abstract void close(); } 使用interface方式定义Door: interface Door { void open(); void close(); } 其他具体的Door类型可以extends使用abstract class方式定义的Door或者 implements使用interface方式定义的Door。看起来好像使用abstract class和 interface没有大的区别。 http://nything.javaeye.com 1.11 抽象类与接口的区别 第 32 / 42 页 如果现在要求Door还要具有报警的功能。我们该如何设计针对该例子的类结构 呢(在本例中,主要是为了展示abstract class和interface反映在设计理念上的区 别,其他方面无关的问题都做了简化或者忽略)下面将罗列出可能的解决方案,并从 设计理念层面对这些不同的方案进行分析。 解决方案一: 简单的在Door的定义中增加一个alarm方法,如下: abstract class Door { abstract void open(); abstract void close(); abstract void alarm(); } 或者 interface Door { void open(); void close(); void alarm(); } 那么具有报警功能的AlarmDoor的定义方式如下: http://nything.javaeye.com 1.11 抽象类与接口的区别 第 33 / 42 页 class AlarmDoor extends Door { void open() { … } void close() { … } void alarm() { … } } 或者 class AlarmDoor implements Door { void open() { … } void close() { … } void alarm() { … } } 这种方法违反了面向对象设计中的一个核心原则ISP(Interface Segregation Priciple),在Door的定义中把Door概念本身固有的行为方法和另外一个概念"报警 器"的行为方法混在了一起。这样引起的一个问题是那些仅仅依赖于Door这个概念的 模块会因为"报警器"这个概念的改变(比如:修改alarm方法的参数)而改变,反之 依然。 解决方案二: http://nything.javaeye.com 1.11 抽象类与接口的区别 第 34 / 42 页 既然open、close和alarm属于两个不同的概念,根据ISP原则应该把它们分别定 义在代表这两个概念的抽象类中。定义方式有:这两个概念都使用abstract class方 式定义;两个概念都使用interface方式定义;一个概念使用abstract class方式定 义,另一个概念使用interface方式定义。 显然,由于Java语言不支持多重继承,所以两个概念都使用abstract class方式 定义是不可行的。后面两种方式都是可行的,但是对于它们的选择却反映出对于问题 领域中的概念本质的理解、对于设计意图的反映是否正确、合理。我们一一来分析、 说明。 如果两个概念都使用interface方式来定义,那么就反映出两个问题: 1、我们可能没有理解清楚问题领域,AlarmDoor在概念本质上到底是Door还 是报警器? 2、如果我们对于问题领域的理解没有问题,比如:我们通过对于问题领域的分 析发现AlarmDoor在概念本质上和Door是一致的,那么我们在实现时就没有能够正 确的揭示我们的设计意图,因为在这两个概念的定义上(均使用interface方式定 义)反映不出上述含义。 如果我们对于问题领域的理解是:AlarmDoor在概念本质上是Door,同时它有 具有报警的功能。我们该如何来设计、实现来明确的反映出我们的意思呢?前面已经 说过,abstract class在Java语言中表示一种继承关系,而继承关系在本质上是"is a"关系。所以对于Door这个概念,我们应该使用abstarct class方式来定义。另外, AlarmDoor又具有报警功能,说明它又能够完成报警概念中定义的行为,所以报警 概念可以通过interface方式定义。如下所示: abstract class Door { abstract void open(); abstract void close(); } interface Alarm { void alarm(); http://nything.javaeye.com 1.11 抽象类与接口的区别 第 35 / 42 页 } class AlarmDoor extends Door implements Alarm { void open() { … } void close() { … } void alarm() { … } } 这种实现方式基本上能够明确的反映出我们对于问题领域的理解,正确的揭示我 们的设计意图。其实abstract class表示的是"is a"关系,interface表示的是"like a"关系,大家在选择时可以作为一个依据,当然这是建立在对问题领域的理解上的, 比如:如果我们认为AlarmDoor在概念本质上是报警器,同时又具有Door的功能, 那么上述的定义方式就要反过来了。 abstract class和interface是Java语言中的两种定义抽象类的方式,它们之间有 很大的相似性。但是对于它们的选择却又往往反映出对于问题领域中的概念本质的理 解、对于设计意图的反映是否正确、合理,因为它们表现了概念间的不同的关系(虽 然都能够实现需求的功能)。这其实也是语言的一种的惯用法,希望读者朋友能够细 细体会 http://nything.javaeye.com 1.11 抽象类与接口的区别 第 36 / 42 页 1.12 面向对象设计61点经验原则 发表时间: 2009-07-10 摘抄自《OOD 启示录》--Arthur J.Riel (1)所有数据都应该隐藏在所在的类的内部。p13 (2)类的使用者必须依赖类的共有接口,但类不能依赖它的使用者。p15 (3)尽量减少类的协议中的消息。p16 (4)实现所有类都理解的最基本公有接口[例如,拷贝操作(深拷贝和浅拷贝)、相等性判断、正确输出内容、从 ASCII描述解析等等]。 p16 (5)不要把实现细节(例如放置共用代码的私有函数)放到类的公有接口中。p17 如果类的两个方法有一段公共代码,那么就可以创建一个防止这些公共代码的私有函数。 (6)不要以用户无法使用或不感兴趣的东西扰乱类的公有接口。p17 (7)类之间应该零耦合,或者只有导出耦合关系。也即,一个类要么同另一个类毫无关系,要么只使用另一个类 的公有接口中的操作。 p18 (8)类应该只表示一个关键抽象。p19 包中的所有类对于同一类性质的变化应该是共同封闭的。一个变化若对一个包影响,则将对包中的所有类产生 影响,而对其他的包不造成任何影响 . (9)把相关的数据和行为集中放置。p19 设计者应当留意那些通过get之类操作从别的对象中获取数据的对象。这种类型的行为暗示着这条经验原则被违 反了。 (10)把不相关的信息放在另一个类中(也即:互不沟通的行为)。p19 朝着稳定的方向进行依赖. (11)确保你为之建模的抽象概念是类,而不只是对象扮演的角色。p23 (12)在水平方向上尽可能统一地分布系统功能,也即:按照设计,顶层类应当统一地共享工作。p30 http://nything.javaeye.com 1.12 面向对象设计61点经验原则 第 37 / 42 页 (13)在你的系统中不要创建全能类/对象。对名字包含Driver、Manager、System、Susystem的类要特别多加 小心。p30 规划一个接口而不是实现一个接口。 (14)对公共接口中定义了大量访问方法的类多加小心。大量访问方法意味着相关数据和行为没有集中存放。p30 (15)对包含太多互不沟通的行为的类多加小心。p31 这个问题的另一表现是在你的应用程序中的类的公有接口中创建了很多的get和set函数。 (16)在由同用户界面交互的面向对象模型构成的应用程序中,模型不应该依赖于界面,界面则应当依赖于模型。 p33 (17)尽可能地按照现实世界建模(我们常常为了遵守系统功能分布原则、避免全能类原则以及集中放置相关数据 和行为的原则而违背这条原则) 。p36 (18)从你的设计中去除不需要的类。p38 一般来说,我们会把这个类降级成一个属性。 (19)去除系统外的类。p39 系统外的类的特点是,抽象地看它们只往系统领域发送消息但并不接受系统领域内其他类发出的消息。 (20)不要把操作变成类。质疑任何名字是动词或者派生自动词的类,特别是只有一个有意义行为的类。考虑一下 那个有意义的行为是否应当迁移到已经存在或者尚未发现的某个类中。p40 (21)我们在创建应用程序的分析模型时常常引入代理类。在设计阶段,我们常会发现很多代理没有用的,应当去 除。p43 (22)尽量减少类的协作者的数量。p52 一个类用到的其他类的数目应当尽量少。 (23)尽量减少类和协作者之间传递的消息的数量。p55 (24)尽量减少类和协作者之间的协作量,也即:减少类和协作者之间传递的不同消息的数量。p55 (25)尽量减少类的扇出,也即:减少类定义的消息数和发送的消息数的乘积。p55 (26)如果类包含另一个类的对象,那么包含类应当给被包含的对象发送消息。也即:包含关系总是意味着使用关 http://nything.javaeye.com 1.12 面向对象设计61点经验原则 第 38 / 42 页 系。p55 (27)类中定义的大多数方法都应当在大多数时间里使用大多数数据成员。p57 (28)类包含的对象数目不应当超过开发者短期记忆的容量。这个数目常常是6。p57 当类包含多于6个数据成员时,可以把逻辑相关的数据成员划分为一组,然后用一个新的包含类去包含这一组成 员。 (29)让系统功能在窄而深的继承体系中垂直分布。p58 (30)在实现语义约束时,最好根据类定义来实现。这常常会导致类泛滥成灾,在这种情况下,约束应当在类的行 为中实现,通常是在构造函数中实现,但不是必须如此。p60 (31)在类的构造函数中实现语义约束时,把约束测试放在构造函数领域所允许的尽量深的包含层次中。p60 (32)约束所依赖的语义信息如果经常改变,那么最好放在一个集中式的第3方对象中。p60 (33)约束所依赖的语义信息如果很少改变,那么最好分布在约束所涉及的各个类中。p60 (34)类必须知道它包含什么,但是不能知道谁包含它。p61 (35)共享字面范围(也就是被同一个类所包含)的对象相互之间不应当有使用关系。p61 (36)继承只应被用来为特化层次结构建模。p74 (37)派生类必须知道基类,基类不应该知道关于它们的派生类的任何信息。p74 (38)基类中的所有数据都应当是私有的,不要使用保护数据。p75 类的设计者永远都不应该把类的使用者不需要的东西放在公有接口中。 (39)在理论上,继承层次体系应当深一点,越深越好。p77 (40)在实践中,继承层次体系的深度不应当超出一个普通人的短期记忆能力。一个广为接受的深度值是6。p77 (41)所有的抽象类都应当是基类。p81 (42)所有的基类都应当是抽象类。p82 http://nything.javaeye.com 1.12 面向对象设计61点经验原则 第 39 / 42 页 (43)把数据、行为和/或接口的共性尽可能地放到继承层次体系的高端。p85 (44)如果两个或更多个类共享公共数据(但没有公共行为),那么应当把公共数据放在一个类中,每个共享这个数 据的类都包含这个类。 p88 (45)如果两个或更多个类有共同的数据和行为(就是方法),那么这些类的每一个都应当从一个表示了这些数据和 方法的公共基类继承。 p89 (46)如果两个或更多个类共享公共接口(指的是消息,而不是方法),那么只有他们需要被多态地使用时,他们才 应当从一个公共基类继承。 p89 (47)对对象类型的显示的分情况分析一般是错误的。在大多数这样的情况下,设计者应当使用多态。p89 (48)对属性值的显示的分情况分析常常是错误的。类应当解耦合成一个继承层次结构,每个属性值都被变换成一 个派生类。 p96 (49)不要通过继承关系来为类的动态语义建模。试图用静态语义关系来为动态语义建模会导致在运行时切换类 型。p97 (50)不要把类的对象变成派生类。对任何只有一个实例的派生类都要多加小心。p99 (51)如果你觉得需要在运行时刻创建新的类,那么退后一步以认清你要创建的是对象。现在,把这些对象概括成 一个类。 p103 (52)在派生类中用空方法(也就是什么也不做的方法)来覆写基类中的方法应当是非法的。p103 (53)不要把可选包含同对继承的需要相混淆。把可选包含建模成继承会带来泛滥成灾的类。p108 (54)在创建继承层次时,试着创建可复用的框架,而不是可复用的组件。p112 (55)如果你在设计中使用了多重继承,先假设你犯了错误。如果没犯错误,你需要设法证明。p120 (56)只要在面向对象设计中用到了继承,问自己两个问题:(1)派生类是否是它继承的那个东西的一个特殊类 型?(2)基类是不是派生类的一部分?p121 (57)如果你在一个面向对象设计中发现了多重继承关系,确保没有哪个基类实际上是另一个基类的派生类。 http://nything.javaeye.com 1.12 面向对象设计61点经验原则 第 40 / 42 页 p122 (58)在面向对象设计中如果你需要在包含关系和关联关系间作出选择,请选择包含关系。p123 (59)不要把全局数据或全局函数用于类的对象的薄记工作。应当使用类变量或类方法。p140 (60)面向对象设计者不应当让物理设计准则来破坏他们的逻辑设计。但是,在对逻辑设计作出决策的过程中我们 经常用到物理设计准则。 p149 (61)不要绕开公共接口去修改对象的状态。p164 http://nything.javaeye.com 1.12 面向对象设计61点经验原则 第 41 / 42 页 感谢阅读! Java基础知识小结 作者: nything http://nything.javaeye.com 本书由JavaEye提供电子书DIY功能制作并发行。 更多精彩博客电子书,请访问:http://www.javaeye.com/blogs/pdf http://www.javaeye.com - 做最棒的软件开发交流社区 第 42 / 42 页
还剩41页未读

继续阅读

下载pdf到电脑,查找使用更方便

pdf的实际排版效果,会与网站的显示效果略有不同!!

需要 20 金币 [ 分享pdf获得金币 ] 0 人已下载

下载pdf

pdf贡献者

openkk

贡献于2011-05-30

下载需要 20 金币 [金币充值 ]
亲,您也可以通过 分享原创pdf 来获得金币奖励!
下载pdf