《Java: The Complete Reference》等书读书笔记

春节期间读了下《Java:TheCompleteReference》发现这本书写的深入浅出,我Java
强烈推介IDEA2020.2破解激活,IntelliJ IDEA 注册码,2020.2 IDEA 激活码

春节期间读了下《Java: The Complete Reference》发现这本书写的深入浅出,我想一个问题,书中很多内容我们也知道,但是为什么我们就写不出这样一本书,这么全面,这么系统,这么简单易懂。不得不佩服Herbert Schildt的编程功底,需要提到的是Herbert Schildt写了很多Java和C、C++的书,他是C、C++、Java和C#编程语言的权威,是ANSI/ISO组织C语言标准化委员会的委员。

Herbert Schildt最新的基本Java著作其实都差不多,在内容侧重点上有点不同。本文虽然名为《Java: The Complete Reference》《Java 8 编程参考官方教程(第9版)》读书笔记,但是实则是同时参考以下几本。

《Java: The Complete Reference, Ninth Edition》   中文版《Java 8 编程参考官方教程(第9版)》
《Java: A Beginner's Guide, Sixth Edition》 中文版《Java 8 编程入门官方教程 第6版》
《Java Programming: A Comprehensive Introduction》 中文版 《Java 7程序设计入门经典》
《Java: The Complete Reference》等书读书笔记

 

《Ivor Horton's Beginning Java Java 7 Edition Edition》

《Java: The Complete Reference》等书读书笔记

 

《The Java Tutorial: A Short Course on the Basics (6th Edition) (Java Series) 6th Edition》

《Java: The Complete Reference》等书读书笔记

本文就是一个针对Java一些关键的知识点学习的笔记。

 

Java的起源

驱使计算机语言革新的因素有两个:程序设计技术的改进 和 计算环境的改变。

 

Java和C和C++的关系

Java继承了C的语法,Java的对象模型从C++改编而来。

Java不是C++的增强版,Java不是为替代C++而设计,而是为了解决特定问题而设计,C++则是用来解决另一个不同系列的问题。

Java的魔法:字节码

Java同时 解决安全性问题和可移植性问题的关键在于Java编译器的编译结果不是可执行代码,而是字节码bytecode。

字节码是一系列设计用来由Java虚拟机(JVM)的Java运行时执行的高度优化的指令。

只需要对每个平台实现Java虚拟机,尽管平台之间的Java虚拟机不同,但是他们都可以理解相同的Java字节码。

Java程序由JVM执行也使其更安全,因为每一个Java程序都处于JVM的控制下,此外Java语言中的一些限制也增强了安全性。

程序被解释要比被编译为可执行代码慢很多,对于Java两者区别不明显,因为字节码已经被高度优化。

虽然Java是解释型语言,但这在技术上不妨碍Java字节码迅速编译为本机代码。Sun在Java的初始版本之后提供了HotSpot技术,HotSpot提供了一个JIT字节码编译器。

当JIT成为JVM的一部分之后,它可以根据逐条命令将字节码实时转换为可执行代码,因为Java执行的各种检查只在运行时才进行,所以不能将整个Java程序一次性编译为可执行代码,而是在执行期间需要时JIT才编译代码。

不是所有的字节码序列都被编译,只有那些能从编译受益的字节码才会被编译,其余的代码被简单的解释。

编译程序

javac  Example.java  

编译器javac创建一个包含程序字节码的名为 Example.class的文件(字节码)。

编译过Java源代码后,每个单独的类被放在自己的输出文件中,输出文件以类名+.class扩展名。因为源码文件和.class文件名称相同,所以将Java源代码文件的名称指定为它包含的类名是个好主意。

运行程序

java  Example

由Java解释器java运行程序,需要将类名Example作为实参传递。

 

注释

支持3种注释:/**/和//和文档注释,文档注释用于生成说明程序的HTML文件。以/**开头,以*/结束。

 

缩进原则

Java本身是形式自由的语言,但是推荐缩进,在每个左括号之后缩进一级,而在每个右括号之后提前一级。

代码块

将语句包含在{}之间实现,代码块一旦创建就成为一个逻辑单元。

代码块不会增加任何开销,{}只存在于源码中,Java不会执行{}。

空白符:空格,制表符,换行符。每个标记之间至少有一个空白符即可。

标识符:标识符用于命名事物,例如类,变量和方法。标识符可以由大小写字母,数字,下划线,美元符号等字符组成的任意序列。

不能以数字开头。Java是大小写敏感的。

 

字面值:常量的值是通过使用表示常量的字面值创建的。

 

分隔符:最常用的是分号,分号是语句的终止符。此外还有(),{}.[]等等。

关键字:50个。

 

 

集合

Object类定义的hashCode()方法能根据对象在内存中的位置,为对象生成int类型的散列码,键的散列码一般用于计算Map在内存中存储对象而分配的偏移量,偏移量决定了键值对的存储位置。

String s="abc";

ss.hashCode();输出其hash值。

----------------------------------------------------------------

以下关于集合参考:集合类操作优化经验总结

ArrayList 和 Vector 使用了数组实现,ArrayList 没有对任何一个方法提供线程同步,因此不是线程安全的,Vector 中绝大部分方法都做了线程同步,是一种线程安全的实现。
Vector 非常类似于 ArrayList,区别是 Vector 是线程同步的。
由 Vector 创建的 Iterator,虽然和 ArrayList 创建的 Iterator 是同一接口,但是,因为 Vector 是同步的,
当一个 Iterator 被创建而且正在被使用,另一个线程改变了 Vector 的状态(例如,添加或删除了一些元素),这时调用 Iterator 的方法时将抛出 ConcurrentModificationException,因此必须捕获该异常。

由于作为 Key 的对象将通过计算其散列函数来确定与之对应的 Value 的位置,因此任何作为 key 的对象都必须实现 HashCode 和 Equals 方法。
HashCode 和 Equals 方法继承自根类 Object,如果你用自定义的类当作 Key 的话,要相当小心,按照散列函数的定义,如果两个对象相同,即 obj1.equals(obj2)=true,则它们的 HashCode 必须相同,
但如果两个对象不同,则它们的 HashCode 不一定不同,如果两个不同对象的 HashCode 相同,这种现象称为冲突,冲突会导致操作哈希表的时间开销增大,所以尽量定义好的 HashCode() 方法,能加快哈希表的操作。
如果相同的对象有不同的 HashCode,对哈希表的操作会出现意想不到的结果(期待的 Get 方法返回 Null),要避免这种问题,最好同时复写 Equals 方法和 HashCode 方法,而不要只写其中一个。

HashMap 和 Hashtable 类似,不同之处在于 HashMap 是线程非同步的,并且允许 Null,即 Null Value 和 Null Key。
但是将 HashMap 视为 Collection 时(values() 方法可返回 Collection),其迭代子操作时间开销和 HashMap 的容量成比例。
因此,如果迭代操作的性能相当重要的话,不要将 HashMap 的初始化容量设得过高,或者 Load Factor 参数设置过低。

WeakHashMap 是一种改进的 HashMap,它对 Key 实行“弱引用”,如果一个 Key 不再被外部所引用,那么该 Key 可以被 GC 回收。
WeakHashMap 特点是当除了自身有对 Key 的引用外,如果此 Key 没有其他引用,那么此 Map 会自动丢弃该值。
WeakHashMap 主要通过 expungeStaleEntries 这个函数来实现移除其内部不用的条目,从而达到自动释放内存的目的。
基本上只要对 WeakHashMap 的内容进行访问就会调用这个函数,从而达到清除其内部不再为外部引用的条目。
但是如果预先生成了 WeakHashMap,而在 GC 以前又不曾访问该 WeakHashMap, 那不是就不能释放内存了吗?果不其然,WeakHashMap 这个时候并没有自动帮我们释放不用的内存。
总的来说,WeakHashMap 并不是你什么也干它就能自动释放内部不用的对象的,而是在你访问它的内容的时候释放内部不用的对象。
WeakHashMap 实现弱引用,是因为它的 Entry<K,V>是继承自 WeakReference<K>的。
WeakHashMap 类是线程不同步的,可以使用 Collections.synchronizedMap 方法来构造同步的 WeakHashMap, 每个键对象间接地存储为一个弱引用的指示对象。因此,不管是在映射内还是在映射之外,只有在垃圾回收器清除某个键的弱引用之后,该键才会自动移除。需要注意的是,WeakHashMap 中的值对象由普通的强引用保持。因此应该小心谨慎,确保值对象不会直接或间接地强引用其自身的键,因为这会阻止键的丢弃。注意,值对象可以通过 WeakHashMap 本身间接引用其对应的键,这就是说,某个值对象可能强引用某个其他的键对象,而与该键对象相关联的值对象转而强引用第一个值对象的键。
处理此问题的一种方法是,在插入前将值自身包装在 WeakReferences 中,如:m.put(key, new WeakReference(value)),然后,分别用 get 进行解包,该类所有“collection 视图方法”返回的迭代器均是快速失败的,在迭代器创建之后,如果从结构上对映射进行修改,除非通过迭代器自身的 Remove 或 Add 方法,其他任何时间任何方式的修改,迭代器都将抛出 ConcurrentModificationException。因此,面对并发的修改,迭代器很快就完全失败,而不是冒着在将来不确定的时间任意发生不确定行为的风险。
注意,我们不能确保迭代器不失败,一般来说,存在不同步的并发修改时,不可能做出任何完全确定的保证。

LinkedList 使用了循环双向链表数据结构,由一系列表项连接而成,一个表项总是包含 3 个部分,元素内容、前驱表项和后驱表项。
当 ArrayList 对容量的需求超过当前数组的大小时,需要进行扩容。扩容过程中,会进行大量的数组复制操作,而数组复制时,最终将调用 System.arraycopy() 方法。LinkedList 由于使用了链表的结构,因此不需要维护容量的大小,然而每次的元素增加都需要新建一个 Entry 对象,并进行更多的赋值操作,在频繁的系统调用下,对性能会产生一定的影响,在不间断地生成新的对象还是占用了一定的资源。而因为数组的连续性,因此总是在尾端增加元素时,只有在空间不足时才产生数组扩容和数组复制。
ArrayList 是基于数组实现的,而数组是一块连续的内存空间,如果在数组的任意位置插入元素,必然导致在该位置后的所有元素需要重新排列,因此其效率较差,尽可能将数据插入到尾部。LinkedList 不会因为插入数据导致性能下降。
ArrayList 的每一次有效的元素删除操作后都要进行数组的重组,并且删除的元素位置越靠前,数组重组时的开销越大,要删除的元素位置越靠后,开销越小。LinkedList 要移除中间的数据需要便利完半个 List。

HashMap 是将 Key 做 Hash 算法,然后将 Hash 值映射到内存地址,直接取得 Key 所对应的数据。在 HashMap 中,底层数据结构使用的是数组,所谓的内存地址即数组的下标索引。HashMap 的高性能需要保证以下几点:
Hash 算法必须是高效的;
Hash 值到内存地址 (数组索引) 的算法是快速的;
根据内存地址 (数组索引) 可以直接取得对应的值。
HashMap 实际上是一个链表的数组。前面已经介绍过,基于 HashMap 的链表方式实现机制,只要 HashCode() 和 Hash() 方法实现得足够好,能够尽可能地减少冲突的产生,那么对 HashMap 的操作几乎等价于对数组的随机访问操作,具有很好的性能。但是,如果 HashCode() 或者 Hash() 方法实现较差,在大量冲突产生的情况下,HashMap 事实上就退化为几个链表,对 HashMap 的操作等价于遍历链表,此时性能很差。
HashMap 的一个功能缺点是它的无序性,被存入到 HashMap 中的元素,在遍历 HashMap 时,其输出是无序的。如果希望元素保持输入的顺序,可以使用 LinkedHashMap 替代。
LinkedHashMap 继承自 HashMap,具有高效性,同时在 HashMap 的基础上,又在内部增加了一个链表,用以存放元素的顺序。
HashMap 通过 hash 算法可以最快速地进行 Put() 和 Get() 操作。TreeMap 则提供了一种完全不同的 Map 实现。从功能上讲,TreeMap 有着比 HashMap 更为强大的功能,它实现了 SortedMap 接口,这意味着它可以对元素进行排序。TreeMap 的性能略微低于 HashMap。如果在开发中需要对元素进行排序,那么使用 HashMap 便无法实现这种功能,使用 TreeMap 的迭代输出将会以元素顺序进行。LinkedHashMap 是基于元素进入集合的顺序或者被访问的先后顺序排序,TreeMap 则是基于元素的固有顺序 (由 Comparator 或者 Comparable 确定)。
LinkedHashMap 是根据元素增加或者访问的先后顺序进行排序,而 TreeMap 则根据元素的 Key 进行排序。

----------------------------------------------------------------

--未完--

 

本文来源21aspnet,由架构君转载发布,观点不代表Java架构师必看的立场,转载请标明来源出处:https://javajgs.com/archives/2109

发表评论