diff --git a/docs/notes/Java 虚拟机.md b/docs/notes/Java 虚拟机.md index 22084be6..3a1ef7b4 100644 --- a/docs/notes/Java 虚拟机.md +++ b/docs/notes/Java 虚拟机.md @@ -442,7 +442,7 @@ G1 把堆划分成多个大小相等的独立区域(Region),新生代和 # 四、类加载机制 -类是在运行期间第一次使用时动态加载的,而不是编译时期一次性加载。因为如果在编译时期一次性加载,那么会占用很多的内存。 +类是在运行期间第一次使用时动态加载的,而不是一次性加载。因为如果一次性加载,那么会占用很多的内存。 ## 类的生命周期 @@ -511,13 +511,9 @@ public static final int value = 123; ### 5. 初始化 -初始化阶段才真正开始执行类中定义的 Java 程序代码。初始化阶段即虚拟机执行类构造器 <clinit>() 方法的过程。 +初始化阶段才真正开始执行类中定义的 Java 程序代码。初始化阶段即虚拟机执行类构造器 <clinit>() 方法的过程。在准备阶段,类变量已经赋过一次系统要求的初始值,而在初始化阶段,根据程序员通过程序制定的主观计划去初始化类变量和其它资源。 -在准备阶段,类变量已经赋过一次系统要求的初始值,而在初始化阶段,根据程序员通过程序制定的主观计划去初始化类变量和其它资源。 - -<clinit>() 方法具有以下特点: - -- 是由编译器自动收集类中所有类变量的赋值动作和静态语句块中的语句合并产生的,编译器收集的顺序由语句在源文件中出现的顺序决定。特别注意的是,静态语句块只能访问到定义在它之前的类变量,定义在它之后的类变量只能赋值,不能访问。例如以下代码: +<clinit>() 是由编译器自动收集类中所有类变量的赋值动作和静态语句块中的语句合并产生的,编译器收集的顺序由语句在源文件中出现的顺序决定。特别注意的是,静态语句块只能访问到定义在它之前的类变量,定义在它之后的类变量只能赋值,不能访问。例如以下代码: ```java public class Test { @@ -529,9 +525,7 @@ public class Test { } ``` -- 与类的构造函数(或者说实例构造器 <init>())不同,不需要显式的调用父类的构造器。虚拟机会自动保证在子类的 <clinit>() 方法运行之前,父类的 <clinit>() 方法已经执行结束。因此虚拟机中第一个执行 <clinit>() 方法的类肯定为 java.lang.Object。 - -- 由于父类的 <clinit>() 方法先执行,也就意味着父类中定义的静态语句块的执行要优先于子类。例如以下代码: +由于父类的 <clinit>() 方法先执行,也就意味着父类中定义的静态语句块的执行要优先于子类。例如以下代码: ```java static class Parent { @@ -550,11 +544,9 @@ public static void main(String[] args) { } ``` -- <clinit>() 方法对于类或接口不是必须的,如果一个类中不包含静态语句块,也没有对类变量的赋值操作,编译器可以不为该类生成 <clinit>() 方法。 +接口中不可以使用静态语句块,但仍然有类变量初始化的赋值操作,因此接口与类一样都会生成 <clinit>() 方法。但接口与类不同的是,执行接口的 <clinit>() 方法不需要先执行父接口的 <clinit>() 方法。只有当父接口中定义的变量使用时,父接口才会初始化。另外,接口的实现类在初始化时也一样不会执行接口的 <clinit>() 方法。 -- 接口中不可以使用静态语句块,但仍然有类变量初始化的赋值操作,因此接口与类一样都会生成 <clinit>() 方法。但接口与类不同的是,执行接口的 <clinit>() 方法不需要先执行父接口的 <clinit>() 方法。只有当父接口中定义的变量使用时,父接口才会初始化。另外,接口的实现类在初始化时也一样不会执行接口的 <clinit>() 方法。 - -- 虚拟机会保证一个类的 <clinit>() 方法在多线程环境下被正确的加锁和同步,如果多个线程同时初始化一个类,只会有一个线程执行这个类的 <clinit>() 方法,其它线程都会阻塞等待,直到活动线程执行 <clinit>() 方法完毕。如果在一个类的 <clinit>() 方法中有耗时的操作,就可能造成多个线程阻塞,在实际过程中此种阻塞很隐蔽。 +虚拟机会保证一个类的 <clinit>() 方法在多线程环境下被正确的加锁和同步,如果多个线程同时初始化一个类,只会有一个线程执行这个类的 <clinit>() 方法,其它线程都会阻塞等待,直到活动线程执行 <clinit>() 方法完毕。如果在一个类的 <clinit>() 方法中有耗时的操作,就可能造成多个线程阻塞,在实际过程中此种阻塞很隐蔽。 ## 类初始化时机 diff --git a/docs/notes/Leetcode 题解.md b/docs/notes/Leetcode 题解.md index 7ee1a2b7..adadb482 100644 --- a/docs/notes/Leetcode 题解.md +++ b/docs/notes/Leetcode 题解.md @@ -256,7 +256,7 @@ Output: "apple" ``` -题目描述:删除 s 中的一些字符,使得它构成字符串列表 d 中的一个字符串,找出能构成的最长字符串。如果有多个相同长度的结果,返回字典序的最大字符串。 +题目描述:删除 s 中的一些字符,使得它构成字符串列表 d 中的一个字符串,找出能构成的最长字符串。如果有多个相同长度的结果,返回字典序的最小字符串。 ```java public String findLongestWord(String s, List d) { @@ -4243,7 +4243,7 @@ public boolean isPalindrome(ListNode head) { slow = slow.next; fast = fast.next.next; } - if (fast != null) slow = slow.next; // 链表节点个数为奇数,让 slow 指向下一个节点 + if (fast != null) slow = slow.next; // 偶数节点,让 slow 指向下一个节点 cut(head, slow); // 切成两个链表 return isEqual(head, reverse(slow)); } diff --git a/docs/notes/pics/gh_a68199af85d6_258_20_282_29.jpg b/docs/notes/pics/gh_a68199af85d6_258_20_282_29.jpg new file mode 100644 index 00000000..3c09c1c4 Binary files /dev/null and b/docs/notes/pics/gh_a68199af85d6_258_20_282_29.jpg differ diff --git a/docs/notes/剑指 offer 题解.md b/docs/notes/剑指 offer 题解.md index a0b07362..5fc40508 100644 --- a/docs/notes/剑指 offer 题解.md +++ b/docs/notes/剑指 offer 题解.md @@ -88,6 +88,10 @@ - [ProcessOn](https://www.processon.com/view/5a3e4c7be4b0909c1aa18b49) - [DrawIO](https://drive.google.com/file/d/1nSSCpPUC05MFoeFuf_aeTtkm7dG5-bJ1/view?usp=sharing) +本文内容可在微信小程序中阅读: + +

+ # 2. 实现 Singleton [单例模式](设计模式.md) @@ -1853,7 +1857,7 @@ private void backtracking(char[] chars, boolean[] hasUsed, StringBuilder s) { 多数投票问题,可以利用 Boyer-Moore Majority Vote Algorithm 来解决这个问题,使得时间复杂度为 O(N)。 -使用 cnt 来统计一个元素出现的次数,cnt 初始为 0。算法依次遍历数组中的数字,遍历到一个元素时,若 cnt 为 0,则令统计元素为遍历到的该元素,并置 cnt 为 1。若 cnt 不为 0,且当遍历到的元素和统计元素相等时,令 cnt++,否则令 cnt--。如果前面查找了 i 个元素,且 cnt == 0,说明前 i 个元素没有 majority,或者有 majority,但是出现的次数少于 i / 2 ,因为如果多于 i / 2 的话 cnt 就一定不会为 0 。此时剩下的 n - i 个元素中,majority 的数目依然多于 (n - i) / 2,因此继续查找就能找出 majority。 +使用 cnt 来统计一个元素出现的次数,当遍历到的元素和统计元素相等时,令 cnt++,否则令 cnt--。如果前面查找了 i 个元素,且 cnt == 0,说明前 i 个元素没有 majority,或者有 majority,但是出现的次数少于 i / 2 ,因为如果多于 i / 2 的话 cnt 就一定不会为 0 。此时剩下的 n - i 个元素中,majority 的数目依然多于 (n - i) / 2,因此继续查找就能找出 majority。 ```java public int MoreThanHalfNum_Solution(int[] nums) { diff --git a/docs/notes/计算机操作系统.md b/docs/notes/计算机操作系统.md index cdd90834..2699676e 100644 --- a/docs/notes/计算机操作系统.md +++ b/docs/notes/计算机操作系统.md @@ -46,7 +46,7 @@ 并发是指宏观上在一段时间内能同时运行多个程序,而并行则指同一时刻能运行多个指令。 -并行需要硬件支持,如多流水线或者多处理器。 +并行需要硬件支持,如多流水线、多核处理器或则分布式计算系统。 操作系统通过引入进程和线程,使得程序能够并发运行。 diff --git a/other/6.gif b/other/6.gif new file mode 100644 index 00000000..378640f5 Binary files /dev/null and b/other/6.gif differ diff --git a/other/剑指 Offer 题解小程序.md b/other/剑指 Offer 题解小程序.md new file mode 100644 index 00000000..6485a19b --- /dev/null +++ b/other/剑指 Offer 题解小程序.md @@ -0,0 +1,3 @@ +
+ +