`
unnKoel
  • 浏览: 13734 次
  • 性别: Icon_minigender_1
  • 来自: 苏州
社区版块
存档分类
最新评论

Think in java 读书笔记

阅读更多
one charpt 对象入门
  •      抽象的进步
    • 汇编对基础机器抽象,“命令式语言”对汇编抽象
    • 所有问题都归为列表,归为算法的抽象
    • 抽象为对象
      • 个 人理解:用对象来描述世界,而不单单只看问题。问题只是各对象相互作用的结果,所以确切地说面向对象语言描述的是与所要解决问题相关的各个部分组成的环 境,这个各个部分即为“对象”。发散而想,用面向对象语言编写的一个程序,解决的不仅仅再是一个特定的问题,而是一类问题,只要是在这个环境中发生的问 题,即可以拓展。它的着眼点不再是问题的本身,而是环境。
        • 当然描述这个环境,因人而异。一个真正好的表达者,应该懂得以“立体”思维去表达的好处。
        • 打个比方,比如“人拿斧头砍树”,其中有三个对象:人,斧头,和树。
      • 什么是计算机:
  • 对象的接口
    • 向对象发出的请求是通过接口定义的,类型则规定了它的接口形式。
    • “接口”规定了可以对一个特定对象发送哪些请求。
    • 满足请求的代码与隐藏起来的数据叫作"隐藏的实现"。
    • 两方面原因促使控制对成员的访问:
      • 防止程序员接触他们不该接触的东西(内部数据类型的设计思想,用户只需操作接口)
      • 设计人员修改修改内部结构,不必担心对客户程序员造成影响
    • 访问修饰符:public ,private ,protected,friendly
  • 方案的重复使用
    • 组织
    • 继承
  • 继承:重新使用接口
    • 利用现成数据类型,对其“克隆”,根据情况进行添加、修改,“继承”针对这个目标设计
    • 继承的类不仅含有现有类型的所有成员,更重要的是,它复制了基础类的接口
    • 把衍生类与基础类区分开:
      • ·为衍生类增加新函数
      • 改善一个函数,为衍生类函数建立新的定义
    • 等价与类似关系
      • 等价:衍生类与基础类属于一个类型,因为拥有完全相同的接口
      • 类似:为衍生类加入新的接口元素,不仅扩展了接口,也创建了一种新类型
  • 多形对象的互换使用
  • 动态绑定
    • 多形性:将一个消息发给对象时,如果不知道对象的具体类型是什么,但采取的动作是正确的。
    • 动态绑定:面向对象语言通过“动态绑定”来实现多形性,编译器与运行期系统会负责所有细节的控制。
  • 抽象基础类和接口
    • 目标:希望基本类只为自己的衍生类提供一个接口,不能创建基础类实例
    • abstract关键字
    • “这是适用于从这个类继承的所有类型的一个接口函数,但目前尚没有对它进行任何形式的实现”
    • 接口:
      • interface(接口)关键字将抽象类的概念更延伸了一步,它完全禁止了所有的函数定义
      • 亦可将多个接口都合并到一起,不能从多个普通class 或abstract class 中继承
  • 对象的创建和存在时间
    • 集合与继承器
    • 单根结构
      • 利用单根结构,我们可以更方便地实现一个垃圾收集器
      • 与垃圾收集有关的必要支持可安装于基础类中
      • 单根结构中的所有对象(比如所有Java 对象)都可以保证拥有一些特定的功能
      • 运行期的类型信息肯定存在于所有对象中,所以永远不会遇到判断不出一个对象的类型的情况
    • 集合库与方便使用集合
      • “上溯造型”与“下溯造型”
      • 假如下溯造型成错误的东西,会得到我们称为“违例”(Exception)的一种运行期错误
      • 必须用某种方式准确地记住它们是什么,以保证下溯造型的正确进行
    • 清除时的困惑:由谁来负责
      • 垃圾收集器
    • 个人理解:一些运行期系统:比如垃圾收集器,基于object
  • 违例控制:解决错误
    • 抛出“违例”,由“违例控制器”捕获,并得到处理
  • 多线程
    • 机器低级知识的程序员编写一些“中断服务例程”
    • 求将问题划分进入独立运行的程序片断中,这些独立运行的片断叫作“线程”(Thread)
    • 程序在逻辑意义上被分割为数个线程,与物理处理器无关。
      • 个 人理解:一个问题的解决,不单单只有cup运行,比如磁盘。比如:cup执行一条读磁盘数据命令,需要1毫秒,而磁盘读写器读取需要10毫秒,如果下面的 工作不一定马上需要现读数据,那cup不必等待,继续执行后续代码,可能会用到其他外围部件,比如打印机。进程使不同应用程序可以轮流运行。而线程使计算 机资源充分利用。
  • 永久性
    • 我们可将对象简单地保存到磁盘上,以后任何时间都可取回
  • Java与web
    • service/client
    • service/web
      • 客户端编程
        • 插件:插件实际是浏览器的一个“后门”,允许创建新的客户端程序设计语言
        • 脚本编制语言(80%)
          • 语言进行解释的插件会在HTML 页显示的时候自动激活
          • JavaScript,VBScript,Tcl
        • java(20%)
          • applet"程序片"
            • 作为Web 页的一部分,程序片代码会自动下载回来
            • Java 程序片的另一个优点是它采用编译好的形式,所以客户端看不到源码,当然可以反编译
        • ActiveX
        • 安全
          • 用ActiveX 编写程序就象编制Windows 应用程序,可以做自己想做的任何事情。目前解决的办法是“数字签名”
          • Java 通过“沙箱”来防止这些问题的发生,一般不能作操作磁盘等敏感事情。解决方法“签了名的程序片”
        • 因特网和互联网
      • 服务器端编程
        • 传统意义上,服务器端编程是用Perl 和CGI 脚本进行的
        • Java 进行所有服务器端编程,写出的程序就叫作“小服务程序”(Servlet)
    • 一个独立的领域:应用程序
  • 分析与设计
    • 不要迷失
      • 对象是什么?(怎样将自己的项目分割成一系列单独的组件?)
      • 它们的接口是什么?(需要将什么消息发给每一个对象?)
    • 整个过程可划分为四个阶段
      • 拟出一个计划
      • 要制作什么
      • 如何构建
      • 开始创建
      • 校订
      • 个人理解:粗略估计系统完成时间。明确需求,转化成系统目标。“庖丁解牛”,构建框架,比对系统目标,不断完善。
  • java还是c++
    • java,最“健壮”的类型检查及错误控制系统
 
two charpt 一切都是对象
  • 用句柄操作对象
    • 遥控板(句柄),电视机(对象)
    • 更安全的做法是:创建一个句柄时,记住无论如何都进行初始化。如果直接向句柄发送一条消息,会报运行期错误。
  • 所有对象都必须创建
    • 使用new
    • 保存到什么地方
      • 寄存器:根据需要由编译器分配,没有直接的控制权
      • 堆栈
        • RAM,特别快、特别有效的数据保存方式,仅次于寄存器。
        • Java 编译器知道堆栈内保存的所有数据的“长度”以及“存在时间”。由于它必须生成相应的代码,以便向上和向下移动指针
        • 对象句柄保存在堆栈中
        • RAM
        • 保存对象
        • 编译器不必知道要从堆里分配多少存储空间和存在多少时间
        • 但在堆里分配空间花费更多时间
      • 静态存储
        • RAM,固定位置
        • 可用static 关键字指出一个对象的特定元素是静态的
      • 常数存储
      • 非RAM存储
        • 流式对象
        • 固定对象
      • 个 人理解:在装载类的时候,即形成Class对象时,static部分,在RAM固定位置分配空间,当然它的位置信息会记录在Class对象,方法块分配 RAM空间,位置信息记录在Class对象。当然成员变量的创建指令也会分配RAM空间,位置信息记录在Class对象,当new时,通过这些创建指令在 推里面分配空间,并且堆栈中有句柄指向这个分配空间,句柄是一个立体的多指向空间。
        • 如果所有变量,在编译时就明确知道类型,就知道分配多少空间,位置也能明确计算出来。堆栈中,明确可以知道类型。等于“指挥者”发指令说:多少空间,放在什么位置,另外多少空间,放在什么位置。
          • 对于不能确定大小的,比如对象引用,该给多少空间呢?肯定规定了一个地址的大小,而且所有引用大小一样,因为这是个对象所分配空间起始点的地址,至于这个对象分配的空间到哪儿结束,这个由堆的管理程序记录维护。
          • 至于基础类型,除了String,其他都明确知道大小。String类似对象处理。
        • 如果编译时不能明确知道类型,“指挥者”说那你先实际去分配,等分配完了,再把分配了多少空间返回给“指挥者”。所以可想而知,堆,有一个完善的管理程序,它可以动态记录堆的状态。
    • 特殊情况:主要类型
      • 这个变量容纳了具体的值,并置于堆栈中,能够更高效地存取。
      • boolean,char,byte,float,double,int,long,void
      • Java 决定了每种主要类型的大小。就象在大多数语言里那样,这些大小并不随着机器结构的变化而变化
      • 主要类型的封装类char-Character
      • BigInteger(任意精度整数),BigDecimal(任意精度的定点数字)
    • Java的数组
      • Java 可以保证被初始化,而且系统自动进行范围检查。
      • 提高了安全性,但牺牲了少许性能
      • 创建对象数组时,实际创建的是一个句柄数组,每个句柄都会自动初始化成一个特殊值。
  • 绝对不要清楚对象
    • 作用域
      • 对于在作用域里定义的名字,作用域同时决定了它的“可见性”以及“存在时间”
      • 下面这种方式在C++,C中正确,但是Java认为非法
                 {
                    int x=12;
                    {
                        int x=3;/*illegal*/
                    }
                  }
 
    • 对象的作用域
  • 新建数据类型:类
    • 字段和方法
      • 数据成员为对象,则必须初始化句柄,通过“构造函数”与实际的对象链接起来,也可以定义位置直接初始化
      • 主要类型,可以在定义位置直接初始化
      • 如果不显示初始化,会默认初始化。对象句柄为null
        • 主成员的默认值:boolean-false;char-'\u0000'(null);byte-(byte)0;short-(short)0;int-0;long-0L;float-0.0f;double-0.0d.可保证主类型的成员变量肯定得到了初始化
        • 并不适用于“局部”变量,如果没显示初始化,则得到一条编译期错误,告诉我们变量可能尚未初始化
  • 方法、自变量和返回值
    • 返回类型 方法名( /* 自变量列表*/ ) {/* 方法主体 */}
    • 对象名.方法名(自变量1,自变量2,自变量3...)
    • “静态”方法可针对类调用,毋需一个对象
    • 自变量列表
      • 传递对象时,通常都是指传递指向对象的句柄
      • “特殊”数据类型boolean,char,byte,short,int,long,,float 以及double 来说是一个例外
  • 构建Java程序
    • 名称的可见性
      • 以目前的整个软件包都以小写字母为标准
      • Java 的设计者鼓励程序员反转使用自己的Internet 域名
    • 使用其他组件
      • import
    • static关键字
      • 通过对象句柄引用static变量和方法,也可通过类名.~
      • static 方法也能创建自己类型的命名对象。static 方法作为一个“领头羊”使用,用它生成一系列自己类型的“实例”
  • 我们的第一个Java程序
    • 于java.lang 默认进入每个Java 代码文件,所以这些类在任何时候都可直接使用
    • 运算符过载,只是对String 对象而言。对于自己编写的任何源代码,都不可能使运算符“过载”。
    • Runtime 可告诉我们与内存使用有关的信息。
  • 注释与嵌入文档
    • /**/ 或者//
    • 编译时会忽略注释
    • 注释文档
      • 嵌入的html
      • 文档标记

three charpt 控制程序流程
  • 使用Java运算符
    • 所有运算符只能操作主类型
      • 例外:"=","==","!="可以操作对象
      • String可以使用"+=","+"
    • 优先级
      • 会忘记,应该使用括号
    • 赋值
      • 对象=对象,实际是对象句柄复制
      • 特殊类型=特殊类型
    • 算术运算符
      • 整数除法会直接砍掉小数,而不是进位。
      • 运算符的使用
    • 自增与自减
      • 副作用:会改变运算对象,而不仅仅是使用自己的值。
    • 关系运算符
      • 检查对象是否相等
        • 关系运算符==和!=也适用于所有对象,但它们的含义通常会使初涉Java 领域的人找不到北
        • 必须使用所有对象都适用的特殊方法equals()
        • equals()的默认行为是比较句柄,大多数Java 类库都实现了equals(),所以它实际比较的是对象的内容,而非它们的句柄。
    • 逻辑运算符
      • 在C 及C++中不同,不可将一个非布尔值当作布尔值在逻辑表达式中使用
      • 注意若在预计为String 值的地方使用,布尔值会自动转换成适当的文本形式。
      • 短路运算
    • 按位运算符
      • 按位运算符允许我们操作一个整数主数据类型中的单个“比特”,即二进制位
      • &,|,^  &=,|=,^=
      • 我们将boolean(布尔)类型当作一种“单位”或“单比特”值对待
    • 移位运算符
      • <<
      • >>(有符号右移),>>>(无符号右移)
      • 若对char,byte 或者short 进行移位处理,那么在移位进行之前,它们会自动转换成一个int
      • int只有右侧的5 个低位才会用到,long只有右侧的6 个低位才会用到
        • char,byte 或者short在移位操作时,不会再自动转换成int.java1.7改变了?
    • 三元运算符
    • 逗号运算符
      • 使用在for循环
    • 字串运算符+
      • 那么早期版本的Java 就会提示出错(以后的版本能将x 转换成一个字串)。
    • 造型运算符
      • “缩小转换”(Narrowing Conversion)的操作,可能面临信息丢失的危险
      • “放大转换”则不必进行明确造型,因为新类型肯定能容纳原来类型的信息
      • Java 允许我们将任何主类型“造型”为其他任何一种主类型,但布尔值(bollean)要除外,“类”不允许进行造型
      • 字面值
        • 对于float,指定值时需要造型,应该编译器默认作为double处理
      • 转型
        • char,byte 或者short,在正式执行运算之前,那些值会自动转换成int,最终生成的值就是int 类型,只要把一个值赋回较小的类型,就必须使用“造型”。
          • short i=0;i+=3;没问题
          • short i=0;i=i+3;需要转型
        • 通常,表达式中最大的数据类型是决定了表达式最终结果大小的那个类型
    • java中没有sizeof
      • 在c或者c++中解决程序移植问题,因为在不同的计算机上,同类型可能占的字节数不相同
    • 复习计算顺序
    • 运算符总结
      • 布尔值(boolean)的能力非常有限。我们只能为其赋予true 和false 值
      • 如果对两个足够大的int 值执行乘法运算,结果值就会溢出
      •           char c='a';
                  short s=34;
                  byte b=23;
                  b=(byte) c;
                  c=(char) b;
                  s=b;
                  b=(byte) s;
                 
                  short s1='a';
                  char c1=3;
                  byte b1='b';
                  long l='a';
  • 执行控制
    • 真和假
      • 所有条件语句都利用条件表达式的真或假来决定执行流程
      • Java 不允许我们将一个数字作为布尔值使用
    • if-else
      • if(布尔表达式)
        语句
        或者
        if(布尔表达式)
        语句
        else
        语句
      • 语句包括复合语句和简单语句
      • return:指定一个方法返回什么值,并立即返回那个值
    • 反复
      • while
        • Math.random(),产生0-1之间的随机数(包括0,但不包括1)
      • do-while
        • 其中的执行语句至少过一遍,即使第一次条件就为false
      • for
        • for(初始表达式;布尔表达式;步进)
          语句
        • 初始表达式,布尔表达式和步进都可为空
        • 1. 逗号运算符
          • 逗号分隔符用于方法参数分割,java唯一用逗号运算符的在for循环表达式
          • 在控制表达式的初始化和步进控制部分,我们可使用一系列由逗号分隔的语句
          • 尽管初始化部分可设置任意数量的定义,但都属于同一类型。
      • 中断和继续
        • break,continue
        • 臭名昭著的“goto”
          • goto 仍是Java 的一个保留字,但并未在语言中得到正式使用;Java 没有goto
          • label1:
            外部循环{
            内部循环{
            //...
            break; //1
            //...
            continue; //2
            //...
            continue label1; //3
            //...
            break label1; //4
            }
            }
          • 在Java 里唯一需要用到标签的地方就是拥有嵌套循环
    • 开关
      • 根据一个整数表达式的值,switch 语句可从一系列代码选出一段执行
      • switch(整数选择因子) {
        case 整数值1 : 语句; break;
        case 整数值2 : 语句; break;
        case 整数值3 : 语句; break;
        case 整数值4 : 语句; break;
        case 整数值5 : 语句; break;
        //..
        default:语句;
        }
      • “整数选择因子”是一个特殊的表达式,能产生整数值
      • 若省略break,会继续执行后面的case 语句的代码,直到遇到一个break 为止
      • 选择因子必须是int 或char 那样的整数值(short也可以,但不能为long)
      • 在case 语句中,用单引号封闭起来的字符也会产生整数值,以便我们进行比较。
      • 将一个float 或double 值造型成整数值后,总是将小数部分“砍掉”,不作任何进位处理。
 
four charpt 初始化与清除
  • 用构造器自动初始化
    • 在Java 中,由于提供了名为“构建器”的一种特殊方法,所以类的设计者可担保每个对象都会得到正确的初始化
    • 第一个是我们使用的任何名字都可能与打算为某个类成员使用的名字冲突。
    • 第二是由于编译器的责任是调用构建器,所以它必须知道要调用是哪个方法。
    • 构建器的名字与类名相同
    • 构建器属于一种较特殊的方法类型,因为它没有返回值。这与void 返回值存在着明显的区别
      • 对于void 返回值,尽管方法本身不会自动返回什么,但仍然可以让它返回另一些东西
      • 构建器则不同,它不仅什么也不会自动返回,而且根本不能有任何选择
  • 方法过载
    • 我们用相同的词表达多种不同的含义——即词的“过载”
    • 另一项因素强迫方法名出现过载情况:构建器
    • 我们把没有自变量的构建器称作“默认构建器”
    • 区分过载方法
      • 除根据自变量的类型,自变量的顺序也足够我们区分两个方法
    • 主类型的过载
      • -------
      • 直接量初始化char,byte,short时,只要在他们访问内,则右边直接量类型就是变量类型,否则为int。而long右边直接量的类型默认是int,除非使用l
      • byte,short,int,long等都可以使用char类型常量来初始化,此时char会转换成整数,再初始化变量
      • byte,short和char变量之间相互负值时,需要明确的类型转换
      • -------
      • 若我们的数据类型“小于”方法中使用的自变量
        • char 获得的效果稍有些不同,这是由于假期它没有发现一个准确的char 匹配,就会转型为int
      • 若我们的自变量“大于”过载方法期望的自变量
        • 必须用括号中的类型名将其转为适当的类型。如果不这样做,编译器会报告出错。
    • 返回值过载
      • 不能根据返回值类型来区分过载的方法
        • void f1(),int f1()。对于int a=f1();自然很容易知道调用了哪个f1.但对于f1();这样的调用就不知道哪个执行哪个f1了
    • 默认构造器
      • 若创建一个没有构建器的类,则编译程序会帮我们自动创建一个默认构建器
    • this关键字
      • 将消息发给对象,编译器为我们完成了一些幕后工作。其中的秘密就是第一个自变量传递给方法f(),自变量是准备操作的那个对象的句柄。
      • 在构建器里调用构建器
        • 编译器不让我们从除了一个构建器之外的其他任何方法内部调用一个构建器
        • 尽管可用this 调用一个构建器,但不可调用两个。
  • 清除:收尾和垃圾收集
    • 假定我们的对象分配了一个“特殊”内存区域,没有使用new。垃圾收集器只知道释放那些由new 分配的内存,所以不知道如何释放对象的“特殊”内存。
    • 有时可能发现一个对象的存储空间永远都不会释放,因为自己的程序永远都接近于用光空间的临界点
    • finalize()用途何在
      • 垃圾收集只跟内存有关
      • 采取与Java 的普通方法不同的一种方法,通过分配内存来做一些具有C 风格的事情。通过“固有方法”来进行,在固有方法中,也许能调用C 的malloc()系列函数,用它分配存储空间。而且除非调用了free(),否则存储空间不会得到释放。
    • 必须执行清除
      • System.gc()
      • System.runFinalization()
  • 成员初始化
    • Char 值为空(NULL),没有数据打印出来
    • 在一个类的内部定义一个对象句柄时,如果不将其初始化成新对象,那个句柄就会获得一个空值
    • 规定初始化
      • 在类内部定义变量的同时也为其赋值
      • 可用相同的方法初始化非基本(主)类型的对象,若尚未为o 指定一个初始值,同时不顾一切地提前试用它,就会得到一条运行期错误提示。
      • class CInit {         
        int i = f();
        //...
        }
         
        class CInit {
        int i = f();
        int j = g(i);
        //...
        }
         
        //非法
        class CInit {
        int j = g(i);
        int i = f();
        //...
        }
    • 构建器初始化
      • 不可妨碍自动初始化的进行,它在构建器进入之前就会发生
      • 初始化顺序
      • 静态数据的初始化
        • 如果它属于一个基本类型(主类型),而且未对其初始化,就会自动获得自己的标准基本类型初始值
        • 如果它是指向一个对象的句柄,那么除非新建一个对象,并将句柄同它连接起来,否则就会得到一个空值
        • 如果想在定义的同时进行初始化,采取的方法与非静态值表面看起来是相同的
      • 明确进行的静态初始化
        • static{}
      • 非静态实例的初始化
        • 针对每个对象的非静态变量的初始化,Java 1.1 提供了一种类似的语法格式
        • {}
  • 数组初始化
 
five charpt 隐藏实施过程
 
“进行面向对象的设计时,一项基本的考虑是:如何将发生变化的东西与保持不变的东西分隔开。”
public,“友好的”(无关键字),protected 以及private。
  •   包:库单位
    • 由于存在名字潜在的冲突,所以特别有必要对Java 中的命名空间进行完整的控制
    • 为Java 创建一个源码文件的时候,它通常叫作一个“编辑单元”
      • 每个编译单元内都只能有一个public 类,类名跟文件名相同。
      • 那个编译单元剩下的类可在那个包外面的世界面前隐藏起来,因为它们并非“公共”的。
      • 一个有效的程序就是一系列.class 文件,它们可以封装和压缩到一个JAR 文件里。Java 解释器负责对这些文件的寻找、装载和解释
    • package 和import 关键字允许我们做的事情就是分割单个全局命名空间,保证我们不会遇到名字的冲突
    • 创建独一无二的包
      • 将某个特定包使用的所有.class 文件都置入单个目录里
      • 编译器强迫package 名的第一部分是类创建者的因特网域名
      • 必须将JAR文件的名字置于类路径里,而不仅仅是它所在的路径
      • 1.自动编译
        • 为导入的类首次创建一个对象时(或者访问一个类的static 成员时),编译器会在适当的目录里寻找同名的.class 文件-X.class,如果X.java存在并且它的日期标记比X.class新,就会自动编译,生成一个新的X.class.
      • 2.冲突
        • 若通过*导入了两个库,而且它们包括相同的名字
        • import com.bruceeckel.util.*;
          import java.util.*;
          java.util.Vector v = new java.util.Vector();这样来解决冲突
    • 自定义工具库
      • ClassPath陷阱
    • 利用导入改变行为 Assert
    • 包的停用
  • 访问指示符
    • “友好的”
      • 友好访问允许我们将相关的类都组合到一个包里,使它们相互间方便地进行沟通
      • class有public和“友好的”修饰符,其他的四个都有
      • 使成员成为“public”(公共的)。这样所有人从任何地方都可以访问它。
      • 变成一个“友好”成员,方法是舍弃所有访问指示符,并将其类置于相同的包内
      • 一个继承的类既可以访问一个protected 成员,也可以访问一个public 成员(但不可访问private 成员)
        • 继承会把父类的所有成员都继承过来,但是private成员不可访问
    • public:接口访问
      • 默认包中的类,只能在默认包中相互可见,不管类的访问权限
    • private:不能接触
      • 若确定一个类只有一个“助手”方法,那么对于任何方法来说,都可以把它们设为private
      • class Sundae {
        private Sundae() {}
        static Sundae makeASundae() {
        return new Sundae();
        }
        }
        1.想控制类创建方式
        2.可阻止这个类被继承
    • protected:友好的一种
      • 继承类之间可见,无视包
  • 接口与实现
  • 类访问
    • 可能(但并常见)有一个编译单元根本没有任何公共类。此时,可按自己的意愿任意指定文件名
    • public或者“友好的”,不能是private,protected
      • 实际上,Java 1.1 内部类既可以是“受到保护的”,也可以是“私有的”,但属于特殊情况
    • 如果没有明确地进行package 声明,那么它们都默认为那个目录的默认包的一部分
 
six charpt 类再生
  • 合成的语法
    • 在类内作为字段使用的基本数据会初始化成零,就象第2 章指出的那样。但对象句柄会初始化成null
    • System.out.println("source = " + source) ;会自动调用source对象的toString()方法
    • 如希望句柄得到初始化,可在下面这些地方进行
      • (1) 在对象定义的时候。这意味着它们在构建器调用之前肯定能得到初始化。
        (2) 在那个类的构建器中。
        (3) 紧靠在要求实际使用那个对象之前。这样做可减少不必要的开销——假如对象并不需要创建的话。
  • 继承的语法
    • 采用这种将main()置入每个类的做法,可方便地为每个类都进行单元测试。
      • 即便java一个编辑单位中没有public类,也可以编译,只要有public main方法,也可以得到允许
    • Java 提供了一个super 关键字,它引用当前类已从中继承的一个“超类”(Superclass)
      • 创建子类时,父类也会被创建,并且把父类的句柄块放入子类对象,这就是super
      • 父类句柄块会复制到子类句柄(堆栈)中
    • 初始化基础类
      • 创建衍生类的一个对象时,它在其中包含了基础类的一个“子对象”
      • 基础类子对象应该正确地初始化,而且只有一种方法能保证这一点:在构建器中执行初始化
      • 编译器也会为我们自动合成一个默认构建器,并发出对基础类构建器的调用
      • 1. 含有自变量的构建器
        • 必须明确地编写对基础类的调用代码。这是用super 关键字以及适当的自变量列表实现的
        • 如果不调用BoardGames()内的基础类构建器,编译器就会报告自己找不到Games()形式的一个构建器
      • 2. 捕获基本构建器的违例
        • 编译器会强迫我们在衍生类构建器的主体中首先设置对基础类构建器的调用,在它之前不能出现任何东西。
        • 防止衍生类构建器捕获来自一个基础类的任何违例事件
  • 合成与继承的结合
    • 保证正确的清除
      • 我们并不知道垃圾收集器什么时候才会显身,或者说不知它何时会调用。所以一旦希望为一个类清除什么东西,必须写一个特别的方法
      • 放入try{}finally{...}语句块中(无论会发生什么事情,总会得到执行)
      • 定义清除方法的调用顺序:首先完成与类有关的所有特殊工作,然后调用基础类清除方法。
      • 1. 垃圾收集的顺序
        • 除内存的回收以外,其他任何东西都最好不要依赖垃圾收集器进行回收
        • 若想明确地清除什么,请制作自己的清除方法,而且不要依赖finalize()
        • Java 1.0 实现的垃圾收集器机制通常不会调用finalize()方法(只有垃圾收集器启动了,才会执行finalize(),但不知道垃圾收集器什么时候启动,可能永远得不到调用)
        • 但是可强迫Java1.1 调用所有收尾模块(Finalizer)
    • 名字的隐藏
      • 覆盖,需要返回值,方法名,以及参数都相同
      • 过载,只要求方法名相同,参数不同,返回值没要求
    • 到底选择合成还是继承
      • 如选择继承,就需要取得一个现成的类,并制作它的一个特殊版本
      • 这意味着我们准备使用一个常规用途的类,并根据特定的需求对其进行定制
      • “属于”关系是用继承来表达的,而“包含”关系是用合成来表达的
  • protected
    • 它本身是私有的,但可由从这个类继承的任何东西或者同一个包内的其他任何东西访问
      • 在包访问的基础上增加了一个”继承访问“
  • 积累开发
  • 上溯造型
    • 何谓“上溯造型”
      • 进行上溯造型的时候,类接口可能出现的唯一一个问题是它可能丢失方法,而不是赢得这些方法
      • 也可以执行下溯造型,但这时会面临困境
      • 1.再论合成与继承
        • 为判断自己到底应该选用合成还是继承,一个最简单的办法就是考虑是否需要从新类上溯造型回基础类
  • final关键字
    • “这个东西不能改变”
    • final数据
      • 常数:(1) 编译期常数,它永远不会改变
        (2) 在运行期初始化的一个值,我们不希望它发生变化
      • 属于基本类型,要用final关键字,必须给出值
        • 初始化与非final变量相同
      • 对象句柄使用final,而不是基本数据类型,不能将句柄变成指向另一个对象。然而,对象本身是可以修改的
      • (数组,内存也是分配在堆中)
      • 空白final
      • final自变量
    • final方法
      • 设计程序时,若希望一个方法的行为在继承期间保持不变,而且不可被覆盖或改写,就可以采取这种做法
      • 采用final 方法的第二个理由是程序执行的效率
        • 它会用方法主体内实际代码的一个副本来替换方法调用
        • 通常,只有在方法的代码量非常少,或者想明确禁止方法被覆盖的时候,才应考虑将一个方法设为final。
    • final类
      • 于安全方面的理由,我们不希望进行子类化
      • 所以一个final 类中的所有方法都默认为final,与我们将一个方法明确声明为final 一样,编译器此时有相同的效率选择。
      • 将类定义成final 后,结果只是禁止进行继承,不影响成员变量
    • final的注意事项
  • 初始化与类装载
    • 继承初始化
 
seven charpt 多形性
     多型性是第三种最基本的特征(前两种是数据抽象和继承)。
  • 上溯造型
    • 为什么要上溯造型
  • 深入理解
    • 方法调用的绑定
      • 早期绑定(编译器和链接程序)
      • 后期绑定
    • 产生正确的行为
    • 拓展性
  • 覆盖与过载
  • 抽象类与方法
    • 如果一个类里包含了一个或多个抽象方法,类就必须指定成abstract
    • 无法实例化抽象类
    • 如果从一个抽象类继承,而且想生成新类型的一个对象,就必须为基础类中的所有抽象方法提供方法定义;如果不这样做(完全可以选择不做),则衍生类也会是抽象的
    • 即使不包括任何abstract 方法,亦可将一个类声明成“抽象类”
    • 抽象方法不能似有
  • 接口
    • 接口用于建立类和类之间的一个“协议”
    • 接口也包含了基本数据类型的数据成员,但它们都默认为static 和final
    • public 关键字,或者“友好的”
    • 在实现一个接口的时候,来自接口的方法必须定义成public
    • 1.java的多重继承
    • 2.通过继承拓展接口
      • 构建一个新接口时,extends 可能引用多个基础接口
    • 3.常数分组
      • 拥有固定标识符的static final 基本数据类型(亦即编译期常数)都全部采用大写字母(用下划线分隔单个标识符里的多个单词)
      • 接口是对常数值进行分组的一个好工
    • 4.初始化接口中的字段
      • 接口中定义的字段会自动具有static 和final 属性。它们不能是“空白final”,但可初始化成非常数表达式
      • 字段并不是接口的一部分,而是保存于那个接口的static 存储区域中
  • 内部类
    • 内部类与上溯造型
      • 内部类与外部类之间可以任意访问,不管修饰符;用在其他地方,遵守修饰符
      • 内部类可以使用private,protected,public,和“友好”修饰,abstract,final都行
    • 方法和作用域中的内部类
      • (1) 正如前面展示的那样,我们准备实现某种形式的接口,使自己能创建和返回一个句柄。
      • (2) 要解决一个复杂的问题,并希望创建一个类,用来辅助自己的程序方案。同时不愿意把它公开。
      • 方法内部类不能使用修饰符,只能使用abstract,final,它的访问范围应该就在方法内
      • 方法内部类,使用在方法内部类外部定义的一个对象,编译器要求外部对象为final属性(包括方法内部的匿名内部类),而类内部匿名内部类不需要类字段为final
    • 链接到外部类
      • 内部类可以访问外部类的所有成员
    • static内部类
      • (1) 为创建一个static 内部类的对象,我们不需要一个外部类对象。
      • (2) 不能从static 内部类的一个对象中访问一个外部类对象。
      • 由于static 成员只能位于一个类的外部级别,所以内部类不可拥有static 数据或static 内部类。创建内部类的对象而不需要创建外部类的一个对象,那么可将所有东西都设为static。为了能正常工作,同时也必须将内部类设为static
      • static 内部类可以成为接口的一部分
    • 引用外部类对象
    • 从内部类继承
      • 外部对象this传给内部类构造器,并调用this.super(),设置外部类的句柄给内部类。外部类也有内部类的引用
    • 内部类可以覆盖吗?
      • 当我们从外部类继承的时候,没有任何额外的内部类继续下去
  • 构造器与多形性
    • 构造器的调用顺序
      • 构建器负有一项特殊任务:检查对象是否得到了正确的构建
      • 这意味着对于一个复杂的对象,构建器的调用遵照下面的顺序:
        (1) 调用基础类构建器。这个步骤会不断重复下去,首先得到构建的是分级结构的根部,然后是下一个衍生
        类,等等。直到抵达最深一层的衍生类。
        (2) 按声明顺序调用成员初始化模块。
        (3) 调用衍生构建器的主体。
    • 继承与finalize()
      • 通过“合成”方法创建新类时,永远不必担心对那个类的成员对象的收尾工作
      • 覆盖衍生类的finalize()时,务必记住调用finalize()的基础类版本。否则,基础类的初始化根本不会发生
    • 构造器内部的多行性方法的行为
      • 在构造器中调用一个被覆盖的方法,会执行覆盖方法,是由于传进去的this值为衍生类对象
      • 先生成基础类的空间和衍生类空间(默认初始化),然后基础类初始化,衍生类初始化(负值初始化和构造器初始化)。
      • 构建器内避免调用任何方法,内唯一能够安全调用的是在基础类中具有final 属性的那些方法(也适用于private,它们自动具有final 属性
  • 通过继承进行设计
    • 合成显得更加灵活,因为可以动态选择一种类型(以及行为),而继承要求在编译期间准确地知道一种类型
    • 纯继承与扩展
    • 下溯造型和运行期类型标志
eightcharpt 对象的容纳
  • 数组
    • 数组和第一类对象
      • 数组标识符实际都是指向真实对象的一个句柄
      • 对象数组容纳的是句柄,而基本数据类型数组容纳的是具体的数值
      • 由基本数据类型构成的数组会自动初始化成零(针对数值类型)、null(字符类型)或者false(布尔类型),对象为null
      • 1.基本数据类型集合
        • 集合类只能容纳对象句柄。但对一个数组,却既可令其直接容纳基本类型的数据,亦可容纳指向对象的句
        • 和访问一个基本数据类型数组,那么比起访问一个封装数据的集合,前者的效率会高出许多
        • 准备一种基本数据类型,同时又想要集合的灵活性,就不宜使用数组,必须使用由封装的数据构成的一个集合
    • 数组的返回
  • 集合
    • Java 提供了四种类型的“集合类”:Vector(矢量)、BitSet(位集)、Stack(堆栈)以及Hashtable(散列表)
    • 缺点:类型未知
      • 由于类型信息不复存在,所以集合能肯定的唯一事情就是自己容纳的是指向一个对象的句柄。正式使用
        它之前,必须对其进行造型,使其具有正确的类型。
      • Vector.addElement(),elementAt();
      • 1. 错误有时并不显露出来
      • 2.生成能自动判别类型的Vector
      • 3. 参数化类型
  • 枚举器
    • Java 的Enumeration(枚举,注释②)便是具有这些限制的一个反复器的例子。elements(),nextElement(),hasMoreElements()
    • ""+对象,(String)对象
  • 集合类型
    • Vector
      • 1. 崩溃Java
        • Java 标准集合里包含了toString()方法,所以它们能生成自己的String 表达方式
        • 在Vector 中,toString()会在Vector 的各个元素中步进和遍历,并为每个元素调用toString()
        • public String toString() {
          return "CrashJava address: " + this + "\n";
          }
          会递归调用,直到奔溃,需使用super.toString();
    • BitSet
      • BitSet 实际是由“二进制位”构成的一个Vector。如果希望高效率地保存大量“开-关”信息,就应使用
    • Stack
      • 从Vector 里“继承”一个Stack
    • Hashtable
      • 继承Dictionary抽象类
      • Java 封装器能做的唯一事情就是将其初始化成一个特定的值,然后读取那个值
      • 1. 创建“关键”类
        • 默认的Object.hashCode,Object.equal只是比较对象的地址,要正确查找,需要覆盖。
      • 2. 属性:Hashtable 的一种类型
        • Properties p = System.getProperties();
          p.list(System.out);
          save(),load()-放入文件,和从文件加载
        • Properties 类是从Hashtable 继承的,但它也包含了一个散列表,用于容纳“默认”属性的列表没有在主列表里找到一个属性,就会自动搜索默认属性
    • 再论枚举器
  • 排序
  • 通用集合类(JGL)
  • 新集合
    • Iterator,Collection-(List,Set),Map
      • Iterator:hasNext(),Next(),remove()
    • 使用Collections
    • 使用Lists
      • List 为Collection 添加了大量方法
      • List 也会生成一个ListIterator(列表反复器),利用它可在一个列表里朝两个方向遍历
      • ArrayList与LinkedList-(addFist(),addLast(),getFirst(),getLast(),removeFist(),removeLast())
 
nine charpt 违例差错控制
  • 基本违例
    • 违例自变量
      • 创建一个不在程序常规执行范围之内的对象,随后,对象实际会从方法中返回
  • 违例的捕获
    • try块
    • 违例控制器
      • 违例控制机制就会搜寻自变量与违例类型相符的第一个控制器,一旦catch 从句结束,对控制器的搜索也会停止
      • 1. 中断与恢复
    • 违例规范(throws)
      • 要求“掷”出一个并没有发生的违例,以后可以方便地产生实际的违例,毋需修改现有的代码
    • 捕获所有违例
      • Exception,Throwable(getMessage(),toString(),printStackTrace(),printStackTrace(PrintStream))
    • 重新抛出违例
      • e.fillInStackTrace()
      • 注意NullPointerException()
  • 标准Java违例
    • Throwable
      • Error:编译器和系统错误
      • Exception:运行期偶发事件中“掷”出
      • 违例的名字代表发生的问题
      • 1.RuntimeException的特殊情况
        • 运行期错误,编译器无法侦察到的错误
        • 如果不捕获这些违例,可能过滤掉我们到达main()方法的所有途径
        • RuntimeException导致程序无法运行,而其他Exception则是一种逻辑选择(错误)
  • 创建自己的违例
  • 违例的限制
    • 一个构建器能够“掷”出它希望的任何东西
  • 用finally清除
    • Java 违例(类似C++的违例)不允许我们恢复至违例产生地方的这一事
    • finally用来做什么
      • 除将内存设回原始状态以外,若要设置另一些东西,finally 就是必需的
      • 打开一个文件或者建立一个网络连接,或者在屏幕上画一些东西,甚至设置外部世界的一个开关,等等
    • 缺点:丢失的违类
      • 执行main函数的Jvm系统程序会catch(Exception e)总的异常,一次处理
  • 构建器
  • 违例匹配
    • 编译器会产生一条出错消息,因为它发现永远不可能抵达Sneeze 捕获从句
    • 违例准则
 
tencharpt javaIO系统

  • 输入和输出
    • 从InputStream(输入流)衍生的所有类都拥有名为read()的基本方法,用于读取单个字节或者
      字节数组。类似地,从OutputStream 衍生的所有类都拥有基本方法write(),用于写入单个字节或者字节数
      组。
    • InputStream类型
      • InputStream 的作用是标志那些从不同起源地产生输入的类。
        • 字节数组,String对象,管道,网络,文件
        • FilterInputStream,属于InputStream的一种,对作为破坏器接口使用的类进行抽象
      • ByteArrayInputStream
      • StringBufferInputStream
      • PipedInputStream :PipedOutputStream作为数据源,与PipedInputStream连接,提供一个有用的接口
      • FileInputStream:选用一个File 或FileDescriptor指出数据源
      • SequenceInputStream 将多个InputStream转化成单个InputStream
    • OutputStream类型
      • 这一类别包括的类决定了我们的输入往何处去
        • 字节数组,文件,管道,网络
        • FilterOutputStream为“破坏器”类提供了一个基础类,它将属性或者有用的接口同输出流连接起来
      • ByteArrayOutputStream
      • FileOutputStream
      • PipedOutputStream
  • 添加属性和有用的接口
    • 装饰者模式
    • 通过FilterInputStream从InputStream里读数据
      • FilterInputStream 类要完成两件全然不同的事情
        • 数据进行自动格式化:DataInputStream读取不同的基本类型数据以及String 对象
        • 修改InputStream 的内部行为方式:是否缓冲,跟踪读入的数据行,能否推回一个字节等
      • DataInputStream
      • BufferedInputStream
      • LineNumberInputStream:getNumber(),setNumber(int)
      • PushbackInputStream
    • 通过FilterOutputStream向OutputStream里写数据
      • DataOutputStream,PrintStream
      • BufferedOutputStream
    • 本身的缺陷:RandomAccessFile
    • File类
      • 它既代表一个特定文件的名字,也代表目录内一系列文件的名字。
    • IO流的典型应用
      • 输入流
        • 从技术上说,会在运行finalize()时调用close()
        • 如果不为自己的所有输出文件调用close(),就可能发现缓冲区不会得到刷新,造成它们不完整。
      • 输出流
        • writeChars(),16位Unicode字符;(readChar())writeBytes(),ASCII(readLine())
        • RandomAccessFile,实现了DataInput,DataOutput接口,seek(),有类似ByteArrayInputStream随机访问
      • 快捷文件处理
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics