《Java核心技术》读书笔记

162 阅读9分钟

1 Java程序设计平台

  1. Java是一门语言,也是一个执行器和库。
  2. Java“白皮书”关键术语 1)简单性:语法和C++接近,语法简单;另一方面是小,解释器和基本库只有40kb左右,支持在微型机上运行。

2)面向对象:面向对象是一门程序设计技术,关注的是对象与接口上面。Java支持了这个细节。

3)分布式:Java底层实现了网络协议,可以通过网络像本地那样访问远程文件。

4)健壮性:编译检查、运行时检查、沙箱机智。

5)安全性:Java平台提供了安全能力,包括类型强制校验、内存管理等,还有一些是提供了加密等安全能力。官方文档

6)体系结构中立:编译目标是个独立的文件结构,只和Java运气有关,和其他无关。

7)可移植性:Java设计规范和操作系统无关,例如类型的大小等,这种确保了可移植性。

8)解释型:Java是解释型语言,在执行器上面翻译编译的文件。但是现在也有了即时编译功能。

9)高性能:即时编译

10)多线程:

11)动态性:Java是个静态语言,但是有一定的动态性,即在代码运行的过程中改变数据结构等,主要是通过反射机制来体现。

2. Java程序设计环境

  1. Java术语

  2. Java没有任何无符号形式的int、long、short或者byte类型的数据。

  3. Unicode转义序列会在解析代码之前得到处理。例如,"\u0022+\u0022"并不是一个由引号(U+0022)包围加号构成的字符串。实际上,\u0022会在解析之前转换为",这会得到""+"",也就是一个空串。更隐秘地,一定要当心注释中的\u。注释 // \u00A0 这是一个注释 会产生一个语法错误,因为读程序时\u00A0会替换为一个换行符。

  4. 在Java中,char类型描述了UTF-16编码中的一个代码单元。我们强烈建议不要在程序中使用char类型,除非确实需要处理UTF-16代码单元。最好将字符串作为抽象数据类型处理(有关这方面的内容将在3.6节讨论)。

  5. 提示:如果想要知道哪些Unicode字符属于Java中的“字母”,可以使用Character类的isJavaIdentifierStart和isJavaIdentifierPart方法来检查。

提示:尽管$是一个合法的Java字符,但不要在你自己的代码中使用这个字符。它只用在Java编译器或其他工具生成的名字中。

  1. StringBuilder不是线程安全的(Builder:建筑者,建筑工人有安全隐患),StringBuffer是安全的。但是一般建议使用StringBuilder,速度快。

四、面向对象程序设计

  1. 过程化语言的操作顺序是:算法+数据结构=程序;面向对象是反过来的,是数据结构+算法=程序。

  2. 类是构造对象的模板或蓝图,由类构造对象的过程称作对象的实例。

  3. 封装是把属性和行为包装在一起,对使用者隐藏实现细节的方式。其中属性是类的状态,每个方法都有可能改变类的状态。封装最重要的特点是:隐藏属性,所有的属性改变只能通过类自己的方法。

封装提高了类的重用性和可靠性。不论数据结构如何变化,只要对外提供的方法没有变化就可以;

  1. 通过扩展一个类来建立一个新类的过程叫做继承。

  2. 对象的三个特性:行为、状态和标识。同一个类的对象有着家族史的相似性,状态的改变一定是被方法调用的,不能是自发性的。一个类的状态不能唯一标识一个类,所以还需要类的标识来定义类的唯一身份。

  3. 过程化语言有个main方法是程序的顶部入口,但是面向对象的语言是没有顶部的。所以上手思路是:从设计类开始,然后往类里面添加方法。

在项目开发中,类往往是名词,方法是动词。

  1. 类与类之间的关系 类与类之间的常见关系有:依赖(use-a)、聚合(has-a)和继承(is-a)。

  2. Java对象变量存储的并不是对象本身,而是对象的引用。 9.Date表示的是一个时间点,LocalDate表示的是一个日历表示方法。
    10.注意不要编写返回引用可变对象的访问器方法。 示例代码

如果需要返回一个可变对象的引用,首先应该对它进行克隆。 11.final修饰的变量理论上应该是不变或不可变的。 12. 静态常量,所以static放前面更好。 13. 静态方法的使用场景:1)不需要使用类的属性,有显示变量提供,例如Math.pow();2)只需要使用类的静态变量。

14.工厂方法的使用

  1. Java程序设计语言总是采用按值调用。也就是说,方法得到的是所有参数值的一个拷贝,特别是,方法不能修改传递给它的任何参数变量的内容。(具体参考4.5方法参数)
  2. 如果多个方法(比如,StringBuilder构造器方法)有相同的名字、不同的参数,便产生了重载。编译器必须挑选出具体执行哪个方法,它通过用各个方法给出的参数类型与特定方法调用所使用的值类型进行匹配来挑选出相应的方法。如果编译器找不到匹配的参数,就会产生编译时错误,因为根本不存在匹配,或者没有一个比其他的更好。(这个过程被称为重载解析(overloading resolution)。)

17.显式域初始化时,可以使用方法的。 18. Java的初始化还有第三种方式:初始化块。 19. 20. 如果对类的静态域进行初始化的代码比较复杂,那么可以使用静态的初始化块。 21. 类的设计技巧 1)一定要保证数据私有。这是保证封装的基础。

2)一定要对数据初始化。实际使用中没有感受到必要性。

3)不要在类中使用过多的基本类型。应该做好类的拆分,用类替代过多的基本类型。

4)不是所有的域都需要访问器或修改器

5)将职责过多的类进行分解

6)类名和方法名要能体现他的职责

7)优先使用不可变类。使用不可变类可以避免多线程等问题。

五、继承

  1. 继承就是利用现有类构造新类的能力。
  2. super和this不是同一个概念。this是一个引用,super是一个关键词,用来告诉编译器调用父类方法,不能够赋值给一个变量。
  3. 多态是同一个行为具有多个不同表现形式或形态的能力。 多态就是同一个接口,使用不同的实例而执行不同操作。
  4. 能够决定类能力的程序叫做反射。
  5. 在程序运行期间,Java运行时系统始终为所有的对象维护一个被称为运行时的类型标识。这个信息跟踪着每个对象所属的类。虚拟机利用运行时类型信息选择相应的方法执行。 然而,可以通过专门的Java类访问这些信息。保存这些信息的类被称为Class,这个名字很容易让人混淆。Object类中的getClass( )方法将会返回一个Class类型的实例。
  6. Class.forName("")这个方法只有在className是类名或接口名时才能够执行,否则会抛出一个checked exception(已检查异常),无论何时使用这个方法,应该都使用一个异常处理器。

六、接口、Lambda表达式和内部类

  1. 常用函数式接口
  2. 双括号初始化 这里使用了匿名内部类的方法。 创建匿名内部类的方法有两种
new interface(){}或者new 父类(){}

内部的双括号是对象构造块。 3. 代理:代理是在编译的时候,无法确定接口的具体类,需要在运行的时候来实现。所有的代理类都实现InvocationHandle类。后续需要补齐

七、异常、断言和日志

  1. 需要注意的是,所有的异常都是由Throwable继承而来,但在下一层立即分解为两个分支:Error和Exception。Error类层次结构描述了Java运行时系统的内部错误和资源耗尽错误。应用程序不应该抛出这种类型的对象。如果出现了这样的内部错误,除了通告给用户,并尽力使程序安全地终止之外,再也无能为力了.
  2. “如果出现RuntimeException异常,那么就一定是你的问题”是一条相当有道理的规则。

八、泛型程序设计

  1. 一个泛型类(generic class)就是具有一个或多个类型变量的类。
  2. 在Java库中,使用变量E表示集合的元素类型,K和V分别表示表的关键字与值的类型。T(需要时还可以用临近的字母U和S)表示“任意类型”。
  3. 泛型方法实际上是一个带有参数的普通方法。类型变量放在修饰符的后面,返回类型的前排
class ArrayAlg{
	public static<T> T getMiddle(T... a)
    {
 		return a[a.length/2]
    }
}
  1. 类型擦除 无论何时定义一个泛型类型,都自动提供了一个相应的原始类型(raw type)。原始类型的名字就是删去类型参数后的泛型类型名。擦除类型变量,并替换为限定类型。
  2. class Interval<T extends Serializable &Comparable>会发生什么。如果这样做,原始类型用Serializable替换T,而编译器在必要时要向Comparable插入强制类型转换。为了提高效率,应该将标签(tagging)接口(即没有方法的接口)放在边界列表的末尾.