【工作】《码出高效》读书笔记

  • 这是一本兼顾深度与广度的通用技术书籍
  • 列出了每节目录,与个人觉得是知识点的地方
  • 以及每章概述

第1章 计算机基础

追根究底是深度分析和解决问题、提升程序员素质的关键所在,有助于编写高质
的代码。基础知识的深度认知决定着知识上层建筑的延展性。试问 对于如下的基
础知识,你的认知是否足够清晰呢?

  • 位移运算可以快速地实现乘除运算 那位移时要注意什么?
  • 浮点数的存储与计算为什么总会产生微小的误差?
  • 乱码产生的根源是什么?
  • 程序执行时 CPU 是如何与内存配合完成程序使命的?
  • 网络连接资源耗尽的 题本质是 么?
  • 黑客攻击的通常套路是什么?如何有效地防止?

本章从编程的角度深度探讨计算机组成原理、计算机网络、信息安全等相关内容,与具体编程语言无关。本章将不会讨论内部硬件的工作原理、网络世界的协议和底层传输方式、 全领域的攻防类型等内容。

1.1 走进0与1的世界

1.2 浮点数

1.2.1 科学计数法

1.2.2 浮点数表示

1.2.3 加减运算(解释浮点运算的偏差原因)

1.2.4 浮点数使用

1.3 字符集与乱码

  • 一个byte 8个bit的原因:有一个bit是校验位
  • GB2312 -> GBK -> GB18030(国家标准)
  • Unicode为每个字符设置了编码
  • UTF是Unicode的实现方式(或者叫压缩格式)分为UTF-8、UTF-16、UTF-32。UTF-8基本思路是越长用越短,会有1-6个字节对Unicode变长编码

1.4 CPU与内存

1.5 TCP/IP

1.5.1 网络协议

  • 网络协议族
  • 分层框架:应用层(HTTP、FTP等)、传输层(TCP、UDP)、网络层(IP)、链路层(IEEE)
  • 报文->路由->端到端->解析

1.5.2 IP协议

1.5.3 TCP握手

需要三次握手的原因:信息对等、防止脏连接


【工作】《码出高效》读书笔记_第1张图片
image.png

1.5.4 TCP 断开连接

四次挥手


【工作】《码出高效》读书笔记_第2张图片
image.png

1.5.5 连接池

1.6 信息安全

1.6.1 黑客与安全

1.6.2 SQL注入

1.6.3 XSS与CSRF

1.6.4 CSRF(跨站请求伪造)

1.6.5 HTTPS

  • 非对称性加密 RSA。核心在于对称加密在需要使用时,密钥的分发危险(不告诉别人,别人就没法加密),但是非对称加密,用于加密的公钥是随便公开的,自己解密的私钥自己保存即可。
  • CA认证中心 HTTPS证书
  • HTTPS通信大概可以分为双方建立加密通信并协定秘钥的过程(这里用非对称),和后续的数据传输过程(这里是对称加密)
  • 非对称加密 性能慢
  • TLS(传输层安全协议)是SSL(安全套接字层)的升级版

1.7 编程语言的发展

第2章 面向对象

本章开始讲解面向对象思想,并以 Java 为载体讲述面向对象思想在具体编程语
言中的运用与实践。当前主流的编程语言有50种左右,主要分为两大阵营:面向对象编程与面向过程编程。
面向对象编程( object -Oriented Programming, OOP )是划时代的编程思想变革,推动了高级语言的快速发展和工业化进程。 OOP的抽象、封装、继承、多态的理念使软件大规模化成为可能,有效地降低了软件开发成本、维护成本和复用成本。面向对象编程思想完全不同于传统的面向过程编程思想,使大型软件的开发就像搭积木那样隔离可控、高效简单,是当今编程领域的一股势不可当的潮流。 OOP 实践了软件工程的三个主要目标:可维护性、可重用性和可扩展性。

2.1 OOP理念

  • 面向过程的结构相对松散 强调如何流程化地解决问题;面向对象的思维更加内聚,强调高内聚、低藕合,先抽象模型,定义共性行为再解决实际问题。
  • 传统意义上 面向对象有三大特性封装、继承、多态。+ 本书强调的抽象

2.2 初识JAVA

2.3 类

2.3.1 类的定义

2.3.2 接口与抽象类

  • 抽象类是模板式设计,而接口是契约式设计。
  • 抽象类在被继承时体现的是 is -a 关系,接口在被实现时体现的是 can - do 关系。
  • Java 言中类的继承采用单继承形式,避免继承泛滥、菱形继承、循环继承,甚至“四不像”实现类的出现。
  • 当纠结定义接口还是抽象类时,优先推荐定义为接口,遵循接口隔离原则,按某个维度划分成多个接口,然后再用抽象类去 implements 某些接口,这样做可方便后续的扩展和重构。

2.3.3 内部类

  • 静态内部类,如:static class StaticinnerCass {} ;
  • 成员内部类,如:private class InstancelnnerCass {} ;
  • 局部内部类,定义在方法或者表达式内部;
  • 匿名内部类,如: (new Thread(){} ).start()。

无论是什么类型的内部类,都会编译成一个独立的class文件
类加载与外部类在同一个阶段进行。JDK源码中定义包内可见静态内部
类的方式很常见,这样做的好处是:

  • 作用域不会扩散到包外。
  • 可以通过”外部类 内部类”的方式直接访问。
  • 内部类可以访问外部类中的所有静态属性和方法。

2.3.4 访问权限控制

2.3.5 this 与 super

2.3.6 类关系

  • 继承 extends (is-a)
  • 实现 implements (can do)
  • 组合 类是成员变量(contains-a)
  • 聚合 类是成员变量 (has-a)比组合要松散,例如小狗有腿(组合),有狗绳(聚合)
  • 依赖 import类(use a)

随着业务和架构的发展,类与类的关系是会发生变化的。

2.3.7 序列化

2.4 方法

2.4.1 方法签名

2.4.2 参数

  • 形参
  • 实参
  • 可变参数(即 ... )觉得不建议用

2.4.3 构造方法

创建类对象时,会先执行父类和子类的静态代码块 然后再执行父类和子类的构造方法。并不是执行完父类的静态代码块和构造方法后,再去执行子类。静态代码块只运行一次,在第二次对象实例化时,不会运行。

2.4.4 类内方法

2.4.5 getter setter

2.4.6 同步与异步

2.4.7 覆写

2.5 重载

JVM在重载方法中,选择合适的目标方法的顺序如下:
1)精确匹配
2)如果是基本数据类型,自动转换为更大表示类型的数据类型
3)自动拆箱与装箱
4)从子类向上转型类型依次匹配
5)通过可变参数匹配

2.6 泛型

  • 泛型的本质是类型参数化,解决不确定具体对象类型的问题。
  • 尖括号里的每个元素都指代一种未知类型(可以是T等,也可以是一个名字)
  • 泛型擦除成Object
  • 泛型与集合的联合使用,可以把泛型的功能发挥到极致。

2.7 数据类型

2.7.1 基本数据类型

  • 对象头最小占用空间为12个字节
  • 实例数据
  • 对齐填充

2.7.2 包装类型

2.7.3 字符串

  • String是只读的
  • String常量池

第3章 代码风格

一致性很重要。
代码风格并不影响程序运行,没有潜在的故障风险,通常与数据结构、逻辑表达无关,是指不可见字符的展示方式、代码元素的命名方式和代码注释风格等。比如,大括号是否换行、缩进方式、常量与变量的命名方式、注释是否统一放置在代码上方等。代码风格的主要诉求是清爽统一、便于阅读和维护。统一的代码风格可以让开发工程师们没有严重的代码心理壁垒,每个人都可以轻松地阅读并快速理解代码逻辑,便于高效协作,逐步形成团队的代码“味道”。

3.1 命名规约

3.1.1 常量

3.1.2 变量

3.2 代码展示风格

3.2.1 缩进、空格与空行

3.2.2 换行与高度

3.2.3 控制语句

3.3 代码注释

3.3.1 注释三要素

3.3.2 注释格式

第4章 走进JVM

Oracle的HotSpot JVM 实现,是目前最主流的JAVA虚拟机。它采用解释与编译混合执行的模式。本章从字节码说起,分析类加载的过程,并结合内存布局,讲解对象创建与垃圾回收等各个知识点。

4.1 字节码

  • 是一种中间码
  • JAVA总共有200多个指令
  • 因此叫ByteCode
  • 解释执行 + 编译执行(热点代码直接JIT编译成机器码)

主要指令类型有

  • 加载或存储指令
  • 运算指令
  • 类型转换指令
  • 对象创建或访问指令
  • 操作栈指令
  • 方法调用与返回指令
  • 同步指令

4.2 类加载过程

  • ClassLoader类加载过程
  • Load、Link、Init过程
  • Class类 - 可以通过反射把实现和定义解耦,可以获取类的声明,注解,方法等

类加载器的分层体系

  • 最高层 Bootstrap ClassLoader:负责JAVA的核心类型如 Object System String 等
  • 第二层 Platform/Extension ClassLoader:加载扩展的系统类如加密
  • 第三层 Application ClassLoader:加载用户自定义的CLASSPATH下的类

其中Bootstrap是c语言实现的,后面是JAVA实现的
类加载器具有等级制度,但是并无继承关系,以组合的方式来复用父加载器的功能。
-XX:+TraceClassLoading可以查看加载了哪个jar中哪个类。
下图说明了类的加载顺序和覆盖机制,即高层优先,低层不能覆盖高层。

image.png

用户可以自定义类加载器

  • 隔离加载类,防止冲突
  • 修改类加载方式 :按需动态加载
  • 扩展源代码:如从网络加载
  • 有时候源码加密后,同样需要自定义类加载器还原

4.3 内存布局

image.png
  • 堆区:新生代(Eden + S0+ S1)和老年代,在S区停留x次后,移动到老年代
  • 元空间 MetaSpace(前身Permanent区)即以前的永久代。主要存储类的信息
  • 虚拟机栈:执行方法的内存区,线程私有
  • 本地方法栈(native方法):本地方法调用的栈数据,也是线程私有的
【工作】《码出高效》读书笔记_第3张图片
image.png

4.4 对象实例化

4.5 垃圾回收

  • 与GC Roots失去引用(GC Roots指常量、静态对象、方法栈中的对象)
  • 标记-清除是GC的基础
  • 引入Mark-Copy解决碎片问题

主要GC算法:

  • Serial 常用与YGC 单线程串行,stop the world
  • CMS(初始标记、并发标记、重新标记、并发清除)共4个步骤。其中1和3 STW
  • G1 将对划分为Regoin,优先回收垃圾较多的区域,对停顿时间更可控

第5章 异常与日志

捕获异常时需要分清稳定代码和非稳定代码。
如果异常在当前方法的处理能力范围之内且没有必要对外透出,那么就直接
捕获异常并做相应处理;否则向上抛出,由上层方法或者框架来处理。

5.1 异常分类

  • 所有异常都是 Throwable 的子类
  • 分为Error(致命异常)和Exception(非致命异常)

5.2 try 代码块

  • finally 是在 return 表达式运行后执行的。因此finally里面的计算可能是无用的。
  • 不要在finally中使用return,会使返回值判断变得复杂

5.3 异常的抛与接

5.4 日志

5.4.1 日志规范

5.4.2 日志框架

image.png
  • 日志门面:它只提供一套接口规范如slf4j,自身不负责日志功能的实现
  • 日志库:主流的日志库有三个 分别是 log4j,log-jdk,logback(log4j的升级版)
  • 曰志适配器:包括日志门面适配器如(slf4j-log4j12)和日志库适配器

第6章 数据结构与集合

本书中其他地方出现的集合概念,都指的是 Collection来保存各种各样的对象。非是数学意义上的Set(互异)。在进入高并发编程时代后,由集合引发的相关故障占比越来越高。比如,多线程共享集合时出现的脏数据问题,某些集合在数据扩容时出现节点之间的死链问题;写多读少的场景误用某些集合导致性能下降问题等。本章将从数组讲起,引申到集合框架,再到重点集合源码分析,最后介绍高并发集合框架,目的是对集合的了解成竹在胸、运用得心应手。

6.1 数据结构

  • 数据结构定义:数据结构是指逻辑意义上的数据组织方式及其相应的处理方式。
  • 数据结构分类:线性、树、图、哈希

6.2 集合框架图

  • 框架图中主要分为两类。第一类是按照单个元素存储的 Collection,第二类是KV结构的Map
  • Collection接口主要有Set、List、Queue三大类子实现
  • Map主要有HashMap、TreeMap、SortedMap等
image.png

6.2.1 List 集合

  • 最常用的是 ArrayList和LinkedList 两个集合类
  • LinkedList 的优点在于可以将零散的内存单元通过附加引用的方式关联起来。内存利用率较高

6.2.2 Queue 集合

  • 队列是一种特殊的线性表,它只允许在表的一端进行获取操作,在表的另一端进行插入操作
  • 经常被作为Buffer (数据缓冲区)使用

6.2.3 Map 集合

  • Map 类提供三种 Collection 视图
  • KeySet、ValueSet、EntrySet
  • 最早用于存储键值对的 Hashtable 因为性能瓶颈已经被淘汰
  • HashMa 线程是不安全的,ConcurrentHashMap 是线程安全的
  • TreeMap是Key有序的Map类集合,有headMap、lower/higher key等特别的操作接口

6.2.4 Set 集合

  • Set 体系最常用的是 HashSet、TreeSet、LinkedHashSet三个集合类
  • HashSet 从源码分析是使 HashMap 来实现的(Valu 固定为一个静态对象)
  • LinkedHashSet维护了插入元素的顺序

6.3 集合初始化

  • 合理初始大小可以避免被动扩容和数组复制的额外开销
  • HashMap扩容还会重建哈希表,非常影响性能
  • 默认值大小ArrayList 为10,HashMap 默认为16

6.4 数组与集合

  • 数组是固定容量大小的
  • 对于动态大小的数组,集合提供了 Vector和ArrayList两个类,前者是线程安全,性能较差,基本弃用
  • Arrays 是针对数组对象进行操作的工具类,包括数组的排序、查找、对比、拷贝等操作。通过这个工具类也可以把数组转成集合
  • Arrays asList 体现的是适配器模式,后台的数据仍是原有数组。并不是通用意义上的ArrayList,是一个内部类实现。。
  • 使用集合toArray(T[] array )方法,转换为数组时注意需要传人类型完全一样的数组,并且它的容量为list.size,这样效率是最高的

6.5 集合与泛型

  • (略,知识点多又不太常用。。)

6.6 元素的比较

6.6.1 Comparable和Comparator

  • Comparable是表示自身有比较的能力,比较方法是compareTo
  • Comparator是第三方实现的比较,比较方法是compare

6.6.2 hashCode和equals

  • 注意任何时候覆写equals 都必须同时覆写 hashCode

6. 7 fail-fast 机制

  • 遍历过程对集合的操作可能导致异常
  • CopyOnWriteArrayList可以优化读多写少的场景

6.8 Map 类集合

【工作】《码出高效》读书笔记_第4张图片
image.png

6.8.1 红黑树

  • 树的结构
  • 二叉树是经典的二分法实现
  • 二叉树:平衡二叉树、查找二叉树、红黑树(TODO 一些重点数据结构,需要展开理解)

6.8.2 TreeMap

6.8.3 HashMap

  • 并发写的死链问题(CPU大量占用)

6.8.4 ConcurrentHashMap

  • 是学习并发编程的一个绝佳示例,此类超过 6300 行代码,涉及volatile、CAS 锁、链表、红黑树等众多知识点
  • 原理与算法 (TODO 也需要展开。。)

第7章 并发与多线程

并发与并行两个概念非常容易混淆,它们的核心区别在于进程是否同时执行。以 KTV 唱歌为例,并行指的是有多少人可以使用话筒同时唱歌,并发指的是同一个话筒被多个人轮流使用。

7.1 线程安全

  • 线程可以拥有自己的操作栈、程序计数器、局部变量表等资源
  • 线程安全的核心理念就是“要么只读,要么加锁”
  • Java 并发包( java.util.concurrent)JUC核心功能
    • 线程同步类:CountDownLatch等。替换notify、wait等
    • 并发集合类:ConcurrentHashMap等
    • 线程管理类:Executors工厂类等
    • 锁相关类:ReentrantLock等

7.2 什么是锁

  • 计算机的锁也是从开始的悲观锁,发展到后来的乐观锁、偏向锁(降低无竞争开销)、分段锁等
  • 锁主要提供两种特性:互斥性和不可见性

7.3 线程同步

7.3.1 同步是什么

  • 原子性:不可分割,要么全部成功,要么全部失败
  • 实现线程同步的方式有很多,比如同步方法、锁、阻塞队列等

7.3.2 volatile

  • 指令优化,指令重排
  • volatile延伸为敏感的易变的,局部阻止了指令重排的发生
  • 双重锁问题(double-check):对象创建和引用赋值不是原子的(JVM的实现或者JIT的编译可能让代码不是按预期顺序执行)

7.3.3 信号量同步

7.4 线程池

7.4.1 线程池的好处

ThreadPoolExecutor 的构造方法:

 public ThreadPoolExecutor(int corePoolSize, 常驻核心线程数
                              int maximumPoolSize, 同时执行的最大线程数
                              long keepAliveTime, 线程池中的线程空闲时间 
                              TimeUnit unit, 时间单位
                              BlockingQueue workQueue, 缓存队列
                              ThreadFactory threadFactory, 线程工厂
                              RejectedExecutionHandler handler 执行拒绝策略的对象
)

7.4.2 线程池源码详解

7.5 ThreadLocal

7.5.1引用类型

7.5.2 Threadlocal 价值

7.5.3 ThreadLocal 副作用

  • 脏数据(原因是线程会被重用,其附带的ThreadLocal也会留存)
  • 内存泄露(没有remove)

第8章 单元测试

8.1 单元测试的基本原则

8.2 单元测试覆盖率

8.3 单元测试编写

8.3.1 JUnit 单元测试框架

8.3.2 命名

8.3.3 断言与假设

第9章 代码规约

9.1 代码规约的意义

9.2 如何推动落地

9.3 手册纵览

9.4 聊聊成长

你可能感兴趣的:(【工作】《码出高效》读书笔记)