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

  • 这是一本兼顾深度与广度的通用技术书籍
  • 列出了每节目录,与个人觉得是知识点的地方
  • 以及每章概述
第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握手
需要三次握手的原因:信息对等、防止脏连接

【工作】《码出高效》读书笔记
文章图片
image.png 1.5.4 TCP 断开连接
四次挥手

【工作】《码出高效》读书笔记
文章图片
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方法):本地方法调用的栈数据,也是线程私有的
【工作】《码出高效》读书笔记
文章图片
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 类集合 【工作】《码出高效》读书笔记
文章图片
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 聊聊成长

    推荐阅读