Java核心技术:卷Ⅰ基础知识(原书第10版)

凯S.霍斯特曼

1.1 Java程序设计平台

  • 1)简单性 2)面向对象 3)分布式 4)健壮性 5)安全性 6)体系结构中立 7)可移植性 8)解释型 9)高性能 10)多线程 11)动态性
  • 简单地讲,面向对象设计是一种程序设计技术。它将重点放在数据(即对象)和对象的接口上。
  • Java与C++的主要不同点在于多重继承,在Java中,取而代之的是更简单的接口概念
  • 虚拟机有一个选项,可以将执行最频繁的字节码序列翻译成机器码,这一过程被称为即时编译。
  • 字符串是用标准的Unicode格式存储的。
  • 字节码可以(在运行时刻)动态地翻译成对应运行这个应用的特定CPU的机器码。
  • 在网页中运行的Java程序称为applet。
  • 早期的Java是解释型的。现在Java虚拟机使用了即时编译器,因此采用Java编写的“热点”代码其运行速度与C++相差无几,有些情况下甚至更快。

3.1 一个简单的Java应用程序

  • Java区分大小写
  • 关键字public称为访问修饰符
  • 关键字class表明Java程序中的全部内容都包含在类中。
  • 源代码的文件名必须与公共类的名字相同,并用.java作为扩展名
  • 根据Java语言规范,main方法必须声明为public
  • Java中任何方法的代码都用“{”开始,用“}”结束。
  • Java中的main方法必须是静态的。
  • 如果希望在终止程序时返回其他的代码,那就需要调用System. exit方法。
  • 在Java中,每个句子必须用分号结束。
  • System.out还有一个print方法,它在输出之后不换行
  • 第3种注释可以用来自动地生成文档。这种注释以/**开始,以*/结束
  • 在Java中,一共有8种基本类型(primitive type),其中有4种整型、2种浮点类型、1种用于表示Unicode编码的字符单元的字符类型char(请参见论述char类型的章节)和1种用于表示真值的boolean类型。
  • Java有一个能够表示任意精度的算术包,通常称为“大数值”(big number)。虽然被称为大数值,但它并不是一种新的Java类型,而是一个Java对象。
  • int类型最常用。但如果表示星球上的居住人数,就需要使用long类型了。byte和short类型主要用于特定的应用场合
  • 在Java中,整型的范围与运行Java代码的机器无关。
  • 十六进制数值有一个前缀0x或0X(如0xCAFE)
  • 注意,Java没有任何无符号(unsigned)形式的int、long、short或byte类型。
  • double表示这种类型的数值精度是float类型的两倍(有人称之为双精度数值)
  • 没有后缀F的浮点数值(如3.14)默认为double类型
  • 可以使用十六进制表示浮点数值。例如,0.125=2-3可以表示成0x1.0p-3。在十六进制表示法中,使用p表示指数,而不是e。注意,尾数采用十六进制,指数采用十进制。指数的基数是2,而不是10。
  • 如果在数值计算中不允许有任何舍入误差,就应该使用BigDecimal类
  • char类型的字面量值要用单引号括起来
  • Unicode转义序列会在解析代码之前得到处理。
  • 码点(code point)是指与一个编码表中的某个字符对应的代码值
  • UTF-16编码采用不同长度的编码表示所有Unicode码点。
  • 我们强烈建议不要在程序中使用char类型,除非确实需要处理UTF-16代码单元。最好将字符串作为抽象数据类型处理
  • 整型值和布尔值之间不能进行相互转换。
  • 变量名必须是一个以字母开头并由字母或数字构成的序列。
  • 尽管$是一个合法的Java字符,但不要在你自己的代码中使用这个字符。它只用在Java编译器或其他工具生成的名字中。
  • 在Java中,变量的声明尽可能地靠近变量第一次使用的地方,这是一种良好的程序编写风格。
  • 利用关键字final指示常量
  • 关键字final表示这个变量只能被赋值一次。一旦被赋值之后,就不能够再更改了
  • 可以使用关键字static final设置一个类常量。
  • 类常量的定义位于main方法的外部。
  • 当参与/运算的两个操作数都是整数时,表示整数除法;否则,表示浮点除法
  • 整数被0除将会产生一个异常,而浮点数被0除将会得到无穷大或NaN结果。
  • 对于使用strictfp关键字标记的方法必须使用严格的浮点计算来生成可再生的结果
  • 在Math类中,为了达到最快的性能,所有的方法都使用计算机浮点单元中的例程。如果得到一个完全可预测的结果比运行速度更重要的话,那么就应该使用StrictMath类。
  • 强制类型转换的语法格式是在圆括号中给出想要转换的目标类型,后面紧跟待转换的变量名。
  • 如果想对浮点数进行舍入运算,以便得到最接近的整数(在很多情况下,这种操作更有用),那就需要使用Math.round方法:
  • 前缀形式会先完成加1;而后缀形式会使用变量原来的值。
  • 建议不要在表达式中使用++,因为这样的代码很容易让人困惑,而且会带来烦人的bug。
  • &&和||运算符是按照“短路”方式来求值的:如果第一个操作数已经能够确定表达式的值,第二个操作数就不必计算了。
  • >>>运算符会用0填充高位,这与>>不同,它会用符号位填充高位。不存在<<<运算符。
  • Java字符串就是Unicode字符序列。
  • String类的substring方法可以从一个较大的字符串提取出一个子串
  • substring方法的第二个参数是不想复制的第一个位置。
  • Java语言允许使用+号连接(拼接)两个字符串。
  • 当将一个字符串与一个非字符串的值进行拼接时,后者被转换成字符串
  • 如果需要把多个字符串放在一起,用一个定界符分隔,可以使用静态join方法:
  • 由于不能修改Java字符串中的字符,所以在Java文档中将String类对象称为不可变字符串
  • 不可变字符串却有一个优点:编译器可以让字符串共享。
  • Java的设计者认为共享带来的高效率远远胜过于提取、拼接字符串所带来的低效率
  • 可以使用equals方法检测两个字符串是否相等。
  • 一定不要使用==运算符检测两个字符串是否相等!这个运算符只能够确定两个字符串是否放置在同一个位置上。
  • 空串""是长度为0的字符串
  • 空串是一个Java对象,有自己的串长度(0)和内容(空)
  • 如果在一个null值上调用方法,会出现错误。
  • length方法将返回采用UTF-16编码表示的给定字符串所需要的代码单元数量
  • 返回的不是一个空格,而是 的第二个代码单元。为了避免这个问题,不要使用char类型。这太底层了。
  • 要想通过控制台进行输入,首先需要构造一个Scanner对象,并与“标准输入流”System.in关联。
  • 因为输入是可见的,所以Scanner类不适用于从控制台读取密码。Java SE 6特别引入了Console类实现这个目的。
  • 不能在嵌套的两个块中声明同名的变量
  • 标签必须放在希望跳出的最外层循环之前,并且必须紧跟一个冒号。
  • collection这一集合表达式必须是一个数组或者是一个实现了Iterable接口的类对象(例如ArrayList)
  • 如果希望将一个数组的所有值拷贝到一个新的数组中去,就要使用Arrays类的copyOf方法

4.1 面向对象程序设计概述

  • 类(class)是构造对象的模板或蓝图。
  • 实现封装的关键在于绝对不能让类中的方法直接地访问其他类的实例域。程序仅通过对象的方法与对象数据进行交互
  • 首先从设计类开始,然后再往每个类中添加方法。
  • 识别类的简单规则是在分析问题的过程中寻找名词,而方法对应着动词。
  • 如果一个类的方法操纵另一个类的对象,我们就说一个类依赖于另一个类。
  • 聚合关系意味着类A的对象包含类B的对象。
  • 一个对象变量并没有实际包含一个对象,而仅仅引用一个对象。
  • 在Java中,任何对象变量的值都是对存储在另外一个地方的一个对象的引用。
  • 所有的Java对象都存储在堆中
  • 在一个源文件中,只能有一个公有类,但可以有任意数目的非公有类。
  • 构造器总是伴随着new操作符的执行被调用,而不能对一个已经存在的对象调用构造器来达到重新设置实例域的目的
  • ● 构造器与类同名● 每个类可以有一个以上的构造器● 构造器可以有0个、1个或多个参数● 构造器没有返回值● 构造器总是伴随着new操作一起调用
  • 不要在构造器中定义与实例域重名的局部变量
  • 关键字this表示隐式参数
  • 注意不要编写返回引用可变对象的访问器方法。
  • 如果需要返回一个可变对象的引用,应该首先对它进行克隆(clone)
  • 如果需要返回一个可变数据域的拷贝,就应该使用clone。
  • final关键字只是表示存储在evaluations变量中的对象引用不会再指示其他StringBuilder对象
  • 静态方法是一种不能向对象实施操作的方法
  • 按值调用(call by value)表示方法接收的是调用者提供的值。而按引用调用(call by reference)表示方法接收的是调用者提供的变量地址。
  • Java程序设计语言对对象采用的不是引用调用,实际上,对象引用是按值传递的。
  • 如果多个方法(比如,StringBuilder构造器方法)有相同的名字、不同的参数,便产生了重载。
  • 要完整地描述一个方法,需要指出方法名以及参数类型。这叫做方法的签名(signature)
  • 不能有两个名字相同、参数类型也相同却返回不同类型值的方法。
  • 如果在构造器中没有显式地给域赋予初值,那么就会被自动地赋为默认值:数值为0、布尔值为false、对象引用为null
  • 如果类中提供了至少一个构造器,但是没有提供无参数的构造器,则在构造对象时如果没有提供参数就会被视为不合法。
  • 首先运行初始化块,然后才运行构造器的主体部分
  • 可以为任何一个类添加finalize方法。finalize方法将在垃圾回收器清除对象之前调用。
  • 如果没有指定public或private,这个部分(类、方法或变量)可以被同一个包中的所有方法访问。
  • 1.一定要保证数据私有
  • 不要在类中使用过多的基本类型
  • 不是所有的域都需要独立的域访问器和域更改器
  • 5.将职责过多的类进行分解
  • 6.类名和方法名要能够体现它们的职责

5.1 类、超类和子类

  • 反射是指在程序运行期间发现更多的类及其属性的能力
  • 这是因为super不是一个对象的引用,不能将super赋给另一个对象变量,它只是一个指示编译器调用超类方法的特殊关键字。
  • 关键字this有两个用途:一是引用隐式参数,二是调用该类其他的构造器。同样,super关键字也有两个用途:一是调用超类的方法,二是调用超类的构造器
  • 一个对象变量(例如,变量e)可以指示多种实际类型的现象被称为多态(polymorphism)
  • 在Java中,子类数组的引用可以转换成超类数组的引用,而不需要采用强制类型转换。
  • 如果是private方法、static方法、final方法(有关final修饰符的含义将在下一节讲述)或者构造器,那么编译器将可以准确地知道应该调用哪个方法,我们将这种调用方式称为静态绑定(static binding)
  • 在覆盖一个方法的时候,子类方法不能低于超类方法的可见性。特别是,如果超类方法是public,子类方法一定要声明为public。
  • 不允许扩展的类被称为final类
  • 如果将一个类声明为final,只有其中的方法自动地成为final,而不包括域。
  • 如果一个方法没有被覆盖并且很短,编译器就能够对它进行优化处理,这个过程为称为内联(inlining)
  • 在进行类型转换之前,先查看一下是否能够成功地转换。这个过程简单地使用instanceof操作符就可以实现。
  • 在将超类转换成子类之前,应该使用instanceof进行检查。
  • 为了提高程序的清晰度,包含一个或多个抽象方法的类本身必须被声明为抽象的。
  • 除了抽象方法之外,抽象类还可以包含具体数据和具体方法
  • 类即使不含抽象方法,也可以将类声明为抽象类。
  • 在子类中定义equals方法时,首先调用超类的equals。如果检测失败,对象就不可能相等。如果超类中的域都相等,就需要比较子类中的实例域。
  • 如果重新定义equals方法,就必须重新定义hashCode方法,以便用户可以将对象插入到散列表中
  • 由于每个值分别包装在对象中,所以ArrayList的效率远远低于int[ ]数组。因此,应该用它构造小型集合,其原因是此时程序员操作的方便性要比执行效率更加重要。
  • 能够分析类能力的程序称为反射
  • 静态方法forName获得类名对应的Class对象
  • 在java.lang.reflect包中有三个类Field、Method和Constructor分别用于描述类的域、方法和构造器
  • 将公共操作和域放在超类

6.1 接口

  • 虽然在接口中不能包含实例域或静态方法,但却可以包含常量
  • 默认的克隆操作是“浅拷贝”,并没有克隆对象中引用的其他对象
  • 使用内部类只是为了把一个类隐藏在另外一个类的内部,并不需要内部类引用外围类对象。为此,可以将内部类声明为static,以便取消产生的引用

7.1 处理错误

  • “如果出现RuntimeException异常,那么就一定是你的问题”是一条相当有道理的规则。
  • Java语言规范将派生于Error类或RuntimeException类的所有异常称为非受查(unchecked)异常,所有其他的异常称为受查(checked)异常。
  • 断言机制允许在测试期间向代码中插入一些检查语句。当代码发布时,这些插入的检测语句将会被自动地移走。

8.1 为什么要使用泛型程序设计

  • 类型参数的魅力在于:使得程序具有更好的可读性和安全性。
  • 一个泛型类(generic class)就是具有一个或多个类型变量的类

9.1 Java集合框架

  • 队列通常有两种实现方式:一种是使用循环数组;另一种是使用链表

14.1 什么是线程

  • 不要调用Thread类或Runnable对象的run方法。直接调用run方法,只会执行同一个线程中的任务,而不会启动新线程。应该调用Thread.start方法。这个方法将创建一个执行run方法的新线程。