《第一行代码——Java》要点摘录

  1. 第一部分 Java 基础知识
    1. 第 1 章 Java 简介
    2. 第 2 章 程序基本概念
  2. 第二部分 面向对象
    1. 第 3 章 面向对象基本概念
    2. 第 4 章 面向对象高级知识
    3. 第 5 章 包及访问控制权限
    4. 第 6 章 异常的捕获及处理
    5. 第 7 章 Eclipse 开发工具
    6. 第 8 章 Java 新特性
  3. 第三部分 Java 高级编程
    1. 第 9 章 多线程
    2. 第 10 章 Java 常用类库
    3. 第 11 章 Java IO 编程

第一部分 Java 基础知识

第 1 章 Java 简介

  1. Java 在开发上分为 Java EE(Java 企业级开发)、Java SE(Java 标准版)、Java ME(Java 嵌入式开发)。Java SE 是整个技术架构的核心。(4页)
  2. Java 语言的特性:简洁有效;可移植性;面向对象;解释型;适合分布式计算;拥有较好的性能;健壮、防患于未然;具有多线程处理能力;具有较高的安全性;是一种动态语言;是一种中性结构。(5页)
  3. 线程,是一种轻量级进程,是现代程序设计中必不可少的一种特性。多线程处理能力使得程序能够具有更好的交互性、实时性。(6页)
  4. 计算机高级语言类型主要有编译型和解释型两种,Java 是两种类型的结合。(6页)
  5. 所有的 Java 程序文件的后缀都应该是 “*.java”,而任何一个 *.java 程序首先必须经过编译,编译之后会形成一个 *.class 的文件(字节码文件),而后在计算机上执行,但是解释程序的计算机并不是一台真正意义上的计算机,而是一台由软件和硬件模拟出来的计算机——Java 虚拟机(Java Virtual Machine,JVM)。(7页)
  6. 在 Java 中所有的程序都是在 JVM 上运行的,Java 虚拟机读取并处理经过编译的与平台无关的字节码 *.class 文件。Java 解释器负责将 Java 虚拟机的代码在特定的平台上运行。(7页)
  7. Java 虚拟机的最大作用是体现在平台的支持上。所有要解释的程序都要在 JVM 上执行,并且由不同版本的 JVM 匹配不同的操作系统,这样只要 JVM 的支持不变,程序就可以任意地在不同的操作系统上运行。(7页)
  8. Java 运行环境(Java Runtime Environment,JRE)包括 Java 虚拟机、Java 核心类库和支持文件。它不包含开发工具——编译器、调试器和其他工具。而包含开发工具和编译器的为 JDK。(9页)
  9. javac.exe 是 java 本身提供的编译命令,主要目的是将 *.java 文件编译成 *.class 文件,此命令不属于 Windows,所以在使用的时候需要单独配置。(11页)
  10. 类是 Java 中的基本组成元素,而所有的 Java 程序一定要被类管理。在类前面可以有选择性地决定是否需要编写 public,所以对于类的定义有以下两种形式:(12页)
    (1)public class 定义:类名称必须和文件名称保持一致,否则程序将无法编译,在一个 *.java 中只能有一个 public class。
    (2)class 定义:类名称何以和文件名称不一致,但是生成的是 class 定义的名称。在一个 *.java 程序中可以同时存在多个 class 定义,编译之后会分为不同的 *.class 文件。
  11. 主方法 main() 表示的是一个程序起点,所有的程序代码都由此开始顺序执行,在 Java 中主方法也要放在一个类中。主方法所在的类称为主类,一般主类都使用 public class 声明。(13页)
  12. 在屏幕上显示系统输出有两种语法:(13页)
    (1)输出后加换行:System.out.println(输出内容);
    (2)输出后不加换行:System.out.print(输出内容);
  13. 在 Java 中每一个完整的语句代码都要求使用 “;” 进行结尾。(13页)
  14. 如果想要解决在不同路径下访问指定目录类的问题,可以通过配置 CLASSPATH 来解决,配置语法如下:SET CLASSPATH = *.class 文件所在的路径。(14页)
  15. CLASSPATH 主要指的是类的运行路径,实际上在用户执行 Java 命令的时候,对于本地的操作系统来说就意味着启动了一个 JVM,JVM 在运行时需要通过 CLASSPATH 加载所需要的类。而默认情况下 CLASSPATH 是指向当前目录(当前命令行窗口所在的目录)中的类,当改变之后 JVM 才会从用户指定的目录下进行类的加载。(14页)
  16. PATH 和 CLASSPATH 的区别:(15页)
    (1)PATH:是操作系统的环境属性,指的是可以执行命令的程序路径;
    (2)CLASSPATH:是所有 *.class 文件的执行路径,Java 命令执行时将利用此路径加载所需要的 *.class 文件。

第 2 章 程序基本概念

  1. 考虑到程序可维护性的特点,在编写代码时都要在每段代码上增加若干个说明文字,这些文字不需要被编译器编译,它们被称为 Java 的注释。(17页)
  2. 单行注释,就是在注释内容前面加双斜线(//),Java 编译器在进行程序编译时会忽略掉这部分信息。(17页)
  3. 多行注释,就是在注释内容前面以单斜线加一个星形标记(/*)开头,并在注释内容末尾以一个星形标记加单斜线(*/)结束。当注释内容超过一行时一般使用这种方法。(18页)
  4. 文档注释,是以单斜线加两个星形标记(/**)开头,并以一个星形标记加单斜线(*/)结束。用这种方法注释的内容会被解释成程序的正式文档,并能包含进如 javadoc 工具生成的文档里,用以说明该程序的层次结构及其方法。(18页)
  5. 标识符的定义要求:标识符由字母、数字、_、\$ 组成,其中不能以数字开头,不能是 Java 中的关键字(有些语言也称其为保留字)。(19页)
    注意:在编写的时候尽量不要去使用数字;命名尽量有意义;Java 中标识符是区分大小写的;对于 “$” 符号有特殊意义,不要去使用。
  6. 关键字全部用小写字母的形式表示。(19页)
  7. 从 JDK 1.7 开始,标识符可以使用中文定义。(20页)
  8. Java 的数据类型可分为基本数据类型与引用数据类型。其中基本数据类型包括最基本的 byte、short、int、long、float、double、char、boolean 等类型;引用数据类型包括 class、interface、array 等类型。(20页)
  9. 基本数据类型不牵扯内存分配问题,而引用数据类型需要由开发者为其分配空间,而后进行关系的匹配。(20页)
  10. 关于基本数据类型的选择:(22页)
    (1)如果要想表示整数就使用 int,表示小数就使用 double;
    (2)如果要描述日期时间数字或者表示文件或内存大小就用 long;
    (3)如果要实现内容传递或者是编码转换就用 byte;
    (4)如果要想实现逻辑的控制,就用 boolean;
    (5)如果要想处理中文,使用 char 可以避免乱码问题。
  11. 在 Java 中所有设置的整数内容默认情况下都是 int 型数据。(22页)
  12. 变量的内容是可以修改的,常量的内容是不能够修改的。变量是利用声明的方式,将内存中某个内存块保留下来以供程序使用。(22页)
  13. 变量可以用来存放数据,而使用变量之前必须先声明它的数据类型。所有的变量名称在同一块代码中只允许声明一次。(23页)
  14. 要想解决数据溢出的问题,只能通过扩大数据范围的方式来实现。(24页)
  15. 数据范围小的数据与数据范围大的数据进行数学计算时,自动向大范围的数据类型转换后计算;数据范围大的数据要变为数据范围小的数据,必须采用强制转换。(26页)
  16. Java 编译时,如果发现使用的数据变量类型为 byte,并且设置的内容在 byte 数据范围之内,就会自动帮助用户实现数据类型的转换。反之,如果超过了 byte 数据范围,则依然会以 int 型进行操作,此时就需要进行强制类型转换了。(27页)
  17. 方法中必须设置变量内容,而类中可以使用各个数据类型的默认值,声明变量时最好的选择就是为其指派默认值。(27页)
  18. Java 中只要是小数,对应的默认数据类型就是 double 型数据。所有的数据类型只有 double 或 float 才可以保存小数。如果需要将 double 型变为 float 型,需要采用强制转换。转换的方式有两种:使用字母 “F” 或 “f”;在变量或常量前使用 “(float)” 声明。(27页)
  19. Java 使用的是十六进制的 UNICODE 编码,此类编码可以保存任意的文字。(29页)
  20. 在程序中使用单引号 “’” 声明的内容称为字符。每一个单引号里面只能够保存一位字符。字符可以和 int 型互相转换(以编码的形式出现)。(29页)
  21. 布尔型是一种逻辑结果,主要保存 true、false 两类数据,这类数据主要用于一些程序的逻辑使用。Java 里面不允许使用 0 或 1 来填充布尔型的变量内容。(31页)
  22. String 属于引用数据类型(它属于一个类,在 Java 里面只要是类名称,每一个单词的首字母都是大写的),要求使用双引号 “”” 声明其内容。(31页)
  23. 在字符串的操作中,如果要改变内容,则可以使用 “+” 进行字符串的连接操作。(32页)
  24. 在基本数据类型操作中,任何数据类型都向范围大的数据类型进行转换,如果是 int 和 double,int 应该先变为 double,再进行加法计算。所有的数据类型如果遇见了 String 的 “+”,那么先变为 String 型数据,再使用 “+” 进行连接运算。(33页)
  25. 表达式由操作数与运算符组成。(33页)
  26. 根据使用的类不同,运算符可以分为赋值运算符、算术运算符、关系运算符、逻辑运算符、条件运算符、括号运算符等。(33页)
  27. 关系运算符的主要功能是进行数据的大小关系比较,返回的结果是 boolean 型数据。(36页)
  28. 三目是一种赋值运算的形式,执行三目时可以以一个布尔表达式的结果进行赋值,基本语法结构如下:(40页)

    数据类型 变量 = 布尔表达式 ? 满足此表达式时设置的内容 : 不满足此表达式时设置的内容;
  29. 逻辑运算一共包含 3 种:与(多个条件一起满足)、或(多个条件有一个满足)、非(使用 “!” 操作,可以实现 true 变 false 以及 false 变 true 的结果转换)。(41页)

  30. 十进制数据变为二进制数据的原则为:数据除 2 取余,随后倒着排列。(44页)
  31. 程序的结构包含顺序结构、选择结构、循环结构 3 种,这 3 种不同的结构有一个共同点,就是它们都只有一个入口,也只有一个出口。单一入口和出口可以让程序易读、好维护,也可以减少调试的时间。(46页)
  32. 默认情况下,switch 语句会从第一个满足的 case 语句开始执行全部的语句代码,一直到整个 switch 执行完毕或者遇见 break。在每一个 case 里出现的 break 语句,表示停止 case 的执行。(50页)
  33. do…while 表示先执行后判断,而 while 循环表示先判断后执行。如果循环条件都不满足的情况下,do…while 至少执行一次,而 while 一次都不会执行。(52页)
  34. 所有的循环语句里面都必须有循环的的初始化条件,每次循环的时候都要去修改这个条件,以判断循环是否结束。(53页)
  35. 方法(Method)是一段可以被重复调用的代码块,在很多地方又被称为函数。(59页)
  36. 如果要在程序中定义方法,Java 的命名规范为:第一个单词的首字母小写,之后每一个单词的首字母大写。(61页)
  37. 如果在方法中执行 return 语句,那么就表示其之后的代码不再执行而直接结束方法调用。如果此时方法有返回值声明,那么必须返回相应类型的数据;如果没有返回值声明,则可以直接编写 return。(62页)
  38. 方法的重载是指方法名称相同,参数的类型或个数不同,调用的时候将会按照传递的参数类型和个数完成不同方法体的执行。(63页)
  39. 在进行方法重载时一定要考虑到参数类型的统一,虽然可以实现重载方法返回不同类型的操作,但是从标准的开发来讲,建议所有重载后的方法使用同一种返回值类型。方法重载的时候重点是根据参数类型及个数来区分不同的方法,而不是依靠返回值的不同来确定的。(64页)
  40. 递归调用是一种特殊的调用形式,指的是方法自己调用自己的形式。(65页)

第二部分 面向对象

第 3 章 面向对象基本概念

  1. 在 Java 中,方法是不可以单独存在的,必须将其放在一个类中才可以。(70页)
  2. 面向过程的操作是以程序的基本功能实现为主,开发的过程中只是针对问题本身的实现,并没有很好的模块化的设计,所以在进行代码维护的时候较为麻烦。而面向对象,采用的更多的是进行子模块化的设计,每一个模块都需要单独存在,并且可以被重复利用。(70页)
  3. 面向对象的程序设计有封装性、继承性、多态性 3 个主要特性。(71页)
  4. 封装机制在程序设计中的表现是,把描述对象属性的变量及实现对象功能的方法合在一起,定义为一个程序单位,并保证外界不能任意更改其内部的属性值,也不能任意调动其内部的功能方法。(71页)
  5. 继承指首先拥有反映事物一般特性的类,然后在其基础上派生出反映特殊事物的类,是提高软件开发效率的重要手段。(71页)
  6. 被继承的类称为父类或超类,而经继承产生的类称为子类或派生类。根据继承机制,派生类继承了超类的所有成员,并相应地增加了自己的一些新的成员。(71页)
  7. 面向对象程序设计中的继承机制,大大增强了程序代码的可复用性,提高了软件的开发效率,降低了程序产生错误的可能性,也为程序的修改扩充提供了便利。(71页)
  8. 若一个子类只允许继承一个父类,称为单继承;若允许继承多个父类,称为多继承。(72页)
  9. 多态是指允许程序中出现重名现象。Java 语言中含有方法重载与对象多态两种形式的多态。(72页)
  10. 多态的特性使程序的抽象程度和简洁程度更高,有助于程序设计人员对程序的分组协同开发。(72页)
  11. 类实际上是表示一个客观世界中某类群体的一些基本特征抽象,属于抽象的概念集合,而对象表示的是一个个独立的个体。(72页)
  12. 如果要使用一个类,就一定会产生对象,每个对象之间是靠各个属性的不同来进行区分的,而每个对象所具备的操作就是类中规定好的方法。(72页)
  13. 类实际上是对象操作的模板,但是类不能直接使用,必须通过实例对象来使用。(73页)
  14. 类是由属性和方法组成的。(73页)
  15. 如果要定义类,则需要使用 class 关键字定义。类的定义语法如下:(73页)

    class 类名称{
    数据类型 属性(变量);
    ……
    public 返回值的数据类型 方法名称(参数1,参数2……){
    程序语句;
    [return 表达式;]
    }
    }
  16. 由对象调用的方法定义时不加 static,不由对象调用的方法定义时才加 static。(74页)

  17. 对象的产生格式:(74页)
    声明并实例化对象:
    类名称 对象名称 = new 类名称();
    分布完成:
    声明对象:类名称 对象名称 = null;
    实例化对象:对象名称 = new 类名称();
  18. 引用数据类型与基本数据类型最大的不同在于需要内存的开辟及使用,关键字 new 的主要功能就是开辟内存空间,即只要是想使用引用数据类型,就必须使用关键字 new 来开辟空间。(74页)
  19. 当一个对象实例化后就可以按照如下方式利用对象来操作类的结构:(74页)

    对象.属性:表示要操作类中的属性内容;
    对象.方法():表示要调用类中的方法。
  20. 堆内存(heap):保存每一个对象的属性内容,堆内存需要用关键字 new 才可以开辟,如果一个对象没有对应的堆内存指向,将无法使用;
    栈内存(stack):保存的是一块堆内存的地址数值,每一块栈内存只能够保留一块堆内存地址。(75页)

  21. 只要看见了关键字 new,不管何种情况下,都表示要开辟新的堆内存空间。(75页)
  22. 每一个对象在刚刚实例化后,里面所有属性的内容都是其对应数据类型的默认值,只有设置了属性内容之后,属性才可以保存内容。(76页)
  23. 造成 “NullPointerException” 异常的原因是在使用引用数据类型时没有为其开辟堆内存空间。(77页)
  24. 一块堆内存空间(保存对象的属性信息)可以同时被多个栈内存共同指向,即每一个栈内存都可以修改同一块堆内存空间的属性值。(78页)
  25. 每一次使用关键字 new 都一定会开辟新的堆内存空间,所以如果在代码里面声明两个对象,并且使用了关键字 new 为两个对象分别进行对象的实例化操作,那么一定是各自占有各自的堆内存空间,并且不会互相影响。(78页)
  26. 在引用的操作过程中,一块堆内存可以同时被多个栈内存所指向,但是反过来,一块栈内存只能够保存一块堆内存空间的地址。(79页)
  27. 一块没有任何栈内存指向的堆内存空间将成为垃圾,所有的垃圾会不定期地被垃圾收集器(Garbage Collector)回收,回收后会被释放掉其所占用的空间。(80页)
  28. 对象的引用会保存在栈内存(Stack)中,而对象的具体内容会保存在堆内存(Heap)中。当 GC 检测到一个堆中的某个对象不再被栈所引用时,就会不定期地对这个堆内存中保存的对象进行回收。(81页)
  29. 可以使用 private 关键字进行封装,将类中的属性进行私有化的操作。(83页)
  30. 所有在类中定义的属性都要求使用 private 声明,如果属性需要被外部所使用,那么按照要求定义相应的 setter、getter 方法。(84页)
    setter 方法主要是设置内容,有参;getter 方法主要是取得属性内容,无参。
  31. 属性使用 private 封装后的 setter、getter 是项目开发中的标准做法,getter、setter 必须同时提供。对于数据的验证部分,在标准开发中应该由其他辅助代码完成。而在实际开发中,setter 往往是简单的设置数据,getter 只是简单的取得数据而已。(85页)
  32. 构造方法本身是一种特殊的方法,它只在新对象实例化的时候调用,其定义原则是:方法名称与类名称相同,没有返回值类型声明,同时构造方法也可以进行重载。(85页)
  33. 在没有定义构造方法的时候之所以能够使用构造方法,是因为在整个 Java 类中,为了保证程序可以正常的执行,即使用户没有定义任何构造方法,也会在程序编译之后自动地为类增加一个没有参数、方法名称与类名称相同、没有返回值的构造方法。(86页)
  34. 对象实例化过程中,类名称规定了对象的类型,即对象可以使用哪些属性与方法,都是由类定义的。(86页)
  35. 在一个类中可以定义构造方法与普通方法两种类型的方法,但是这两种方法在调用时有明显的区别:(86页)
    (1)构造方法是在实例化新对象(new)的时候只调用一次;
    (2)普通方法是在实例化对象产生之后,通过 “对象.方法” 调用多次。
  36. 如果在构造方法上使用了 void,其定义的结构与普通方法就完全一样,而程序的编译是依靠定义结构来解析的,所以不能有返回值声明。(87页)
  37. 类中构造方法与普通方法的最大区别在于:构造方法是在使用关键字 new 的时候直接调用的,是与对象创建一起执行的操作;要通过普通方法进行初始化,就表示要先调用无参构造方法实例化对象,再利用对象调用初始化方法就比较啰嗦了。(87页)
  38. 构造方法的主要功能是进行对象初始化操作,所以要是希望在对象实例化时进行属性的赋值操作,则可以使用构造方法完成。(87页)
  39. 在实际的工作中,构造方法的核心作用是,在类对象实例化时设置属性的初始化内容。构造方法是为属性初始化准备的。当程序中已经明确定义一个有参构造方法时,就不会再自动生成默认的构造方法,即一个类中至少保留有一个构造方法。(88页)
  40. 编写类的时候一定要注意顺序:首先编写属性(必须封装,同时提供 getter、setter 的普通方法),然后编写构造方法,最后编写普通方法。(88页)
  41. 构造方法本身也属于方法,所以可以针对构造方法进行重载。在构造方法重载时,要求只注意参数的类型及个数即可。(88页)
  42. 在一个类中对构造方法重载时,所有重载的方法按照参数的个数由多到少,或者是由少到多排列。(89页)
  43. 在定义一个类时,可以为属性直接设置默认值,但是这个默认值只有在构造执行完才会设置,否则不会设置。(89页)
  44. 没有栈内存指向堆内存空间,就是一个匿名对象。(90页)
  45. 由于匿名对象没有对应的栈内存指向,所以只能使用一次,一次之后就将成为垃圾,并且等待被 GC 回收释放。(90页)
  46. 简单 Java 类是一种在实际开发中使用最多的类的定义形式,在简单 Java 类中包含类、对象、构造方法、private 封装等核心该概念的使用。(91页)
  47. setter 方法除了具备设置属性内容外,还具备修改属性内容的功能。(93页)
  48. 数组指的是一组相关变量的集合。数组的定义语法如下:(93页)
    声明并开辟数组:
    数据类型 数组名称[] = new 数据类型[长度]数据类型 [] 数组名称 = new 数据类型[长度]
    分步完成:
    声明数组:数据类型 数组名称[] = null;
    开辟数组:数组名称 = new 数据类型[长度]
  49. 所有数组的下标都是从 0 开始的,如果访问的时候超过了数组允许下标的长度,会出现数组越界异常(Array Index Out Of Bounds Exception)。(94页)
  50. 使用动态初始化的方式定义数组的结构,数组会首先开辟内存空间,但是数组中的内容都是其对应数据类型的默认值,如果声明的是 int 型数组,则数组里面的全部内容都是其默认值 0。(94页)
  51. 数组是一种顺序的结构,并且数组的长度都是固定的,所以可以使用循环的方式输出。Java 为了方便数组的输出,提供了一个 “数组名称.length” 的属性,可以取得数组长度。(94页)
  52. 数组保存与对象保存唯一的区别在于:对象中的堆内存保存的是属性,而数组中的堆内存保存的是一组信息。(94页)
  53. 数组本身属于引用数据类型,所以在数组的操作中依然可以进行内存空间的引用传递。(95页)
  54. 在数组定义中还提供了静态初始化的操作,即数组定义的同时就设置好了相应的数据内容,格式如下:(96页)
    简化格式:数据类型 数组名称[] = {值,值,……};
    完整格式(建议使用):数据类型 数组名称[] = new 数据类型[]{值,值,……};
  55. 数组的最大缺点:长度不能被改变。(97页)
  56. 二维数组与一维数组最大的区别在于:一维数组声明时只会有一个 “[]”,二维数组会有两个 “[]”(即 “[][]”)。(97页)
  57. 二维数组就是一张数据表(多行多列)。(97页)
  58. 如果要在二维数组里面确定一个数据,需要行和列一起定位。(97页)
  59. 二维数组的定义语法:(97页)

    动态初始化:数据类型 数组名称[][] = new 数据类型[行的个数][列的个数];
    静态初始化:数据类型 数组名称[][] = new 数据类型[][]{{值,值,值},{值,值,值}}。
  60. 二维数组实际上就是将多个一维数组变为一个大的数组,并且为每一个一维数组设置一个行号。(97页)

  61. 由于二维数组需要两个数据控制索引值,所以可以采用双层循环的方式实现内容的输出。(98页)
  62. 数组排序时,不管有多少个数据,总的排序次数不会超过数组的长度。所以只要排序的总次数达到 “长度*长度”,那么所有的数据一定可以排序成功。(100页)
  63. 在代码设计中主方法是作为程序的起点存在的,所有的程序起点都可以称为客户端。既然是客户端,所有的代码一定要简单。(101页)
  64. 要想实现数组转置的操作,首先定义一个新的数组,然后将原始数组按照倒序的方式插入到新的数组中,最后改变原始数组引用,将其指向新的数组空间。(102页)
  65. 在进行程序开发的过程中,应该尽可能少的产生垃圾空间。(102页)
  66. 数组复制可以将一个数组的部分内容复制到另外一个数组之中。其语法如下:(108页)

    System.arraycopy(源数组名称,源数组复制开始索引,目标数组名称,目标数组复制开始索引,长度);
  67. 数组排序可以按照由小到大的顺序对基本数据类型的数据进行排序。其语法如下:(108页)

    java.utils.Arrays.sort(数组名称);
  68. 数组是引用类型,而类也是引用类型,所以对象数组表示一个引用类型里面嵌套其他的引用类型。(109页)

  69. 所有的引用数据类型都可以定义数组,这样的数组称为对象数组。(109页)
  70. 对象数组的定义格式(以类为例):(109页)

    对象数组的动态初始化:类名称[] 对象数组名称 = new 类名称 [长度];
    对象数组的静态初始化:类名称[] 对象数组名称 = new 类名称 []{实例化对象,实例化对象,……};
  71. 如果使用了对象数组的动态初始化,则默认情况下,数组的每一个元素都是其对应的默认值 null,都需要分别进行对象的实例化操作。(109页)

  72. 使用对象数组的最大好处是将多个对象统一进行管理。(111页)
  73. String 本身不属于基本数据类型,也不属于引用数据类型,String 是字符串的描述类型。(111页)
  74. String 类的两种实例化方式:(111页)
    (1)直接赋值:String 变量 = “字符串”;
    (2)利用构造方法:String 变量 = new String(“字符串”);
  75. 在 Java 中,“==” 可以应用在所有数据类型中,但 “==” 并不能够实现准确的字符串比较。(113页)
  76. 在使用 “==” 比较 String 时,比较的只是内存地址的数值,并不是内容,所以只要地址数值不相同的 String 类对象在使用 “==” 比较时其结果一定返回 “false”。(113页)
  77. 在整个 Java 中只要是引用数据类型一定会存在内存地址。(113页)
  78. 如果要比较字符串的内容,可以使用 String 类里面定义的方法,内容比较操作(区分大小写)语法如下:(113页)

    public boolean equals(String str); //此方法是 String 类内部提供的比较方法,专门判断内容是否相等。
  79. String 类中 “==” 和 “equals()” 比较的区别:(114页)
    (1)“==” 是 Java 提供的关系运算符,主要的功能是进行数值相等判断,如果用在 String 对象上表示的是内存地址数值的比较;
    (2)“equals()” 是由 String 提供的一个方法,此方法专门负责进行字符串内容的比较。

  80. 任何编程语言都没有提供字符串数据类型的概念,很多编程语言里面都是使用字符数组来描述字符串的定义。同样在 Java 里面也没有字符串的概念,但由于所有的项目开发中都不可能离开字符串的应用,所以 Java 创造了属于自己的特殊类—— String(字符串),同时也规定了所有的字符串要求使用 “”” 声明,但是 String 依然不属于基本数据类型,所以字符串数据实际上是作为 String 类的匿名对象的形式存在的。(114页)
  81. String 类的匿名对象是由系统自动生成的,不再由用户自己直接创建。(114页)
  82. null 对象调用 equals() 方法的结果将直接导致 “NullPointerException”。(115页)
  83. 直接赋值就是给字符串的匿名对象设置了一个名字。(115页)
  84. 利用直接赋值还可以实现堆内存空间的重用,在内容相同的情况下不会开辟新的堆内存空间,二回直接指向已有的堆内存空间。(116页)
  85. String 类采用的设计模式为共享设计模式。在 JVM 的底层实际上会存在一个对象池(不一定只保存 String 对象),当代码中使用了直接赋值的方式定义一个 String 类对象时,会将此字符串对象所使用的匿名对象入池保存。如果后续还有其他 String 类对象也采用了直接赋值的方式,并且设置了同样的内容时,将不会开辟新的堆内存空间,而是使用已有的对象进行引用的分配,从而继续使用。(117页)
  86. 使用构造方法的方式定义的字符串对象,实际上会开辟两块空间,其中有一块空间将成为垃圾。(117页)
  87. 如果使用构造方法实例化 String 类对象,由于关键字 new 永远表示开辟新的堆内存空间,所以其内容不会保存在对象池中。可以采用手工入池的操作将开辟的新内存数据保存到对象池中,语法如下:(118页)

    public String intern();
  88. String 类的两种对象实例化方式的区别:(118页)
    (1)直接赋值只会开辟一块堆内存空间,并且会自动保存在对象池中以供下次重复使用;
    (2)构造方法会开辟两块堆内存空间,其中有一块空间将成为垃圾,并且不会自动入池,但是用户可以使用 intern() 方法手工入池。

  89. 字符串的内容一旦定义则不可改变。(118页)
  90. 对于每一个文档的内容而言,它都包含以下的 4 个主要组成部分:(120页)
    (1)第一部分:类的定义以及相关的继承结构;
    (2)第二部分:类的一些简短的说明;
    (3)第三部分:类的组成结构:

    • 类中的成员(Field Summary);
    • 类中的构造方法(Constructor Summary);
    • 类中的普通方法(Method Summary)。

    (4)第四部分:对每一个成员、构造方法、普通方法的作用进行详细说明,包括参数的作用。

  91. String 类的基本操作方法(121页)
No. 方法名称 类型 描述
1 public String(char[] value) 构造 将字符数组变为 String 类对象
2 public String(char[] value,int offset,int count) 构造 将部分字符数组变为 String 类对象
3 public char charAt(int index) 普通 返回指定索引对应的字符信息
4 public char[] toCharArray() 普通 将字符串以字符数组的形式返回
5 public String(byte[] bytes) 构造 将全部字节数组变为字符串
6 public String(byte[] bytes,int offset,int length) 构造 将部分字节数组变为字符串
7 public byte[] getBytes() 普通 将字符串变为字节数组
8 public byte[] getBytes(String CHarsetName) throws UnsupportedEncodingException 普通 进行编码转换
9 public boolean equals(String anObject) 普通 进行相等判断,区分大小写
10 public boolean equalsIgnoreCase(String anotherString) 普通 进行相等判断,不区分大小写
11 public int compareTo(String anotherString) 普通 判断两个字符串的大小(按照字符编码比较),此方法的返回值有以下 3 种结果:① = 0:表示要比较的两个字符串内容相等;② > 0:表示大于的结果;③ < 0:表示小于的结果。
12 public boolean contains(String str) 普通 判断指定的内容是否存在
13 public int indexOf(String str) 普通 由前向后查找指定字符串的位置,如果找到了则返回(第一个字母)位置索引,如果找不到返回 -1
14 public int indexOf(String str,int fromIndex) 普通 由指定位置从前向后查找指定字符串的位置,找不到返回 -1
15 public int lastIndexOf(String str) 普通 由后向前查找指定字符串的位置,找不到返回 -1
16 public int lastIndexOf(String str,int fromIndex) 普通 从指定位置由后向前查找字符串的位置,找不到返回 -1
17 public boolean startsWith(String prefix) 普通 判断是否以指定的字符串开头
18 public boolean startsWith(String prefix,int toffset) 普通 从指定位置开始判断是否以指定的字符串开头
19 public boolean endsWith(String suffix) 普通 判断是否以指定的字符串结尾
20 public String replaceAll(String regex,String replacement) 普通 用新的内容替换全部旧的内容
21 public String replaceFirst(String regex,String replacement) 普通 替换首个满足条件的内容
22 public String substring(int beginIndex) 普通 从指定索引截取到结尾
23 public String substring(int beginIndex,int endIndex) 普通 截取部分子字符串的数据
24 public String[] split(String regex) 普通 按照指定的字符串进行全部拆分
25 public String[] split(String regex,int limit) 普通 按照指定的字符串进行部分拆分,拆分的数组个数由 limit 决定(如果能拆分的结果很多,数组个数才会由 limit 决定),即前面拆,后面不拆
26 public String concat(String str) 普通 字符串连接,与 “+” 类似
27 public String toLowerCase() 普通 转小写
28 public String toUpperCase() 普通 转大写
29 public String trim() 普通 去掉字符串中左右两边的空格,中间空格保留
30 public int length() 普通 取得字符串长度
31 public String intern() 普通 数据入池
32 public boolean isEmpty() 普通 判断是否是空字符串(不是 null,而是 “”,长度0)
  1. 在 Java 开发中,针对返回 boolean 值的方法习惯性以 “isXxx()” 的形式命名。(125页)
  2. 字节一般主要用于数据的传输或编码的转换。(125页)
  3. 在 String 类中 substring() 方法传递的参数只能是正整数,不能是负数。(130页)
  4. 空字符串(不是 null)指的是长度为 0 的字符串数据,利用 isEmpty() 方法可以实现判断。(135页)
  5. 在 Java 中,this 关键字可以完成 3 件事情:调用本类属性,调用本类方法,表示当前对象。(136页)
  6. 在一个类中定义的方法可以直接访问类中的属性,但是很多时候有可能会出现方法参数名称与属性名称重复的情况,所以此时就需要利用 “this.属性” 的形式明确地指明要调用的是类中的属性而不是方法的参数。(136页)
  7. 为了减少不必要的麻烦,在类中访问属性时不管是否有重名的变量,一定要加上 “this”。(137页)
  8. 在一个构造中要调用其他构造,可以使用 “this()” 调用。(138页)
  9. 在使用 this 调用构造方法时,存在两个重要的限制:(140页)
    (1)使用 “this()” 调用构造方法形式的代码只能够放在构造方法的首行;
    (2)进行构造方法互相调用时,一定要保留调用的出口(至少保留一个构造没有使用 this() 调用其他构造)。
  10. 当前对象指的就是当前正在调用类中方法的实例化对象。(143页)
  11. 引用传递的核心意义是:同一块堆内存空间可以被不同的栈内存所指向,不同栈内存可以对同一堆内存进行内容的修改。(144页)
  12. 字符串内容不可改变,String 类对象内容的改变是通过引用的变更实现的。(146页)
  13. 基本数据类型在进行参数传递时使用的是值传递。(147页)
  14. 引用是实现两个不同类型之间互相关联的主要手段。(153页)
  15. 如果有一个自定义的类,要想判断它的两个对象是否相等,那么必须要实现类对象中所有属性内容的比较。(156页)
  16. 如果一个类中的属性使用了 private 封装,那么在类的外部不能通过对象直接调用属性。但是如果将一个对象传递回类的方法里,就相当于取消了封装的形式,可以直接通过对象访问属性。(158页)
  17. 进行本类对象的比较操作时,首先会判断传入的对象是否为 null,然后判断地址是否相同,如果都不相同则进行对象内容的判断。(158页)
  18. 当一个类接收了本类对象的引用后,可以直接调用本类中的私有化操作。(159页)
  19. 对象比较的操作有如下 4 个特点:(159页)
    (1)本类接收自己的引用,再与本类当前对象(this)进行比较;
    (2)为了避免 NullPointerException 的产生,应该增加一个 null 的判断;
    (3)为了防止浪费性能的情况出现(要判断的属性会多),可以增加地址数值的判断,因为相同的对象地址相同;
    (4)进行属性的依次比较,如果属性全部相同,则返回 true,否则返回 false。
  20. 如果类中的某个属性希望定义为公共属性(所有对象都可以使用的属性),则可以在声明属性前加上 static 关键字。有任何一个对象修改了此属性的内容都将影响其他对象。(160页)
  21. 在 Java 中主要存在 4 块内存空间,这些内存空间的名称及作用如下:(161页)
    (1)栈内存空间:保存所有的对象名称(保存引用的堆内存空间的地址);
    (2)堆内存空间:保存每个对象的具体属性内容;
    (3)全局数据区:保存 static 类型的属性;
    (4)全局代码区:保存所有的方法定义。
  22. 利用 static 定义的属性是可以由类名称直接调用的。static 属性的一个特征:虽然定义在类结构里面,但是并不受到对象的控制,是独立于类存在的。(161页)
  23. static 属性与非 static 属性有一个最大的区别:所有的非 static 属性必须产生实例化对象才可以访问,但是 static 属性不受实例化对象的控制,也就是说,在没有实例化对象产生的情况下,依然可以使用 static 属性。(161页)
  24. 一般只有在描述共享属性概念或者是不受实例化对象控制的属性才会使用 static 定义属性。(162页)
  25. 在定义类的普通方法时可以使用 static 进行定义,使用 static 定义的方法也可以在没有实例化对象产生的情况下由类名称直接进行调用。(162页)
  26. static 方法和非 static 方法间的访问受到如下限制:(163页)
    (1)static 方法不能直接访问非 static 属性或方法,只能调用 static 属性或方法;
    (2)非 static 方法可以访问 static 的属性或方法,不受任何的限制。
  27. 所有的非 static 定义的结构,必须在类已经明确产生实例化对象时才会分配堆内存空间,才可以使用;
    所有的 static 定义的结构,不受实例化对象的控制,即可以在没有实例化对象的时候访问。(163页)
  28. 产生实例化对象是因为在堆内存中可以保存属性信息,所以如果一个类中没有属性产生,就自然也没有必要去开辟堆内存保存属性内容了,所以这个时候就可以考虑类中的方法全部使用 static 声明。(164页)
  29. static 关键字具备如下特点:(165页)
    (1)不管有多少个对象,都使用同一个 static 属性;
    (2)使用 static 方法可以避免实例化对象调用方法的限制。
  30. 在程序编写中可以直接使用 “{}” 定义一段语句,根据此部分定义的位置以及声明的关键字的不同,代码块一共可以分为 4 种:普通代码块、构造块、静态块、同步代码块。(167页)
  31. 如果一个代码块写在方法里,就称它为普通代码块。(167页)
  32. 如果将一个代码块写在一个类里,这个代码块就称为构造块。(168页)
  33. 如果一个代码块使用 static 进行定义,就称其为静态块。(168页)
  34. 当有多个实例化对象产生时,静态块会优先调用,而且只调用一次。静态块的主要作用一般可以为 static 属性初始化。(169页)
  35. 静态块优先于主方法执行。(170页)
  36. 内部类指的就是一个类的内部继续定义其他内部结构类的情况。(170页)
  37. 内部类的最大好处是可以轻松地访问外部类中的私有属性。(171页)
  38. 外部类也可以通过内部类对象轻松地访问内部类的私有属性。(172页)
  39. 所有的 “$” 是在文件中的命名,如果反映到程序中就变为 “.”。(173页)
  40. 如果一个内部类只希望被一个外部类访问,不能被外部调用,那么可以使用 private 定义私有内部类。(174页)
  41. 使用 static 定义的属性或方法是不受类实例化对象控制的,所以如果使用 static 定义内部类,它一定不可能受到外部类的实例化对象控制。(174页)
  42. 如果一个内部类使用 static 定义,那么这个内部类就变为一个 “外部类”,并且只能访问外部类中定义的 static 操作。相当于定义一个外部类。(174页)
  43. 实例化内部类的操作有如下两种格式:(175页)
    (1)非 static 定义内部类:外部类.内部类 内部类对象 = new 外部类().内部类()。
    (2)static 定义内部类:外部类.内部类 内部类对象 = new 外部类.内部类()。
  44. 内部类理论上可以在类的任意位置上进行定义,包括在代码块中,或在普通方法中。(175页)
  45. 在方法中定义的内部类从 JDK 1.8 开始也可以直接访问方法中的参数或变量了。在 JDK 1.7 及之前的版本有一个严格要求:方法中定义的内部类如果要想访问方法的参数或方法定义的变量,在参数或变量前一定要加上 “final” 标记。(176页)
  46. 链表是一种最为简单地数据结构,它的主要目的是依靠引用关系来实现多个数据的保存。(178页)
  47. 链表的基本操作有如下特点:(182页)
    (1)客户端代码不用关注具体的 Node 以及引用关系的细节,只需要关注 Link 类中提供的数据操作方法;
    (2)Link 类的主要功能是控制 Node 类对象的产生和根节点;
    (3)Node 类主要负责数据的保存以及引用关系的分配。
  48. 链表的基础功能(184页)
No. 方法名称 类型 描述
1 public void add(数据类型 变量) 普通 向链表中增加新的数据
2 public int size() 普通 取得链表中保存的元素个数
3 public boolean isEmpty() 普通 判断是否是空链表(size()==0)
4 public boolean contains(数据类型 变量) 普通 判断某一个数据是否存在
5 public 数据类型 get(int index) 普通 根据索引取得数据
6 public void set(int index,数据类型 变量) 普通 使用新的内容替换指定索引的旧内容
7 public void remove(数据类型 变量) 普通 删除指定数据,如果是对象则要进行对象比较
8 public 数据类型 [] toArray() 普通 将链表以对象数组的形式返回
9 public void clear() 普通 清空链表
  1. 空链表(不是 null)指的是链表中不保存任何数据。(187页)
  2. 链表本身就属于一种动态地对象数组,与普通的对象数组相比,链表最大的优势就在于没有长度限制。(189页)

第 4 章 面向对象高级知识

  1. 继承性要解决的就是代码重用的问题,利用继承性可以从已有的类继续派生出新的子类。(204页)
  2. 继承性严格来讲就是指扩充一个类已有的功能。(205页)
  3. 在 Java 中,如果要实现继承的关系,可以使用如下语法:(205页)

    class 子类 extends 父类 {}

    (1)对于 extends 而言,应该翻译为扩充,但是为了理解方便,统一将其称为继承;
    (2)子类又被称为派生类;
    (3)父类又被称为超类(Super Class)。

  4. 子类即使不扩充父类,也属于维持功能的状态。(206页)
  5. 子类实际上是将父类定义得更加具体化的一种手段。父类表示的范围大,而子类表示的范围小。(207页)
  6. Java 不允许多重继承,但是允许多层继承。从实际的开发角度讲,类之间的继承关系最多不要超过三层。(208页)
  7. 子类在继承父类时,严格来讲会继承父类中的全部操作,但是对于所有的私有操作属于隐式继承,而所有的非私有操作属于显式继承。(208页)
  8. 在子类对象构造前一定会默认调用父类的构造(默认使用无参构造),以保证父类的对象先实例化,子类对象后实例化。对于子类的构造而言,就相当于隐含了 super() 语句的调用,由于 super() 主要是调用父类的构造方法,所以必须放在子类构造方法的首行。当父类中提供有无参构造方法时,是否编写 super() 没有区别。但是如果父类中没有无参构造方法,则必须明确地使用 super() 调用父类指定参数的构造方法。(208页)
  9. this() 与 super() 均必须编写在构造方法的第一行,所以不能同时存在于同一个构造方法内。(210页)
  10. 当子类定义了和父类的方法名称、返回值类型、参数类型及个数完全相同的方法时,就称为方法的覆写。(211页)
  11. 一个类可能会产生多个子类,每个子类都可能会覆写父类中的方法,这样一个方法就会根据不同的子类有不同的实现效果。(212页)
  12. 如果子类覆写了方法,并且实例化了子类对象,调用的一定是被覆写过的方法。(212页)
  13. 如果发现父类中的方法名称功能不足(不适合本子类对象操作),但是又必须使用这个方法名称时,就需要采用覆写这一概念实现。(213页)
  14. 被子类所覆写的方法不能拥有比父类更严格的访问控制权限。(213页)
  15. 为了能够明确地由子类调用父类中已经被覆写的方法,可以使用 super.方法() 来进行访问。super.方法() 可以放在子类方法的任意位置。(216页)
  16. 在发生重载关系时,返回值可以不同,但是考虑到程序设计的统一性,重载时应尽量保证方法的返回值类型相同。(216页)
  17. 父类方法使用 private 权限,对子类不可见。(216页)
  18. 使用 this.方法() 会首先查找本类中是否存在要调用的方法名称,如果存在则直接调用,如果不存在则查找父类中是否有此方法,如果有就调用,如果没有则会发生编译时错误。(217页)
  19. 方法重载与覆写的区别(217页)
No. 区别 重载 覆写
1 英文单词 Overloading Override
2 发生范围 发生在一个类中 发生在继承关系中
3 定义 方法名称相同、参数的类型及个数不同 方法名称相同、参数的类型、个数相同、方法返回值相同
4 权限 没有权限的限制 被覆写的方法不能拥有比父类更为严格的访问控制权限
  1. 如果子类定义了和父类完全相同的属性名称时,就称为属性的覆盖。(217页)
  2. this 与 super 的区别(218页)
No. 区别 this super
1 功能 调用本类构造、本类方法、本类属性 子类调用父类构造、父类方法、父类属性
2 形式 先查找本类中是否存在有指定的调用结构,如果有则直接调用,如果没有则调用父类定义 不查找子类,直接调用父类操作
3 特殊 表示本类的当前对象
  1. 一般开发中子类的编写思路:(221页)
    (1)绝对不改变客户端已有的使用方法;
    (2)子类为了维持方法的功能继续完善,必须要根据情况进行父类方法的覆写。
  2. 反转类指的是在进行数组数据取得时,可以实现数据的首尾交换。(222页)
  3. 子类可以随意地扩充方法, 但是如果是子类扩充的方法,那么这个方法只能由子类对象来调用,父类对象将不知道这个方法的定义。(223页)
  4. 在 Java 中 final 称为终结器,可以使用 final 定义类、方法和属性。(223页)
  5. 使用 final 定义的类不能再有子类,任何类都不能继承以 final 声明的父类。(223页)
  6. String 也是使用 final 定义的类,所以 String 类不允许被继承。(223页)
  7. 使用 final 定义的方法不能被子类所覆写。(223页)
  8. 使用 final 定义的变量就成为了常量,常量必须在定义的时候设置好内容,并且不能修改。代码中定义常量的最大意义在于:使用常量可以利用字符串(常量名称)来更直观地描述数据。(224页)
  9. 常量名称使用全部字母大写的形式,这是 Java 的命名规范。(224页)
  10. 全局常量指的是利用了 “public” “static” “final” 3个关键字联合定义的常量。(224页)
  11. 在定义常量时必须对其进行初始化赋值,否则将出现语法错误。(224页)
  12. 多态性在开发中可以体现在两个方面:(224页)
    (1)方法的多态性:重载与覆写;
    |-重载:同一个方法名称,根据不同的参数类型及个数可以完成不同的功能;
    |-覆写:同一个方法,根据实例化的子类对象不同,所完成的功能也不同。
    (2)对象的多态性:父子类对象的转换;
    |-向上转型:子类对象变为父类对象,格式:父类 父类对象 = 子类实例,自动转换;
    |-向下转型:父类对象变为子类对象,格式:子类 子类对象 = (子类) 父类实例,强制转换。
  13. 向下转型操作本身是有前提条件的,即必须发生向上转型后才可以发生向下转型。如果是两个没有关系的类对象发生强制转换,就会出现 “ClassCastException” 异常(类转换异常)。(226页)
  14. 在实际开发中,对象向上转型的主要意义在于参数的统一,也是最为主要的用法,而对象的向下转型指的是调用子类的个性化操作方法。(227页)
  15. 当发生继承关系后,父类对象可以使用的方法必须在父类中明确定义。(228页)
  16. 向上转型:其目的是参数的统一,但是向上转型中,通过子类实例化后的父类对象所能调用的方法只能是父类中定义过的方法;
    向下转型:其目的是父类对象要调用实例化它的子类中的特殊方法,但是向下转型是需要强制转换的,这样的操作容易带来安全隐患。(229页)
  17. 利用关键字 instanceof 可以判断某一个对象是否是指定类的实例,使用格式如下:(229页)

    对象 instanceof 类 (返回 boolean 型,如果某个对象是某个类的实例,就返回 true,否则就返回 false)
  18. null 在使用 instanceof 判断时返回的结果为 false。(229页)

  19. 在进行向下转型时建议都使用 instanceof 判断。(229页)
  20. 利用抽象类可以明确地定义子类需要覆写的方法。(230页)
  21. 普通类可以直接产生实例化对象,并且在普通类中可以包含构造方法、普通方法、static 方法、常量、变量的内容。抽象类就是指在普通类的结构里面增加抽象方法的组成部分,抽象方法指的是没有方法体的方法,同时抽象方法还必须使用 abstract 关键字进行定义。拥有抽象方法的类一定属于抽象类,抽象类要使用 abstract 声明。(230页)
  22. 所有的普通方法上面都会有一个 “{}” 来表示方法体,有方法体的方法一定可以被对象直接调用。抽象类中的抽象方法没有方法体,声明时不需要加 “{}”,但是必须有 abstract 声明,否则在编译时将出现语法错误。(231页)
  23. 抽象类只是比普通类多了抽象方法的定义,其他结构与普通类完全一样。(231页)
  24. 抽象类不能进行直接的对象实例化操作。依靠对象的向上转型概念,可以通过抽象类的子类完成抽象类的实例化对象操作。(231页)
  25. 抽象类必须有子类,即每一个抽象类一定要被子类所继承(使用 extends 关键字),但是在 Java 中每一个子类只能够继承一个抽象类,所以具备单继承局限。(231页)
  26. 抽象类的子类(子类不是抽象类)必须覆写抽象类中的全部抽象方法(强制子类覆写)。(231页)
  27. 普通类最好不要继承另外一个普通类,而是继承抽象类。(232页)
  28. 抽象类里面由于会存在一些属性,那么在抽象类中一定会存在构造方法,目的是为属性初始化,并且子类对象实例化时依然满足先执行父类构造再调用子类构造的情况。(232页)
  29. 抽象类不能使用 final 定义,因为抽象类必须有子类,而 final 定义的类不能有子类。(233页)
  30. 抽象类中可以没有任何抽象方法,但是只要是抽象类,就不能直接使用关键字 new 实例化对象。(233页)
  31. 抽象类中依然可以定义内部的抽象类,而实现的子类也可以根据需要选择是否定义内部类来继承抽象类。(233页)
  32. 外部抽象类不允许使用 static 声明,而内部的抽象类允许使用 static 声明,使用 static 声明的内部抽象类就相当于是一个外部抽象类,继承的时候使用 “外部类.内部类” 的形式表示类名称。(233页)
  33. 在抽象类中,如果定义了 static 属性或方法时,就可以在没有对象的时候直接调用。(234页)
  34. 在任何一个类的构造执行完前,所有属性的内容都是其对应数据类型的默认值。(235页)
  35. 抽象类的最主要特点相当于制约了子类必须覆写的方法,同时抽象类中也可以定义普通方法,而且最为关键的是,这些普通方法定义在抽象类时,可以直接调用类中定义的抽象方法,但是具体的抽象方法内容就必须由子类来提供。(236页)
  36. 如果一个类只是由抽象方法和全局常量组成的,那么在这种情况下不会将其定义为一个抽象类,而只会将其定义为接口。所谓的接口严格来讲就属于一个特殊的类,而且这个类里面只有抽象方法与全局常量。在 Java 中可以使用 interface 关键字来实现接口的定义。(240页)
  37. 由于接口中存在抽象方法,所以接口对象不可能直接使用关键字 new 进行实例化的操作。接口具有以下使用原则:(241页)
    (1)接口必须要有子类,但是此时一个子类可以使用 implements 关键字实现多个接口,避免单继承局限;
    (2)接口的子类(如果不是抽象类),必须要覆写接口中的全部抽象方法;
    (3)接口的对象可以利用子类对象的向上转型进行实例化操作。
  38. 在接口里面只能使用一种访问权限——public。即便在接口的方法中没有写 public,其最终的访问权限也是 public,绝对不会是 default(默认)权限。强烈建议在接口定义方法时写上 public。(241页)
  39. 如果一个子类既要继承抽象类又要实现接口,那么应该采用先继承(extends)后实现接口(implements)的顺序完成。(243页)
  40. 一个抽象类可以继承一个抽象类或者实现若干个接口,一个接口却不能继承抽象类。一个接口可以使用 extends 关键字同时继承多个父接口。(243页)
  41. 在一个接口内部如果使用 static 去定义一个内部接口,该接口就表示是一个外部接口。(244页)
  42. 良好的代码编写风格应该遵从以下标准:(248页)
    (1)客户端调用简单,不需要关注具体的细节;
    (2)程序代码的修改,不影响客户端的调用,即使用者可以不去关心代码是否变更。
  43. 耦合度太高的代码不方便维护,就相当于 A 一直要与 B 绑定在一起。(248页)
  44. 代理设计模式就是指一个代理主题来操作真实主题,真实主题执行具体的业务操作,而代理主题负责其他相关业务的处理。(250页)
  45. 抽象类与接口的比较(252页)
No. 区别 抽象类 接口
1 关键字 abstract class interface
2 组成 构造方法、普通方法、抽象方法、static 方法、常量、变量 抽象方法、全局常量
3 子类使用 class 子类 extends 抽象类 class 子类 implements 接口,接口,……
4 关系 抽象类可以实现多个接口 接口不能继承抽象类,却可以继承多个父接口
5 权限 可以使用各种权限 只能使用 public 权限
6 限制 单继承局限 没有单继承局限
7 子类 抽象类和接口都必须有子类,子类必须要覆写全部的抽象方法
8 实例化对象 依靠子类对象的向上转型进行对象的实例化
  1. 在进行某些公共操作时一定要定义出接口;有了接口就需要利用子类完善方法;如果是自己写的接口,那么绝对不要使用关键字 new 直接实例化接口子类,应该使用工厂类完成。(252页)
  2. Object 类是所有类的父类,也就是说任何一个类在定义时如果没有明确地继承一个父类,那它就是 Object 类的子类。(254页)
  3. 利用 Object 类可以接收全部类的对象,因为可以向上自动转型。(254页)
  4. 在设计代码时,如果不确定参数类型,使用 Object 类应该是最好的选择。(254页)
  5. 在子类对象实例化时都会默认调用父类中的无参构造方法。(254页)
  6. 对于任意一个简单的 Java 类而言,理论上应该覆写 Object 类中的 3 个方法:(254页)
    public String toString()
    public boolean equals(Object obj)
    public int hashCode()

这 3 个方法都将默认在 Object 的子类继承(所有类都继承),但是要根据具体的情况来选择覆写哪个方法。

  1. 在输出一个对象时不管是否调用 toString(),其最终都是调用 toString() 将对象信息转换为 String 进行输出,而在 Object 类中的 toString() 方法设计时,由于要考虑其可以满足所有对象的输出信息,所以默认返回的是对象的编码。(256页)
  2. 覆写了 toString() 方法后,在进行对象输出时,就可以发现会自动调用对象所在类的 toString() 方法将对象变为字符串后输出。(256页)
  3. 在 Object 类中,默认的 equals() 方法实现比较的是两个对象的内存地址数值。(256页)
  4. Object 类实际上是可以接收所有引用数据类型的数据,这就包括数组、接口、类。(257页)
  5. 数组直接输出的对象信息,都会带有一个 “[” 的标记,第二位是数组类型的标记。(258页)
  6. 接口不会继承任何类,所以也不会继承 Object,而之所以可以使用 Object 接收,是因为接口属于引用数据类型。(258页)
  7. 内部类指的是在一个类的内部定义了另外的类结构,利用内部类可以方便地实现私有属性的互相访问,但是内部类需要明确地使用 class 进行定义。而匿名内部类是没有名字的内部类,其必须在抽象类或接口基础上才可以定义。(269页)
  8. Java 在设计中有一个基本原则,即一切皆对象,也就是说一切操作都要求用对象的形式进行描述。(270页)
  9. Java 专门给出了一组包装类,来包装 8 种基本数据类型:byte(Byte)、short(Short)、int(Integer)、long(Long)、float(Float)、double(Double)、char(Character) 和 boolean(Boolean)。包装类可以分为以下两种子类型:(271页)
    (1)对象型包装类(Object 直接子类):Character、Boolean。
    (2)数值型包装类(Number 直接子类):Byte、Short、Integer、Long、Float、Double。
  10. Number 是一个抽象类,里面一共定义了 6 个操作方法:intValue()、doubleValue()、floatValue()、byteValue()、shortValue()、longValue()。(271页)
  11. 基本数据类型与包装类之间的转换可以通过以下方式定义:(271页)
    (1)装箱操作:将基本数据类型变为包装类的形式(每个包装类的构造方法都可以接收各自数据类型的变量);
    (2)拆箱操作:从包装类中取出被包装的数据(利用从 Number 类中继承而来的一系列 xxxValue() 方法完成。
  12. 从 JDK 1.5 开始,Java 为了方便代码开发,提供了自动装箱与自动拆箱的机制。(272页)
  13. 可以直接利用包装类进行数学计算。(272页)
  14. 如果使用直接装箱实例化的方式,会使用同一块堆内存空间,而使用了构造方法实例化的包装类对象,会开辟新的堆内存空间,而在进行包装类数据相等比较时,最可靠的方法依然是 equals()。(273页)
  15. 利用 Object 接收基本数据类型的流程是:基本数据类型 → 自动装箱(成为对象) → 向上转型为 Object。(273页)
  16. Object 不可能直接向下转型为 int,所以要取出基本数据类型必须首先向下转型为指定的包装类。(273页)
  17. Object 类对象并不具备直接的数学计算功能。如果要想将 Object 类中的包装数据取出,必须将其强制转换为包装类后才可以利用自动拆箱完成。(273页)
  18. 包装类默认值为 null,而基本数据类型有具体内容。(274页)
  19. 使用包装类最多的情况实际上是它的数据类型转换功能,在包装类里面提供了将 String 型数据变为基本数据类型的方法。(275页)
  20. 在 String 型数据转换为 boolean 类型数据时,如果要转换的字符串不是 true 或 false,将统一按照 false 进行处理。在字符串转换为 boolean 数据类型的操作中永远不会出现转换异常。(276页)
  21. 任何数据类型遇见 “+” 都会变为字符串进行连接处理(如果是引用数据类型会调用 toString() 转换后进行连接)。(277页)
  22. 利用 String 类中提供的方法:public static String valueOf(数据类型 变量) 可以将基本数据类型变为 String 型数据。(277页)

第 5 章 包及访问控制权限

  1. 在 Java 程序中的包主要用于将不同功能的文件进行分割。在不同的目录下可以有重名文件。所谓的包实际上指的就是文件夹。在 Java 中使用 package 关键字来定义包,此语句必须写在 *.java 文件的首行。(282页)
  2. 在实际的开发过程中,所有的类都一定要放在一个包中,而完整的类名称永远都是 “包.类”,同时没有包的类不应该在开发中出现。在定义包时出现 “.”,就表示子目录。(283页)
  3. 不同包之间进行互相访问,需要使用包的导入(import 语句)操作。(283页)
  4. 如果一个程序定义在包中,并且需要引入其他程序类,那么 import 语句必须写在 package 语句之后,同时 import 语句应该编写在类的定义之前。(284页)
  5. public class 与 class 声明类的区别:(285页)
    (1)public class:文件名称必须与类名称保持一致,在一个 *.java 文件里面只能有一个 public class 声明,如果一个类需要被不同的包访问,那么一定要定义为 public class;
    (2)class:文件名称可以与类名称不一致,并且一个 *.java 文件里面可以有多个 class 定义,编译后会形成多个 *.class 文件,如果一个类使用的是 class 定义,那么表示这个类只能被本包所访问。
  6. 可以使用 “import 包.*” 的方式来代替一个包中多个类的导入操作。(285页)
  7. 即便代码中使用了 “import 包.*” 的操作,也不会将本包中的所有类都导入进来,类加载时也只是加载所需要的类,不使用的类不会被加载。(286页)
  8. 如果两个包中有同样的类名称,为了可以明确地找到所需要的类,可以在使用类时加上包名称。如果觉得导包操作会造成冲突,那么就在实例化对象的时候写上完整的类名称(包.类)。(287页)
  9. 系统常见包(287页)
No. 包名称 作用
1 java.lang 基本的包,像 String 这样的类就都保存在此包中,此包现在为自动导入
2 java.lang.reflect 反射机制的包,是 java.lang 的子包
3 java.util 工具包,一些常用的类库、日期操作等都在此包中
4 java.text 提供了一些文本的处理类库,国际化处理程序包
5 java.sql 数据库操作包,提供了各种数据库操作的类和接口
6 java.net 完成网络编程
7 java.io 输入、输出及文件处理操作处理
8 java.awt 包含构成抽象窗口工具集(abstract window toolkits)的多个类,这些类被用来构建和管理应用程序的图形用户界面(GUI)
9 javax.swing 用于建立图形用户界面,此包中的组件相对于 java.awt 包而言是轻量级组件
10 java.util.regex 正则工具包
  1. 使用 jar 命令针对 *.class 文件进行压缩,最终交付用户使用的是 Java 归档(Java Archive,jar)文件。(288页)
  2. 4 种访问控制权限(289页)
No. 范围 private default protected public
1 在同一包的同一类
2 同一包的不同类
3 不同包的子类
4 不同包的非子类
  1. private 只能在一个类中访问;default 只能在一个包中访问;protected 在不同包的子类中访问;public 为所有都可以。(289页)
  2. 属性声明主要使用 private 权限;方法声明主要使用 public 权限。(290页)
  3. Java 命名规范:(291页)
    (1)类名称:每一个单词的开头首字母大写;
    (2)变量名称:第一个单词的首字母小写,之后每个单词的首字母大写;
    (3)方法名称:第一个单词的首字母小写,之后每个单词的首字母大写;
    (4)常量名称:每个字母大写;
    (5)包名称:所有字母小写。
  4. 对于构造方法也可以使用 private 声明,此时的构造方法就被私有化。(291页)
  5. 如果一个类中没有明确地定义一个构造方法,则会自动生成一个无参的、什么都不做的构造方法。(291页)
  6. 如果要控制一个类中实例化对象的产生个数,首先要锁定的就是类中的构造方法(使用 private 定义构造方法),因为在实例化任何新对象时都要使用构造方法,如果构造方法被锁,就自然无法产生新的实例化对象。(293页)
  7. 单例设计模式有两种形式:饿汉式和懒汉式。(295页)
  8. 单例设计模式只留下一个类的一个实例化对象,而多例设计模式会定义出多个对象。(295页)

第 6 章 异常的捕获及处理

  1. 在 Java 中,程序的错误主要是语法错误、语义错误。(299页)
  2. 异常是程序中导致程序中断的一种指令流。(299页)
  3. 程序没有进行异常的处理时,默认情况下,会进行异常信息打印,同时将终止执行异常产生之后的代码。(300页)
  4. Java 针对异常的处理提供了 3 个核心的关键字:try、catch、finally。利用这 3 个关键字就可以组成以下异常处理格式:(300页)

    try{
    //有可能出现异常的语句
    }[catch(异常类型 对象){
    //异常处理;
    }catch(异常类型 对象){
    //异常处理;
    }catch(异常类型 对象){
    //异常处理;
    }……][finally{
    ;不管是否出现异常,都执行统一的代码
    }]
  5. 在 try 语句中捕获可能出现的异常代码。如果在 try 中产生了异常,则程序会自动跳转到 catch 语句中找到匹配的异常类型进行相应的处理。不管程序是否会产生异常,都会执行到 finally 语句,finally 语句就作为异常的统一出口。finally 块是可以省略的,如果省略了 finally 块不写,则在 catch() 块运行结束后,程序将继续向下执行。(300页)

  6. catch 与 finally 都是可选的。异常格式的组合,往往有 3 种:try…catch、try…catch…finally、try…finally。(300页)
  7. 为了能够进行异常的处理,可以使用异常类中提供的 printStackTrace() 方法进行异常信息的完整输出。所有的异常类中都会提供 printStackTrace() 方法,而利用这个方法输出的异常信息,会明确地告诉用户是代码中的第几行出现了异常,这样非常方便用户进行代码的调试。(301页)
  8. finally 往往是在开发中进行一些资源释放操作的。(303页)
  9. 所有的异常类型最高的继承类是 Throwable,并且在 Throwable 下有两个子类。(305页)
    (1)Error:指的是 JVM 错误,这时的程序并没有执行,无法处理;
    (2)Exception:指的是程序运行中产生的异常,用户可以使用异常处理格式处理。
  10. Java 中异常的处理完整流程(305页)
    异常处理完整流程
    (1)当程序在运行的过程中出现了异常,会由 JVM 自动根据异常的类型实例化一个与之类型匹配的异常类对象(此处不用关心如何实例化对象,由 JVM 负责处理)。
    (2)产生异常对象后会判断当前的语句是否存在异常处理,如果现在没有异常处理,就交给 JVM 进行默认的异常处理,处理的方式:输出异常信息,而后结束程序的调用。
    (3)如果此时存在异常的捕获操作,那么会先由 try 语句来捕获产生的异常类实例化对象,再与 try 语句后的每一个 catch 进行比较,如果有符合的捕获类型,则使用当前 catch 的语句来进行异常的处理,如果不匹配,则向下继续匹配其他 catch。
    (4)不管最后异常处理是否能够匹配,都要向后执行,如果此时程序中存在 finally 语句,就先执行 finally 中的代码。执行完 finally 语句后需要根据之前的 catch 匹配结果来决定如何执行,如果之前已经成功地捕获了异常,就继续执行 finally 之后的代码。如果之前没有成功地捕获异常,就将此异常交给 JVM 进行默认处理(输出异常信息,而后结束程序执行)。

  11. 所有异常类对象都可以向父类对象转型,也就证明所有的异常类对象都可以使用 Exception 来接收,这样就可以简单地实现异常处理了。(306页)

  12. 处理多个异常时,捕获范围小的异常要放在捕获范围大的异常之前处理。(307页)
  13. throws 关键字主要在方法定义上使用,表示此方法中不进行异常的处理,而是交给被调用处处理。(如果在方法中处理也可以)(308页)
  14. 调用具有 throws 声明的方法时,不管调用方法时是否会产生异常,都必须进行异常处理操作。(308页)
  15. 主方法上也可以使用 throws 抛出。在主方法上如果使用了 throws 抛出,就表示在主方法里面可以不用强制性地进行异常处理,如果出现了异常,将交给 JVM 进行默认处理,则此时会导致程序中断执行。主方法上不建议使用 throws,因为如果程序出现了错误,也希望其可以正常结束调用。(309页)
  16. 通过 throw 关键字可以手工抛出一个实例化对象(手工调用异常类的构造方法)。(309页)
  17. throw 和 throws 的区别:(310页)
    (1)throw:指的是在方法中人为抛出一个异常类对象(这个异常类对象可能是自己实例化或者是抛出已存在的);
    (2)throws:在方法的声明上使用,表示此方法在调用时必须处理异常。
  18. RuntimeException 异常类的最大特征是:程序在编译时不会强制性地要求用户处理异常,用户可以根据自己的需要有选择地进行处理,但是如果没有处理又发生了异常,将交给 JVM 默认处理。也就是说 RuntimeException 的子异常类,可以由用户根据需要有选择地进行处理。(312页)
  19. RuntimeException 和 Exception 的区别:RuntimeException 是 Exception 的子类;Exception 定义了必须处理的异常,而 RuntimeException 定义的异常可以选择性地进行处理。(313页)
  20. assert 关键字主要的功能是进行断言。断言指的是程序执行到某行之后,其结果一定是预期的结果。(313页)
  21. Java 默认情况下是不开启断言的。(313页)

第 7 章 Eclipse 开发工具

  1. Eclipse 中所有的项目都是以工作区为主的,一个工作区中可以包含多个项目。每一个工作区都有自己独立的配置,如果发现某一个工作区坏了,那么用户只需要更换一个工作区就可以恢复到原始状态。(318页)
  2. 每当用户创建完一个类,或者是保存一个程序代码后,Eclipse 都会帮助用户自动进行代码的编译。(320页)
  3. 在 Eclipse 里面最为方便的是可以帮助用户自动生成构造方法、setter 方法与 getter 方法。(323页)
  4. 如果要想为一个类配置初始化参数,那么这个类一定要先执行一次,否则即使进入到运行配置,也找不到对应的类。(324页)
  5. debug 功能(代码的跟踪调试),可以让开发者手工处理程序执行,这样就可以快速地排除错误。(326页)
  6. 如果要想进行程序的 debug 操作,就需要首先定义出程序的断点(在代码行的左边空白栏双击鼠标后会出现一个蓝点,重复执行后会消失)。所谓的断点指的是程序执行到此处时会暂时丧失自动执行的能力,并将程序的执行操作交由用户进行控制。(326页)
  7. 调试的方法有以下 4 种:(327页)
    (1)单步进入(Step Into):指的是进入到执行的方法中观察方法的执行效果。
    (2)单步跳过(Step Over):在当前代码的表面上执行。
    (3)单步返回(Step Return):不再观察,返回到进入处。
    (4)恢复执行(Resume):停止调试,直接正常执行完毕。
  8. 如果某一个项目不再使用了,那么可以进行删除。删除也分为一下两种形式:(327页)
    (1)从工作区里删除但是磁盘保留:日后可以对项目进行重新导入;
    (2)从磁盘上彻底删除项目:彻底消失。
  9. JUnit 测试是程序员测试,即白盒测试,因为程序员知道被测试的软件如何(How)完成功能和完成什么样(What)的功能。JUnit 是一套框架,所有需要测试的类直接继承 TestCase 类,就可以用 JUnit 进行自动测试。JUnit 是一个开发源代码的 Java 测试框架,用于编写和运行可重复的测试。(329页)

第 8 章 Java 新特性

  1. 在 JDK 1.5 中有三大主要新特性:泛型、枚举和 Annotation。而 JDK 1.8 最大新特性是引入了 Lambda 表达式。(332页)
  2. 从 JDK 1.5 开始,为了解决参数任意多个的问题,专门在方法定义上提供了可变参数的概念。语法形式如下:(333页)

    [public|protected|private][static][final][abstract] 返回值类型 方法名称(参数类型...变量){
    [return [返回值];]
    }

    此时可以使用 “参数类型…变量” 的形式传递若干个参数,而有趣的是这多个参数变量传递到方法中都将以指定类型的数组进行保存,也就是说传递时传递的是多个参数,而接收后就变成了一个数组内容。方法在使用可变参数定义后,调用处可以任意传递多个参数,或者直接传递一个数组。而方法本身对于多个参数的处理都将统一使用数组进行接收。

  3. foreach 是一种加强型的 for 循环操作,主要可以用于简化数组或集合数组的输出操作。形式如下:(335页)

    for(数据类型 变量:数组|集合){
    //每一次循环会自动的将数组的内容设置给变量
    }
  4. 向下转型的操作并不是安全的,向下转型会存在类转换异常(ClassCastException)。(337页)

  5. 泛型技术的核心意义在于:类属性或方法的参数在定义数据类型时,可以直接使用一个标记进行占位,在具体使用时才设置其对应的实际数据类型,这样当设置的数据类型出现错误后,就可以在程序编译时检测出来。(339页)
  6. 在开发中一个类上可能会定义多种泛型声明。(340页)
  7. 使用泛型后,所有类中属性的类型都是动态设置的,而所有使用泛型标记的方法参数类型也都发生了改变。如果要想使用泛型,那么它能够采用的类型只能够是类,即不能是基本类型,只能是引用类型。(340页)
  8. 为了保证设计的合理性,如果不设置泛型会使用 Object 类型。(341页)
  9. 只要在类对象声明时使用了泛型,那么实例化对象时就可以不再重复设置泛型类型。(342页)
  10. 通配符 “?” 设置的泛型类型只表示可以取出,但是不能设置,一旦设置了内容,程序编译时就会出现错误提示。(345页)
  11. “?” 的子通配符:(345页)
    (1)“?extends 类”:设置泛型上限,可以在声明和方法参数上使用;
    (2)“?super 类”:设置泛型下限,方法参数上使用。
  12. 泛型不仅可以定义在类中,也可以定义在接口上。定义在接口上的泛型被称为泛型接口。(346页)
  13. 对于使用了泛型的接口子类而言,有以下两种实现方式:(346页)
    (1)在子类继续设置泛型标记。
    (2)在子类不设置泛型,而为父接口明确地定义一个泛型类型。
  14. 对于泛型除了可以定义在类上外,也可以在方法上进行定义,而在方法上定义泛型时,这个方法不一定非要在泛型类中定义。(347页)
  15. 枚举主要用于定义一组可以使用的类对象,这样在使用时只能通过固定的几个对象来进行类的操作。(348页)
  16. 从 JDK 1.5 开始,专门提供了一个新的关键字 enum 定义枚举类型。(348页)
  17. 在 Java 中使用 enum 定义的枚举类就相当于默认继承 java.lang.Enum 类。Enum 类本身是一个抽象类,而抽象类在使用时必须被子类继承。(350页)
  18. 只要权限不是 public 都表示封装。(350页)
  19. enum 和 Enum 的关系:enum 是 JDK 1.5 之后定义的新关键字,主要用于定义枚举类型,在 Java 中每一个使用 enum 定义的枚举类型实际上都表示一个类默认继承了 Enum 类。(351页)
  20. 枚举中定义的构造方法不能使用 public 声明,如果没有无参构造,要手工调用构造传递参数;枚举对象必须要放在首行,随后才可以定义属性、构造、普通方法等结构。(351页)
  21. 枚举最大的作用就是限定一个类的对象的产生格式。(354页)
  22. JDK 1.5 之后,最具有鲜明特点的莫过于注解技术的提出与应用,利用注解技术可以回避面向对象中覆写方法名称固定的问题。(356页)
  23. 当进行方法覆写时,为了保证子类所覆写的方法的确是父类中定义过的方法,就可以加上 “@Override” 注解,这样即使用户覆写方法时出现了错误,也可以在编译时直接检查出来。(357页)
  24. 不写 “@Override” 在正确覆写时没有任何问题,但是一旦覆写错误将无法验证。(358页)
  25. 使用 “@Deprecated” 注解来声明过期的不建议使用的方法。(358页)
  26. 从 JDK 1.8 开始,可以在接口中定义普通方法(使用 default 声明)与静态方法(使用 static 声明)。(359页)
  27. 使用 default 定义普通方法,需要利用实例化对象明确调用。如果用户有需要还可以使用 static 定义方法,这样该方法就可以由接口名称直接调用。(360页)
  28. Lambda 表达式指的是应用在单一抽象方法(Single Abstract Method,SAM)接口环境下的一种简化定义形式,可以用于解决匿名内部类的定义复杂问题。(361页)
  29. Lambda 表达式的语法:(362页)

    (参数)->方法体
  30. 在接口上使用 “@FunctionalInterface” 注解,表示此为函数式接口,里面只允许定义一个抽象方法。在函数式接口中依然可以定义普通方法与静态方法。(363页)

  31. 对于 Lambda 表达式的使用有如下 3 种形式:(363页)
    (1)方法主体为一个表达式:(params)->expression;
    (2)方法主体为一行执行代码:(params)->statement;
    (3)方法主体需要编写多行代码:(params)->{statements}。
  32. 从 JDK 1.8 开始,在方法上也支持了引用操作,这样就相当于为方法定义了别名。对于方法引用,Java 8 一共定义了一下 4 种操作形式:(365页)
    (1)引用静态方法:类名称::static 方法名称;
    (2)引用某个对象的方法:实例化对象::普通方法;
    (3)引用特定类型的方法:特定类::普通方法;
    (4)引用构造方法:类名称::new。
  33. 对于可能出现的函数式接口的方法最多只有 4 类:有参数有返回值、有参数无返回值、无参数有返回值、判断真假。(368页)
  34. 开发包 java.util.function 中提供了以下 4 个核心的函数式接口:(368页)
    (1)功能型接口(Function)
    主要作用:此接口需要接收一个参数,并且返回一个处理结果。
    (2)消费型接口(Consumer)
    主要作用:此接口只是负责接收数据(引用数据时不需要返回),并且不返回处理结果。
    (3)供给型接口(Supplier)
    主要作用:此接口不接收参数,但是可以返回结果。
    (4)断言型接口(Predicate)
    主要作用:进行判断操作使用。

第三部分 Java 高级编程

第 9 章 多线程

  1. 进程是程序的一次动态执行过程,它经历了从代码加载、执行到执行完毕的一个完整过程,这个过程也是进程本身从产生、发展到最终消亡的过程。(373页)
  2. 多进程操作系统能同时运行多个进程(程序),由于 CPU 具备分时机制,所以每个进程都能循环获得自己的 CPU 时间片。由于 CPU 执行速度非常快,使得所有程序好像是在 “同时” 运行一样。(373页)
  3. 线程是比进程更小的执行单位,线程是在进程的基础之上进行的进一步划分。多线程是实现并发机制的一种有效手段。所谓多线程是指一个进程在执行过程中可以产生多个线程,这些线程可以同时存在、同时运行。一个进程可能包含多个同时执行的线程。(373页)
  4. Windows 属于多线程的处理操作,在同一个时间段上会有多个程序共同执行,而在一个时间点上只能有一个程序在执行。多线程是在一个进程基础上的进一步划分。(373页)
  5. 所有的线程一定要依附于进程才能够存在,那么进程一旦消失了,线程也一定会消失。而 Java 是为数不多的支持多线程的开发语言之一。(374页)
  6. 在 Java 中,如果要想实现多线程的程序,就必须依靠一个线程的主体类。(374页)
  7. java.lang.Thread 是一个负责线程操作的类,任何类只需要继承 Thread 类就可以成为一个线程的主类。线程启动的主方法需要覆写 Thread 类中的 run() 方法实现。(374页)
  8. 多线程的执行应该是多个线程彼此交替执行。如果直接调用 run() 方法,并不能启动多线程,多线程启动的唯一方法就是 Thread 类中的 start() 方法:(375页)

    public void start()(调用此方法执行的方法体是 run() 方法定义的代码)
  9. Java 本地接口(Java Native Interface,JNI)技术的特点是使用 Java 调用本机操作系统提供的函数。(376页)

  10. 使用 Thread 类的 start() 方法不仅要启动多线程的执行代码,还要根据不同的操作系统进行资源的分配。(376页)
  11. 如果某一个线程对象重复进行了启动(同一个线程对象调用多次 start() 方法),就会抛出 java.lang.IllegalThreadStateException 异常。(377页)
  12. 在 Java 中也可以利用 Runnable 接口来实现多线程。在 Runnable 接口中也定义了 run() 方法,所以线程的主类只需要覆写此方法即可。(377页)
  13. 要启动多线程,一定需要通过 Thread 类中的 start() 方法才可以完成。Thread 类中提供了一个有参构造方法:public Thread(Runnable target),本方法可以接收一个 Runnable 接口对象。(377页)
  14. 使用 Runnable 接口可以有效避免单继承局限问题,所以在实际的开发中,对于多线程的实现首先选择的就是 Runnable 接口。(378页)
  15. Thread 类也是 Runnable 接口的子类。(379页)
  16. 使用 Runnable 接口可以更加方便地表示出数据共享的概念(但不是说 Thread 类不能实现数据共享)。(379页)
  17. 多线程的两种实现方式及区别:
    (1)多线程的两种实现方式都需要一个线程的主类,而这个类可以实现 Runnable 接口或者继承 Thread 类,不管使用何种方式都必须在子类中覆写 run() 方法,此方法为线程的主方法;
    (2)Thread 类是 Runnable 接口的子类,而且使用 Runnable 接口可以避免单继承局限,并且可以更加方便地实现数据共享的概念。
    ①Runnable 接口:

    class MyThread implements Runnable{
    @Override
    public void run(){//线程主方法
    //线程操作方法
    }
    }
    MyThread mt = new MyThread();
    new Thread(mt).start();

    ②Thread 类:

    class MyThread extends Thread{
    @Override
    public void run(){//线程主方法
    //线程操作方法
    }
    }
    MyThread mt = new MyThread();
    mt.start();
  18. Runnable 接口里面的 run() 方法不能返回操作结果。从 JDK 1.5 开始,Java 对于多线程的实现提供了一个新的接口:java.util.concurrent.Callable。(382页)

  19. 如果实现多线程,建议使用 Runnable 接口完成。(384页)
  20. 任何线程一般都具有 5 种状态,即创建、就绪、运行、堵塞和终止。(384页)
  21. 在程序中用构造方法创建一个线程对象后,新的线程对象便处于新建状态,此时,它已经有相应的内存空间和其他资源,但还处于不可运行状态。(384页)
  22. 新建线程对象后,调用该线程的 start() 方法就可以启动线程。当线程启动时,线程进入就绪状态。(385页)
  23. 当就绪状态的线程被调用并获得处理器资源时,线程就进入了运行状态。此时,自动调用该线程对象的 run() 方法。(385页)
  24. 在可执行状态下,如果调用 sleep()、suspend()、wait() 等方法,线程都将进入堵塞状态。堵塞时,线程不能进入排队队列,只有当引起堵塞的原因被消除后,线程才可以转入就绪状态。(385页)
  25. 线程调用 stop() 方法时或 run() 方法执行结束后,就处于终止状态。处于终止状态的线程不具有继续运行的能力。(385页)
  26. 所有线程程序的执行,每一次都是不同的运行结果,因为它会根据自己的情况进行资源抢占,所以要想区分每一个线程,就必须依靠线程的名字。对于线程名字一般而言会在其启动之前进行定义,不建议对已经启动的线程更改名称,或者是为不同的线程设置重名的情况。(385页)
  27. 由于线程的状态不确定,所以每次可以操作的都是正在执行 run() 方法的线程。(385页)
  28. 当实例化 Thread 类对象时可以自己定义线程名称,也可以采用默认名称进行操作。(386页)
  29. 当用户使用 Java 命令执行一个类时就表示启动了一个 JVM 的进程,而主方法只是这个进程上的一个线程而已,当一个类执行完毕后,此进程会自动消失。(387页)
  30. 每一个 JVM 进程都至少启动以下两个线程:(387页)
    (1)main 线程:程序的主要执行,以及启动子线程;
    (2)gc 线程:负责垃圾收集。
  31. 线程的休眠指的是让程序的执行速度变慢一些,在 Thread 类中线程休眠操作方法为:(387页)

    public static void sleep(long millis) throws InterruptedException,设置的休眠单位是毫秒(ms)
  32. 当设置了更多的执行线程对象后,由于线程的切换速度较快,会有一种所有线程同时进入 run() 方法中的感觉(实际上是有先后差距的,只是顺序间隔过短而导致观察不明显),并且这些线程也都会等待执行的休眠时间后才会进行各自的输出。(388页)

  33. 在 Java 的线程操作中,所有的线程在运行前都会保持就绪状态,此时哪个线程的优先级高,哪个线程就有可能会先被执行。(388页)
  34. 线程优先级操作:(388页)
No. 方法或常量 类型 描述
1 public static final int MAX_PRIORITY 常量 最高优先级,数值为 10
2 public static final int NORM_PRIORITY 常量 中等优先级,数值为 5
3 public static final int MIN_PRIORITY 常量 最低优先级,数值为 1
4 public final void setPriority(int newPriority) 普通 设置线程优先级
5 public final int getPriority() 普通 取得线程优先级
  1. 主线程属于中等优先级。(390页)
  2. 在程序开发中,所有程序都是通过主方法执行的,而主方法本身就属于一个主线程,所以通过主方法创建的新的线程对象都是子线程。(390页)
  3. 利用子线程可以进行异步的操作处理,这样可以在不影响主线程运行的前提下进行其他操作,程序的执行速度不仅变快了,并且操作起来也不会产生太多的延迟。(390页)
  4. 多个线程操作同一资源就有可能出现不同步的问题。(391页)
  5. 所谓同步操作就是一个代码块中的多个操作在同一个时间段内只能有一个线程进行,其他线程要等待此线程完成后才可以继续执行。(392页)
  6. 在 Java 里面如果要想实现线程的同步,操作可以使用 synchronized 关键字。synchronized 关键字可以通过以下两种方式进行使用:(392页)
    (1)同步代码块:利用 synchronized 包装的代码块,但是需要指定同步对象,一般设置为 this;
    (2)同步方法:利用 synchronized 定义的方法。
  7. 同步的代码性能会很低,但是数据的安全性会高(线程安全性高)。(394页)
  8. Java 中方法的完整定义格式如下:(394页)

    [public|protected|private][static][final][native][synchronized] 方法返回值类型 方法名称(参数列表 | 可变参数) [throws 异常,异常,...]{
    [return [返回值];]
    }
  9. static、native、synchronized 都不能和 “abstract” 同时声明方法。(395页)

  10. 同步就是指一个线程要等待另外一个线程执行完毕才会继续执行的一种操作形式。(395页)
  11. 所谓死锁就是指两个线程都在等待彼此先完成,造成了程序的停滞状态,一般程序的死锁都是在程序运行时出现的。(395页)
  12. 死锁是一种需要回避的代码,并且在多线程的开发中,死锁都是需要通过大量测试后才可以被检测出来的一种程序非法状态。(395页)
  13. 多个线程访问同一资源时,考虑到数据操作的安全性问题,一定要使用同步操作。同步有以下两种操作模式:
    (1)同步代码块:synchronized(锁定对象) {代码};
    (2)同步方法:public synchronized 返回值 方法名称(){代码}。
    过多的同步操作有可能会带来死锁问题,导致程序进入停滞状态。(397页)
  14. sleep() 和 wait() 的区别:(403页)
    (1)sleep() 是 Thread 类定义的 static 方法,表示线程休眠,将执行机会给其他线程,但是监控状态依然保持,会自动恢复;
    (2)wait() 是 Object 类定义的方法,表示线程等待,一直到执行了 notify() 或 notifyAll() 后才结束等待。

第 10 章 Java 常用类库

  1. StringBuffer 类方便用户进行内容的修改。在 String 类中使用 “+” 进行数据的连接操作,而在 StringBuffer 类中使用 append() 方法进行数据的连接。(407页)
  2. String 类可以直接赋值实例化,但是 StringBuffer 类不行。(407页)
  3. StringBuffer 类对象的内容是可以修改的。StringBuffer 类主要用于频繁修改字符串的操作上。(408页)
  4. String 或 StringBuffer 类的对象都可以利用自动向上转型的操作为 CharSequence 接口实例化。(408页)
  5. 在一些类库中会出现接收 CharSequence 接口对象的方法,简单的话只需要传递字符串即可操作。(409页)
  6. 虽然 String 和 StringBuffer 类都属于 CharSequence 接口的子类,但是这两个类对象是不能直接转换的。(409页)
  7. 将 String 转换为 StringBuffer 类对象:(409页)
    (1)利用 StringBuffer 类的构造方法(public StringBuffer(String str));
    (2)利用 StringBuffer 类中的 append() 方法(public StringBuffer append(String str))。
  8. 将 StringBuffer 类变为 String:(409页)
    (1)利用 toString() 方法可以将 StringBuffer 转换为 String;
    (2)利用 String 类的构造方法(public String(StringBuffer buffer))。
  9. 所有的类中都会继承 Object 类的 toString() 方法,所以所有的类对象都可以转换为 String 类对象。(410页)
  10. String 类里面提供一个和 StringBuffer 比较的方法:public boolean contentEquals(StringBuffer sb)。contentEquals() 方法在进行字符串的比较时要区分大小写。(410页)
  11. StringBuffer 类常用操作方法(所有方法都返回 StringBuffer 类型的对象,可以使用代码链的方式一直调用 StringBuffer 的方法):(410页)
No. 方法 类型 描述
1 public StringBuffer append(数据类型 变量) 普通 数据追加操作
2 public StringBuffer reverse() 普通 字符串反转操作
3 public StringBuffer insert(int offset,数据类型 变量) 普通 在指定位置追加内容
4 public StringBuffer delete(int start,int end) 普通 删除指定索引范围的内容
  1. 在 StringBuffer 类中定义的方法全部使用 “synchronized” 进行同步定义,而 StringBuilder 类没有进行同步定义,所以 StringBuilder 类的方法都是异步方法。(412页)
  2. String 类、StringBuffer 类和 StringBuilder 类的区别:(412页)
    (1)String 类的内容一旦声明则不可改变,而 StringBuffer 类与 StringBuilder 类声明的内容可以改变;
    (2)StringBuffer 类中提供的方法都是同步方法,属于安全的线程操作;而 StringBuilder 类中的方法都属于异步方法,属于非线程安全的操作。
  3. 在每一个 JVM 进程中,都会存在一个运行时的操作类的对象,而这个对象所属的类型就是 Runtime 类。利用 Runtime 类可以启动新的进程或进行相关运行时环境的操作。(412页)
  4. 单例设计模式所属的类一定会提供一个 static 型的方法,用于取得本类的实例化对象,Runtime 类使用了单例设计模式,所以在 Runtime 类中也提供了一个 getRuntime() 方法用于取得本类实例化对象。取得 Runtime 类实例化对象的方法为:public static Runtime getRuntime()。(412页)
  5. 在 Runtime 类有一个非常重要的方法:public void gc(),用于进行垃圾收集器,释放垃圾空间,即调用此方法后所产生的垃圾空间将被释放。(412页)
  6. Java 中可用内存空间是可以调整的。(413页)
  7. 垃圾回收主要是对年轻代(Young Generation)与旧生代(Old Generation)的内存进行回收。年轻代内存空间用于存放新产生的对象,而经过若干次回收还没有被回收掉的对象向旧生代内存空间移动。对年轻代进行垃圾回收称为 MinorGC(从垃圾收集),对旧生代垃圾回收称为 MajorGC(主垃圾收集),并且两块内存回收互不干涉。在 JVM 中的对象回收机制会使用分代回收(Generational Collection)的策略,用较高的频率对年轻代对象进行扫描和回收,而对旧生代对象则用较低的频率进行回收,这样就不需要在每次执行 GC 时将内存中的所有对象都检查一遍。(415页)
  8. 当 JVM 剩余内存空间不足时会触发 GC,如果 Eden 内存空间不足就要进行从回收(Minor Collection),旧生代空间不足时要进行主回收(Major Collection),永久代空间不足时会进行完全垃圾收集(Full Collection)。(415页)
  9. GC(Garbage Collection)垃圾收集器,指的是释放无用的内存空间。GC 会由系统不定期进行自动回收,或者调用 Runtime 类中的 gc() 方法手工回收。(416页)
  10. System 类的方法:(417页)
No. 方法 类型 描述
1 public static void arraycopy(Object src,int srcPos,Object dest,int destPos,int length) 普通 数组复制操作
2 public static long currentTimeMillis() 普通 取得当前的日期时间,以 long 型数据返回
3 public static void gc() 普通 垃圾收集(并不是新定义的方法,而是间接调用了 Runtime 类中的 gc() 方法)
  1. 调用 System.gc() 和调用 Runtime.getRuntime().gc() 最终的效果是完全一样的。(418页)
  2. 如果希望在一个对象收尾时执行一些收尾工作,则对象所在的类可以通过覆写 finalize() 方法实现,此方法由 Object 类定义。(418页)
  3. 在进行对象回收前,有可能代码会产生异常(Exception),或者由于 JVM 的一些问题而产生错误(Error),但是不管出现任何异常或错误,都不会导致程序中断执行。(418页)
  4. 当一个对象的堆内存空间被回收后将自动调用 finalize() 方法,这样就可以进行一些对象回收前的收尾工作。并且此方法即使产生任何异常或错误,也不会影响程序的正常执行。(418页)
  5. final、finally、finalize 的区别:(419页)
    (1)final 表示终结器,用于定义不能被继承的父类,不能被覆写的方法、常量;
    (2)finally 是异常处理的出口;
    (3)finalize 是 Object 类定义的一个方法,用于执行对象回收前的收尾工作。
  6. 克隆就是对象的复制操作,在 Object 类中存在一个 clone() 方法用于对象的克隆。此方法是实现克隆的唯一方法,所有类的对象只有调用此方法才可以进行克隆。(419页)
  7. 不是所有类的对象都可以被克隆。在 Java 中为了区分出哪些类对象可以被克隆,专门提供一个 Cloneable 接口,也就是说要克隆对象的类必须实现 Cloneable 接口。(419页)
  8. Cloneable 接口没有任何方法,所以这个接口属于标识接口,用于表示一种能力。(419页)
  9. Math 类是一个专门进行数学计算的操作类,它提供了一系列数学计算方法。在 Math 类里面提供的一切方法都是 static 型的方法,所以可以直接由类名称进行调用。(420页)
  10. 当四舍五入的数据为负数时,操作数据小数位大于 0.5 才进位,小于或等于 0.5 则不进位。(421页)
  11. Math.round() 设计的原则就是不保留任何小数位。(421页)
  12. java.util.Random 是一个专门负责产生随机数的操作类。Random 类的常用方法:(421页)
No. 方法 类型 描述
1 public Random() 构造 创建一个新的 Random 实例
2 public Random(long seed) 构造 创建一个新的 Random 实例并设置一个种子数
3 public int nextInt(int bound) 普通 产生一个不大于指定边界的随机整数
  1. Java 提供了两个大数字操作类:java.math.BigInteger 和 java.math.BigDecimal,而这两个类都属于 Number 的子类。(423页)
  2. BigInteger 类的基本操作方法:(424页)
No. 方法 类型 描述
1 public BigInteger(String val) 构造 实例化 BigInteger 对象
2 public BigInteger add(BigInteger) 普通 加法操作
3 public BigInteger subtract(BigInteger val) 普通 减法操作
4 public BigInteger multiply(BigInteger val) 普通 乘法操作
5 public BigInteger divide(BigInteger val) 普通 除法操作(不保留余数)
6 public BigInteger[] devideAndRemainder(BigInteger val) 普通 除法操作(保留余数),数组第一个元素是商,第二个元素是余数
  1. 如果要想取得当前的日期时间,只需要直接实例化 Date 类对象即可。(426页)
  2. Date 类的常用方法:(426页)
No. 方法 类型 描述
1 public Date() 构造 实例化 Date 类对象
2 public Date(long date) 构造 将数字变为 Date 类对象,long 为日期时间数据
3 public long getTime() 普通 将当前的日期时间变为 long 型
  1. 在 Date 类的构造方法中,构造方法可以接收一个 long 类型的数据,而且 getTime() 也可以返回一个 long 类型的数据,利用这两个方法就可以实现 Date 与 long 之间的转换。(426页)
  2. SimpleDateFormat 类常用方法:(427页)
No. 方法 类型 描述
1 public SimpleDateFormat(String pattern) 构造 传入日期时间标记实例化对象
2 public final String format(Date date) 普通 将日期格式化为字符串数据
3 public Date parse(String source) throws ParseException 普通 将字符串格式化为日期数据
  1. 如果用户设置了不正确的日期时间数字,SimpleDateFormat 类会帮助用户自动进行进位处理。(428页)
  2. 在实际的 Java 项目开发中,有 6 种最为常见的数据类型:java.lang.String、java.util.Date、int(Integer)、double(Double)、byte(Byte)、boolean(Boolean)。互相之间的转换原则:(428页)
    (1)Date 与 String 类之间的转换依靠 SimpleDateFormat;
    (2)String 与基本类型之间的转换依靠包装类与 String.valueOf() 方法;
    (3)long 与 Date 转换依靠 Date 类提供的构造以及 getTime() 方法。
  3. Calendar 类可以将取得的时间精确到毫秒,并且由于其可以分别取得日期时间数字,这样可以直接进行各种日期时间的计算操作。Calendar 类本身是一个抽象类,利用 getInstance() 方法可以取得本类的实例化对象。(429页)
  4. Calendar 类中定义的常量与方法:(429页)
No. 常量及方法 类型 描述
1 public static final int YEAR 常量 取得年、int 类型
2 public static final int MONTH 常量 取得月、int 类型
3 public static final int DAY_OF_MONTH 常量 取得日、int 类型
4 public static final int HOUR_OF_DAY 常量 取得小时(24 小时制)、int 类型
5 public static final int MINUTE 常量 取得分、int 类型
6 public static final int SECOND 常量 取得秒、int 类型
7 public static final int MILLISECOND 常量 取得毫秒、int 类型
8 public static Calendar getInstance() 普通 根据默认的时区实例化对象
9 public boolean after(Object when) 普通 判断一个日期是否在指定日期之后
10 public boolean before(Object when) 普通 判断一个日期是否在指定日期之前
11 public int get(int field) 普通 返回给定日历字段的值
  1. Arrays 类的常用方法:(431页)
No. 方法 类型 描述
1 public static boolean equals(int[] a,int[] a2) 普通 判断两个数组是否相等,此方法被重载多次,可以判断各种数据类型的数组
2 public static void fill(int[] a,int[] val) 普通 将指定内容填充到数组中,此方法被重载多次,可以填充各种数据类型的数组
3 public static void sort(int[] a) 普通 数组排序,此方法被重载多次,可以对各种类型的数组进行排序
4 public static int binarySearch(int[] a,int key) 普通 对排序后的数组进行检索,此方法被重载多次,可以对各种类型的数组进行检索
5 public static String toString(int[] a) 普通 输出数组信息,此方法被重载多次,可以输出各种数据类型的数组
  1. 二分查找又被分为折半查找法,要使用二分查找法,则要求数组中的数据必须为有序的。(431页)
  2. 对象数组由于本身存放的都是地址数据,不可能依据大小关系来实现排序。要想使用 sort() 方法进行排序,必须有一个前提:对象所在的类一定要实现 Comparable 接口,否则代码执行时会出现 ClassCastException 异常。(432页)
  3. 在 Comparable 接口中只定义了一个 compareTo() 方法,此方法返回一个 int 型数据,而用户覆写此方法时只需要返回 3 种结果:1(>0)、-1(<0)、0(=0)。(433页)
  4. String 类、Integer 类等都实现了 Comparable 接口。(433页)
  5. 在 Java 中比较器有两种实现方式,其中 Comparable 是最为常用的比较器接口。(434页)
  6. 树是一种比链表更为复杂的概念应用,其本质也属于动态对象数组,但是与链表不同的是,树的最大特征是可以针对数据进行排序。(434页)
  7. 树的操作原理:选择第一个数据作为根节点,而后比根节点小的放在根节点的左子树(左节点),比根节点大的数据放在右子树(右节点),取得数据时按照中序遍历的方式取出(左─中─右)。(434页)
  8. Comparable 和 Comparator 的区别:(440页)
    (1)如果对象数组要进行排序就必须设置排序规则,可以使用 Comparable 或 Comparator 接口实现;
    (2)java.lang.Comparable 是在一个类定义时实现好的接口,这样本类的对象数组就可以进行排序,在 Comparable 接口下定义了一个 public int compareTo() 方法;
    (3)java.util.Comparator 是专门定义一个指定类的比较规则,属于挽救的比较操作,里面有两个方法:public int compare()、public boolean equals()。
  9. 正则表达式(Regular Expression,在代码中常简写为 regex、regexp 或 RE)在本质上是一种字符串操作的语法规则,利用此语法可以更加灵活地实现字符串的匹配、拆分、替换等操作。(440页)
  10. 所有正则表达式支持的类都定义在 java.util.regex 包里面。此包中定义了如下两个主要的类:(442页)
    (1)Pattern 类:主要定义要使用的表达式对象(要想取得此类对象必须使用 compile() 方法,方法的功能是编译正则);
    (2)Matcher 类:用于进行正则标记与指定内容的匹配操作。
  11. 所有可以使用的正则标记都在 java.util.regex.Pattern 类的说明文档中定义,常用的标记有如下 6 类:(442页)
    (1)单个字符(数量:1)
    ①字符:表示由一位字符组成;
    ②\\:表示转义字符 “\”;
    ③\t:表示一个 “\t” 符号;
    ④\n:匹配换行(\n)符号。
    (2)字符集(数量:1)
    ①[abc]:表示可能是字符 a、字符 b、字符 c 中的任意一位;
    ②[^abc]:表示不是字符 a、b、c 中的任意一位;
    ③[a-z]:所有的小写字母;
    ④[a-zA-Z]:表示任意的一位字母,不区分大小写;
    ⑤[0-9]:表示任意的一位数字。
    (3)简化的字符集表达式(数量:1)
    ①.:表示任意的一位字符;
    ②\d:等价于 “[0-9]”,属于简化写法;
    ③\D:等价于 “[^0-9]”,属于简化写法;
    ④\s:表示任意的空白字符,例如:“\t”、“\n”;
    ⑤\S:表示任意的非空白字符;
    ⑥\w:等价于 “[a-zA-Z_0-9]”,表示由任意的字母、数字、_ 组成。
    (4)边界匹配
    ①^:正则的开始;
    ②$:正则的结束。
    (5)数量表达
    ①正则?:表示此正则可以出现 0 次或 1 次;
    ②正则+:表示此正则可以出现 1 次或 1 次以上;
    ③正则*:表示此正则可以出现 0 次、1 次或多次;
    ④正则{n}:表示此正则正好出现 n 次;
    ⑤正则{n,}:表示此正则出现 n 次以上(包含 n 次);
    ⑥正则{n,m}:表示此正则出现 n~m 次(包含 n,m)。
    (6)逻辑运算
    ①正则 1 正则 2:正则 1 判断完成后继续判断正则 2;
    ②正则 1|正则 2:正则 1 或者是正则 2 有一组满足即可;
    ③(正则):将多个正则作为一组,可以为这一组单独设置出现的次数。
  12. String 类与正则有关的 5 个操作方法:(443页)
No. 方法名称 类型 描述
1 public boolean matches(String regex) 普通 正则验证,使用指定的字符串判断是否符合给出的正则表达式结构
2 public String replaceAll(String regex,String replacement) 普通 将满足正则标记的内容全部替换为新的内容
3 public String replaceFirst(String regex,String replacement) 普通 将满足正则标记的首个内容替换为新的内容
4 public String[] split(String regex) 普通 按照指定的正则标记进行字符串的全拆分
5 public String[] split(String regex,int limit) 普通 按照指定的正则标记进行字符串的部分拆分
  1. 如果要在字符串中定义 “\”,必须使用 “\\”。(444页)
  2. 在 String 类中提供的方法在 Pattern 或 Matcher 类中也提供了相同的功能。(448页)
  3. java.util.regex.Pattern 类的主要功能是进行数据的拆分以及为 Matcher 类对象实例化。(448页)
  4. Pattern 类的常用方法:(448页)
No. 方法 类型 描述
1 public static Pattern compile(String regex) 普通 编译正则表达式
2 public String[] split(CharSequence input) 普通 数据全拆分操作
3 public String[] split(CharSequence input,int limit) 普通 数据部分拆分操作
4 public Matcher matcher(CharSequence input) 普通 取得 Matcher 类对象
  1. 在 Pattern 类中没有定义构造方法,所以如果要想取得 Pattern 类对象,必须利用 compile() 方法进行指定正则表达式的编译操作。(448页)
  2. 在 Pattern 类中定义的方法,在进行参数接收时接收的都是 CharSequence 接口对象,这样就表示只要是 CharSequence 接口的子类对象都可以进行正则操作。(448页)
  3. 如果要想实现数据的验证与替换操作,就需要通过 Matcher 类实现操作。Matcher 类的常用方法:(449页)
No. 方法 类型 描述
1 public boolean matches() 普通 正则匹配
2 public String relpaceAll(String replacement) 普通 全部替换
3 public String replaceFirst(String replacement) 普通 替换首个
  1. 反射是 Java 中最为重要的特性,几乎所有的开发框架以及应用技术中都是基于反射技术的应用。(449页)
  2. 在正常的类操作过程中,一定是要先确定使用的类,再利用关键字 new 产生实例化对象后使用。如果要通过对象取得此对象所在类的信息,那么就可以通过 Object 类中的 getClass() 方法实现。(449页)
  3. java.lang.Class 类是反射操作的源头类,即所有的反射操作都需要通过此类开始。(450页)
  4. Class 类的常用方法:(451页)
No. 方法 类型 描述
1 public static Class<?> forName(String className) throws ClassNotFoundException 普通 通过字符串设置的类名称实例化 Class 类对象
2 public Class<?>[] getInterfaces() 普通 取得类实现的所有接口
3 public String getName() 普通 取得反射操作类的全名
4 public String getSimpleName() 普通 取得反射操作类名,不包括包名称
5 public Package getPackage() 普通 取得反射操作类所在的包
6 public CLass<? super T> getSuperclass() 普通 取得反射操作类的父类
7 public boolean isEnum() 普通 反射操作的类是否是枚举
8 public boolean isInterface() 普通 反射操作的类是否是接口
9 public boolean isArray() 普通 反射操作的类是否是数组
10 public T newInstance() throws InstantiationException,IllegalAccessException 普通 反射实例化对象
  1. 在 Class 类中最为重要的一个方法就是 newInstance() 方法,通过此方法可以利用反射实现 Class 类包装类型的对象实例化操作,也就是说即使不使用关键字 new 也可以进行对象的实例化操作。(452页)
  2. 任何类都至少存在一个构造方法,如果利用 Class 类中的 newInstance() 方法反射实例化类对象,则类中一定要提供无参构造方法,否则会出现语法错误。(452页)
  3. 有了反射后,进行对象实例化的操作不再只是单独的依靠关键字 new 完成了,反射也同样可以完成,但是这并不表示 new 就被完全取代,在应用开发中大部分都会利用 new 实现对象的实例化操作。(454页)
  4. 利用 Class 类的 newInstance() 方法可以实现反射实例化对象的操作,但是这样的操作本身有一个限制,就是类中必须提供无参构造方法。所以当类中只提供有参构造方法时,就必须通过 java.lang.reflect.Constructor 类来实现对象的反射实例化操作。(454页)
  5. 如果一个类中没有提供无参构造方法,则执行时会出现 “InstantiationException” 异常信息。(454页)
  6. java.lang.reflect 是所有反射操作类的程序包,类中的每一个结构都有相应的类进行操作定义。(455页)
  7. Constructor 类的常用操作方法:(455页)
No. 方法 类型 描述
1 public Class<?>[] getExceptionTypes() 普通 返回构造方法上所有抛出异常的类型
2 public int getModifiers() 普通 取得构造方法的修饰符
3 public String getName() 普通 取得构造方法的名字
4 public int getParameterCount() 普通 取得构造方法中的参数个数
5 public Class<?>[] getParameterTypes() 普通 取得构造方法中的参数类型
6 public T newInstance(Object…initargs) throws InstantiationException,IllegalAccessException,IllegalArgumentException,InvocationTargetException 普通 调用指定参数的构造实例化类对象
  1. 所有修饰符都是一个数字,修饰符的组成就是一个数字的加法操作。(456页)
  2. 在 java.lang.reflect.Modifer 类中明确地定义了各个修饰符对应的常量操作,同时也提供了将数字转换为指定修饰符的方法:public static String toString(int mod)。(456页)
  3. 在类的组成中,方法是类的主要操作手段,以往的做法都是利用 “对象.方法()” 的形式进行方法调用,而现在也可以利用反射机制实现类方法的操作。(457页)
  4. 在反射操作中,每一个方法都通过 java.lang.reflect.Method 类表示。Method 类的常用方法:(457页)
No. 方法 类型 描述
1 public int getModifiers() 普通 取得方法的修饰符
2 public Class<?> getReturnType() 普通 取得方法的返回值类型
3 public int getParameterCount() 普通 取得方法中定义的参数数量
4 public Class<?>[] getParameterTypes() 普通 取得方法中定义的所有参数类型
5 public Object invoke(Object obj,Object…args) throws IllegalAccessException,IllegalArgumentException,InvocationTargetException 普通 反射调用方法并且传递执行方法所需要的参数数据
6 public Class<?>[] getExceptionTypes() 普通 取得方法抛出的异常类型
  1. 在任何情况下,只要是调用类中的普通方法,就必须产生类的实例化对象才可以正常完成。(458页)
  2. 在 Method 类的 invoke() 方法调用时要接收的第一个参数就是类的实例化对象,此时的类型使用的是 Object,也就是用反射实现的方法调用,不需要具体的对象类型,这一点操作要比直接使用对象调用方法更加灵活。(458页)
  3. 国际化程序指的是同一套程序代码可以在不同的国家使用。所谓的国际化程序实际上指的就是同一套程序,可以根据其应用的国家自动在项目中显示出本国的相应文字信息。(461页)
  4. 如果要对用户使用的语言环境进行定义,可以使用 java.util.Locale 类完成。Locale 类的常用方法:(462页)
No. 方法 类型 描述
1 public Locale(String language,String country) 构造 设置要使用的语言及国家编码
2 public static Locale getDefault() 普通 取得当前语言环境下的 Locale 类对象
  1. 资源文件一般都是以 “key=value” 的形式保存文本信息,这样在进行信息读取时就可以根据指定的 key 取得相应的 value 数据。资源文件的文件名称是有要求的,必须以 “*.properties” 作为文件后缀。如果要在程序中读取资源文件,则可以利用 java.util.ResourceBundle 类完成。(463页)
  2. ResourceBundle 类的常用方法:(463页)
No. 方法 类型 描述
1 public static final ResourceBundle getBundle(String baseName) 普通 根据当前默认语言环境,取得资源对象
2 public static final ResourceBundle getBundle(String baseName,Locale locale) 普通 根据指定的语言环境,取得资源对象
3 public final String getString(String key) 普通 根据 key 取得对应的 value 数据
  1. 资源文件必须保存在 CLASSPATH 目录下。资源文件可以保存在包中,但是在读取时需要加上包名称(如果访问不到则会出现 “MissingResourceException” 异常)。同时资源文件的命名规范应该与类名称相同,即每个单词的首字母必须大写。(463页)
  2. 资源文件要保存中文则必须将中文转换为 UNICODE 编码。(463页)
  3. 用户也可以通过占位符在资源文件中采用动态的内容设置,而这一操作就必须依靠 java.text.MessageFormat 类完成。(464页)
  4. 所有的格式化操作类都保存在 java.text 包中,也就是说这个包中定义的类都是与国际化操作有关的程序类。(464页)
  5. 在资源信息中使用 “{0}” 表示第一个动态文本,使用 “{1}” 表示第二个动态文本,如果有需要也可以定义更多的动态文本占位符。(465页)
  6. 即使定义了多个资源文件,在使用 ResourceBundle 类读取时依然只会输入文件名称,而具体的语言编码和国家编码都是由程序自己分辨的。这样在进行资源文件定义时就有可能有两类资源:公共资源(没有设置语言与国家编码)和具体的语言资源文件(设置了语言与国家编码)。这样在读取时会优先读取存在具体语言与国家编码的资源文件,如果读取不到则再读取公共资源。(465页)

第 11 章 Java IO 编程

  1. Java IO 操作主要指的是通过 Java 进行输入、输出操作,Java 中所有操作类都存放在 java.io 包中,用户在使用时需要将操作导入此包中。(469页)
  2. 所有的 IO 操作都在 java.io 包中进行定义,而且整个 java.io 包实际上就是五个类和一个接口。(469页)
    (1)五个类:File、InputStream、OutputStream、Reader、Writer;
    (2)一个接口:Serializable。
  3. 如果抽象类或接口中的抽象方法被子类覆写了,那么实例化这个子类时,所调用的方法一定是被覆写过的方法,即方法名称以父类为标准,而具体的实现需要依靠子类完成。(469页)
  4. 在 java.io 包中,如果需要进行文件自身的操作(例如:创建、删除等),只能依靠 java.io.File 类完成。(469页)
  5. File 类常用操作方法:(469页)
No. 方法 类型 描述
1 public File(String pathname) 构造 传递完整文件操作路径
2 public File(File Parent,String child) 构造 设置父路径与子文件路径
3 public boolean createNewFile() throws IOException 普通 创建新文件
4 public boolean exists() 普通 判断给定路径是否存在
5 public boolean delete() 普通 删除指定路径的文件
6 public File getParentFile() 普通 取得当前路径的父路径
7 public boolean mkdirs() 普通 创建多级目录
8 public long length() 普通 取得文件大小,以字节为单位返回
9 public boolean isFile() 普通 判断给定路径是否是文件
10 public boolean idDirectory() 普通 判断给定路径是否是目录
11 public long lastModified() 普通 取得文件的最后一次修改日期时间
12 public String[] list() 普通 列出指定目录中的全部内容
13 public File[] listFiles() 普通 列出所有的路径以 File 类对象包装
  1. File 类中提供的方法并不涉及文件的具体内容,只是针对文件本身的操作。(470页)
  2. 在操作系统中如果要定义路径则一定会存在路径分隔符的问题。如果程序运行在 Linux 系统中,则路径分隔符为 “/”。在 java.io.File 类里面提供有一个路径分隔符常量:public static final String separator,利用此常量可以在不同的操作系统中自动转化为适合于该操作系统的路径分隔符。(471页)
  3. 在进行 java.io 操作文件的过程中,会出现延迟情况。因为 Java 程序是通过 JVM 间接地调用操作系统的文件处理函数进行的文件处理操作,所以中间会出现延迟情况。(471页)
  4. 如果给定的路径为根路径,则文件可以直接利用 createNewFile() 方法进行创建;如果要创建的文件存在目录,那么将无法进行创建。所以合理的做法应该是在创建文件前判断父路径(getParent() 取得父路径)是否存在,如果不存在则应该先创建目录(mkdirs() 创建多级目录),再创建文件。(否则会出现 “java.io.IOException:系统找不到指定的路径。”)(471页)
  5. 对于目录而言,最常用的功能就是列出目录组成,可以使用 listFiles() 方法完成。(473页)
  6. 如果要进行文件内容的操作,就必须依靠流的概念来完成。流在实际中分为输入流与输出流两种。(475页)
  7. 在 Java 中针对数据流的操作提供了以下两类支持:(475页)
    (1)字节流(JDK 1.0 开始提供):InputStream(输入字节流)、OutputStream(输出字节流);
    (2)字符流(JDK 1.1 开始提供):Reader(输入字符流)、Writer(输出字符流)。
  8. 流的基本操作形式:(475页)
    (1)第一步:通过 File 类定义一个要操作文件的路径;
    (2)第二步:通过字节流或字符流的子类对象为父类对象实例化;
    (3)第三步:进行数据的读(输入)、写(输出)操作;
    (4)第四步:数据流属于资源操作,资源操作必须关闭。
  9. 不管何种情况,只要是资源操作(例如:网络、文件、数据库的操作都属于资源操作),必须要关闭连接(几乎每种类都会提供 close() 方法)。(475页)
  10. 在 java.io 包中,四个操作流的类(OutputStream、InputStream、Writer、Reader)全部都属于抽象类,所以在操作这些类时,一定要通过子类对象的向上转型来进行抽象类对象的实例化操作。(475页)
  11. java.io.OutputStream 是一个专门实现字节输出流的操作类。OutputStream 类的常用方法:(475页)
No. 方法 类型 描述
1 public void close() throws IOException 普通 关闭字节输出流
2 public void flush() throws IOException 普通 强制刷新
3 public abstract void write(int b) throws IOException 普通 输出单个字节
4 public void write(byte[] b) throws IOException 普通 输出全部字节数组数据
5 public void write(byte[] b,int off,int len) throws IOException 普通 输出部分字节数组数据
  1. OutputStream 本身是一个抽象类,如果要进行文件操作,则可以使用 FileOutputStream 子类完成操作。FileOutputStream 类的常用方法:(477页)
No. 方法 类型 描述
1 public FileOutputStream(File file) throws FileNotFoundException 构造 将内容输出到指定路径,如果文件已存在,则使用新的内容覆盖旧的内容
2 public FileOutputStream(File file,boolean append) throws FileNotFoundException 构造 如果将布尔参数设置为 true,表示追加新的内容到文件中
  1. 在程序中如果要进行文件数据的读取操作,可以使用 java.io.InputStream 类完成,此类可以完成字节数据的读取操作。InputStream 类的常用方法:(479页)
No. 方法 普通 描述
1 public void close() throws IOException 普通 关闭字节输入流
2 public abstract int read() throws IOException 普通 读取单个字节
3 public int read(byte[] b) throws IOException 普通 将数据读取到字节数组中,同时返回读取长度
4 public int read(byte[] b,int off,int len) 普通 将数据读取到部分字节数组中,同时返回读取的数据长度
  1. OutputStream 类中的 write() 中的参数包含的是要输出的数据,而 InputStream 类中的 read() 中的参数是为了接收输入数据准备的。(480页)
  2. java.io.InputStream 是一个抽象类,所以如果要想进行文件读取,需要使用 FileInputStream 子类。FileInputStream 类的常用方法:(481页)
方法 类型 描述
public FileInputStream(File file) throws IOException 构造 设置要读取文件数据的路径
  1. 利用 java.io.Writer 类可以直接实现字符数组(包含了字符串)的输出。Writer 类的常用方法:(484页)
No. 方法 类型 描述
1 public coid close() throws IOException 普通 关闭字节输出流
2 public void flush() throws IOException 普通 强制刷新
3 public Writer append(CharSequence csq) throws IOException 普通 追加数据
4 public void write(String str) throws IOException 普通 输出字符串数据
5 public void write(char[] cbuf) throws IOException 普通 输出字符数组数据
  1. Writer 类中直接提供了输出字符串数据的方法,这样就没有必要将字符串转成字节数组后再输出了。(485页)
  2. Writer 类是一个抽象类,要针对文件内容进行输出,可以使用 java.io.FileWriter 类实现 Writer 类对象的实例化操作。FileWriter 类的常用方法:(485页)
No. 方法 类型 描述
1 public FileWriter(File file) throws IOException 构造 设置输出文件
2 publci FileWriter(File file,boolean append) throws IOException 构造 设置输出文件以及是否进行数据追加
  1. java.io.Reader 类是实现字符数据输入的操作类,在进行数据读取时可以不使用字节数据,而直接依靠字符数据(方便处理中文)进行操作。Reader 类的常用方法:(486页)
No. 方法 类型 描述
1 public void close() throws IOException 普通 关闭字节输入流
2 public int read() throws IOException 普通 读取单个字符
3 public int read(char[] cbuf) throws IOException 普通 读取数据到字符数组中,返回读取长度
4 public long skip(long n) throws IOException 普通 跳过字节长度
  1. 在 Writer 类中存在直接输出字符串的操作,而 Reader 类中并没有直接返回字符串的操作,这是因为输出数据时可以采用追加的模式,所以随着时间的推移,文件有可能变得非常庞大。而如果在 Reader 类中提供了直接读取全部数据的方式,则有可能造成内存溢出问题。(487页)
  2. Reader 类是一个抽象类,要实现文件数据的字符流读取,可以利用 FileReader 子类为 Reader 类对象实例化。FileReader 类的常用方法:(487页)
方法 类型 描述
public FileReader(File file) throws IOException 构造 定义要读取的文件路径
  1. 字节流与字符流最大的区别是:字节流直接与终端文件进行数据交互,字符流需要将数据经过缓冲区处理才与终端文件数据交互。(488页)
  2. 在使用 OutputStream 输出数据时即使最后没有关闭输出流,内容也可以正常输出,但是反过来如果使用的是字符输出流 Writer,在执行到最后如果不关闭输出流,就表示在缓冲区中处理的内容不会被强制性清空,所以就不会输出数据。如果有特殊情况不能关闭字符输出流,可以使用 flush() 方法强制清空缓冲区。(488页)
  3. 在开发中,对于字节数据处理是比较多的,例如:图片、音乐、电影、文字。而字符流最大的好处是它可以进行中文的有效处理。在开发中,如果要处理中文时应优先考虑字符流,如果没有中文问题,建议使用字节流。(489页)
  4. 在 DOS(Windows 定义的命令行工具)中,可以利用 copy 实现文件的复制操作。此命令的语法为:“copy 源文件路径 目标文件路径”。(491页)
  5. 在实现文件的复制操作时,采用边读取边输出的操作方式,每次从源文件输入流中读取部分数据,而后将这部分数据交给输出流输出,这样的做法不会占用较大的内存空间,但是会适当损耗一些时间。(491页)
  6. 如果要在开发时实现二进制文件的保存操作,一定要利用 OutputStream 输出(唯一的方案)。(492页)

持续更新中……