@@ -47,7 +47,7 @@ Java 语言提供了八种基本类型。六种数字类型(四个整数型,
4747- short 数据类型是 16 位、有符号的以二进制补码表示的整数
4848- 最小值是 **-32768(-2^15)**
4949- 最大值是 **32767(2^15 - 1)**
50- - short 数据类型也可以像 byte 那样节省空间,一个short变量是int型变量所占空间的二分之一
50+ - short 数据类型也可以像 byte 那样节省空间,一个 short 变量是 int 型变量所占空间的二分之一
5151- 默认值是 **`0`**
5252- 例子:`short s = 1000,short r = -20000`
5353
@@ -57,7 +57,7 @@ Java 语言提供了八种基本类型。六种数字类型(四个整数型,
5757- 最小值是 **-2,147,483,648(-2^31)**
5858- 最大值是 **2,147,483,647(2^31 - 1)**
5959- 一般地整型变量默认为 int 类型
60- - 默认值是 **`0`** ;
60+ - 默认值是 **`0`**
6161- 例子:`int a = 100000, int b = -200000`
6262
6363**long:**
@@ -100,19 +100,7 @@ Java 语言提供了八种基本类型。六种数字类型(四个整数型,
100100- 最小值是 **`\u0000`**(即为 0)
101101- 最大值是 **`\uffff`**(即为 65535)
102102- char 数据类型可以储存任何字符
103- - 例子:`char c = 'A';` `char c = '张';`
104-
105- ```mermaid
106- graph LR
107- 数据范围从小到大图
108-
109- A[byte]-->B[short]
110- C[char]-->D[int]
111- B-->D
112- D-->F[long]
113- G[float]
114- G-->H[double]
115- ```
103+ - 例子:`char c = 'A';` `char c = '张'`
116104
117105上下转型
118106
@@ -762,7 +750,7 @@ public static 返回值类型 方法名(参数) {
762750
763751重载仅针对**同一个类**中方法的名称与参数进行识别,**与返回值无关**,不能通过返回值来判定两个方法是否构成重载
764752
765- 原理:JVM → 运行机制 → 字节码 → 方法表
753+ 原理:JVM → 运行机制 → 方法调用 → 多态原理
766754
767755```java
768756public class MethodDemo {
@@ -1244,7 +1232,7 @@ static 静态修饰的成员(方法和成员变量)属于类本身的。
12441232}
12451233```
12461234
1247- 子类继承父类的东西 :
1235+ 子类不能继承父类的东西 :
12481236
12491237* 子类不能继承父类的构造器,子类有自己的构造器
12501238* 子类是不能可以继承父类的私有成员的,可以反射暴力去访问继承自父类的私有成员
@@ -3755,7 +3743,7 @@ public class RegexDemo {
37553743* 链表:元素不是内存中的连续区域存储,元素是游离存储的,每个元素会记录下个元素的地址
37563744 特点:**查询元素慢,增删元素快**(针对于首尾元素,速度极快,一般是双链表)
37573745
3758- * 树
3746+ * 树:
37593747
37603748 * 二叉树:binary tree 永远只有一个根节点,是每个结点不超过2个节点的树(tree)
37613749 特点:二叉排序树:小的左边,大的右边,但是可能树很高,性能变差
@@ -4464,8 +4452,9 @@ PriorityQueue 是优先级队列,底层存储结构为 Object[],默认实现
44644452
44654453#### Collections
44664454
4467- java.utils.Collections:集合**工具类**,Collections并不属于集合,是用来操作集合的工具类
4468- Collections有几个常用的API:
4455+ java.utils.Collections:集合**工具类**,Collections 并不属于集合,是用来操作集合的工具类
4456+
4457+ Collections 有几个常用的API:
44694458
44704459* `public static <T> boolean addAll(Collection<? super T> c, T... e)`:给集合对象批量添加元素
44714460* `public static void shuffle(List<?> list)`:打乱集合顺序
@@ -6683,16 +6672,16 @@ Stream<String> arrStream2 = Stream.of(arr);
66836672
66846673#### 常用API
66856674
6686- | 方法名 | 说明 |
6687- | --------------------------------------------------------- | ---------------------------------------------------- |
6688- | void forEach(Consumer<? super T> action) | 逐一处理(遍历) |
6689- | long count | 返回流中的元素数 |
6690- | Stream<T> filterPredicate <? super T> predicate) | 用于对流中的数据进行过滤 |
6691- | Stream<T> limit(long maxSize) | 返回此流中的元素组成的流,截取前指定参数个数的数据 |
6692- | Stream<T> skip(long n) | 跳过指定参数个数的数据,返回由该流的剩余元素组成的流 |
6693- | <R> Stream<R> map(Function<? super T,? extends R> mapper) | 加工方法,将当前流中的T类型数据转换为另一种R类型的流 |
6694- | static <T> Stream<T> concat(Stream a, Stream b) | 合并a和b两个流为一个 ,调用 `Stream.concat(s1,s2)` |
6695- | Stream<T> distinct() | 返回由该流的不同元素组成的流 |
6675+ | 方法名 | 说明 |
6676+ | --------------------------------------------------------- | -------------------------------------------------------- |
6677+ | void forEach(Consumer<? super T> action) | 逐一处理(遍历) |
6678+ | long count | 返回流中的元素数 |
6679+ | Stream<T> filter(Predicate <? super T> predicate) | 用于对流中的数据进行过滤 |
6680+ | Stream<T> limit(long maxSize) | 返回此流中的元素组成的流,截取前指定参数个数的数据 |
6681+ | Stream<T> skip(long n) | 跳过指定参数个数的数据,返回由该流的剩余元素组成的流 |
6682+ | <R> Stream<R> map(Function<? super T,? extends R> mapper) | 加工方法,将当前流中的 T 类型数据转换为另一种 R 类型的流 |
6683+ | static <T> Stream<T> concat(Stream a, Stream b) | 合并 a 和 b 两个流为一个 ,调用 `Stream.concat(s1,s2)` |
6684+ | Stream<T> distinct() | 返回由该流的不同元素组成的流 |
66966685
66976686```java
66986687public class StreamDemo {
@@ -6771,6 +6760,7 @@ Collectors 方法:
67716760* `public static <T> Collector toSet()`:把元素收集到 Set 集合中
67726761* `public static Collector toMap(Function keyMapper,Function valueMapper)`:把元素收集到 Map 集合中
67736762* `Object[] toArray()`:把元素收集数组中
6763+ * `public static Collector groupingBy(Function<? super T, ? extends K> classifier)`:分组
67746764
67756765```java
67766766public static void main(String[] args) {
@@ -10318,7 +10308,7 @@ public void localvarGC4() {
1031810308
1031910309垃圾收集主要是针对堆和方法区进行,程序计数器、虚拟机栈和本地方法栈这三个区域属于线程私有的,只存在于线程的生命周期内,线程结束之后就会消失,因此不需要对这三个区域进行垃圾回收
1032010310
10321- 在堆里存放着几乎所有的Java对象实例,在GC执行垃圾回收之前 ,首先需要区分出内存中哪些是存活对象,哪些是已经死亡的对象。只有被标记为己经死亡的对象,GC才会在执行垃圾回收时 ,释放掉其所占用的内存空间,因此这个过程我们可以称为垃圾标记阶段,判断对象存活一般有两种方式:**引用计数算法**和**可达性分析算法**
10311+ 在堆里存放着几乎所有的Java对象实例,在 GC 执行垃圾回收之前 ,首先需要区分出内存中哪些是存活对象,哪些是已经死亡的对象。只有被标记为己经死亡的对象,GC 才会在执行垃圾回收时 ,释放掉其所占用的内存空间,因此这个过程我们可以称为垃圾标记阶段,判断对象存活一般有两种方式:**引用计数算法**和**可达性分析算法**
1032210312
1032310313
1032410314
@@ -10783,7 +10773,7 @@ GC性能指标:
1078310773
1078410774#### Parallel
1078510775
10786- Parallel Scavenge 收集器是应用于新生代的并行垃圾回收器,**采用复制算法**、并行回收和" Stop the World" 机制
10776+ Parallel Scavenge 收集器是应用于新生代的并行垃圾回收器,**采用复制算法**、并行回收和 Stop the World 机制
1078710777
1078810778Parallel Old 收集器:是一个应用于老年代的并行垃圾回收器,**采用标记-整理算法**
1078910779
@@ -10800,7 +10790,7 @@ Parallel Old 收集器:是一个应用于老年代的并行垃圾回收器,*
1080010790
1080110791停顿时间和吞吐量的关系:新生代空间变小 → 缩短停顿时间 → 垃圾回收变得频繁 → 导致吞吐量下降
1080210792
10803- 在注重吞吐量及 CPU 资源敏感的场合,都可以优先考虑 Parallel Scavenge+Parallel Old 收集器,在 Server 模式下的内存回收性能很好,**Java8默认是此垃圾收集器组合 **
10793+ 在注重吞吐量及 CPU 资源敏感的场合,都可以优先考虑 Parallel Scavenge+Parallel Old 收集器,在 Server 模式下的内存回收性能很好,**Java8 默认是此垃圾收集器组合 **
1080410794
1080510795
1080610796
@@ -10845,7 +10835,7 @@ Par 是 Parallel 并行的缩写,New:只能处理的是新生代
1084510835ParNew 是很多 JVM 运行在 Server 模式下新生代的默认垃圾收集器
1084610836
1084710837- 对于新生代,回收次数频繁,使用并行方式高效
10848- - 对于老年代,回收次数少,使用串行方式节省资源(CPU并行需要切换线程 ,串行可以省去切换线程的资源)
10838+ - 对于老年代,回收次数少,使用串行方式节省资源(CPU 并行需要切换线程 ,串行可以省去切换线程的资源)
1084910839
1085010840
1085110841
@@ -12196,6 +12186,7 @@ protected Class<?> loadClass(String name, boolean resolve)
1219612186 }
1219712187 }
1219812188 if (resolve) {
12189+ // 链接指定的 Java 类,可以使类的 Class 对象创建完成的同时也被解析
1219912190 resolveClass(c);
1220012191 }
1220112192 return c;
@@ -14505,7 +14496,7 @@ public class GeneratedMethodAccessor1 extends MethodAccessorImpl {
1450514496
1450614497
1450714498
14508- ## JVM调优
14499+ ## 系统优化
1450914500
1451014501### 性能调优
1451114502
@@ -18581,15 +18572,16 @@ JDK 动态代理方式的优缺点:
1858118572
1858218573- 优点:可以为任意的接口实现类对象做代理,也可以为被代理对象的所有接口的所有方法做代理,动态代理可以在不改变方法源码的情况下,实现对方法功能的增强,提高了软件的可扩展性,Java 反射机制可以生成任意类型的动态代理类
1858318574- 缺点:**只能针对接口或者接口的实现类对象做代理对象**,普通类是不能做代理对象的
18584- - 原因:**生成的代理类继承了 Proxy**,java 是单继承的,所以 JDK 动态代理只能代理接口
18575+ - 原因:**生成的代理类继承了 Proxy**,Java 是单继承的,所以 JDK 动态代理只能代理接口
1858518576
1858618577ProxyFactory 不是代理模式中的代理类,而代理类是程序在运行过程中动态的在内存中生成的类,可以通过 Arthas 工具查看代理类结构:
1858718578
1858818579* 代理类($Proxy0)实现了 SellTickets 接口,真实类和代理类实现同样的接口
1858918580* 代理类($Proxy0)将提供了的匿名内部类对象传递给了父类
18581+ * 代理类($Proxy0)的修饰符是 public final
1859018582
1859118583```java
18592- //程序运行过程中动态生成的代理类
18584+ // 程序运行过程中动态生成的代理类
1859318585public final class $Proxy0 extends Proxy implements SellTickets {
1859418586 private static Method m3;
1859518587
@@ -18646,7 +18638,7 @@ public static Object newProxyInstance(ClassLoader loader,
1864618638 checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
1864718639 }
1864818640
18649- //从缓存中查找 class 类型的代理对象,参数二是代理需要实现的接口
18641+ // 从缓存中查找 class 类型的代理对象,参数二是代理需要实现的接口
1865018642 Class<?> cl = getProxyClass0(loader, intfs);
1865118643 //proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory())
1865218644
@@ -18655,20 +18647,20 @@ public static Object newProxyInstance(ClassLoader loader,
1865518647 checkNewProxyPermission(Reflection.getCallerClass(), cl);
1865618648 }
1865718649
18658- //获取代理类的构造方法,根据参数 InvocationHandler 匹配获取某个构造器
18650+ // 获取代理类的构造方法,根据参数 InvocationHandler 匹配获取某个构造器
1865918651 final Constructor<?> cons = cl.getConstructor(constructorParams);
1866018652 final InvocationHandler ih = h;
18661- //构造方法不是 pubic 的需要启用权限
18653+ // 构造方法不是 pubic 的需要启用权限
1866218654 if (!Modifier.isPublic(cl.getModifiers())) {
1866318655 AccessController.doPrivileged(new PrivilegedAction<Void>() {
1866418656 public Void run() {
18665- //设置可访问的权限
18657+ // 设置可访问的权限
1866618658 cons.setAccessible(true);
1866718659 return null;
1866818660 }
1866918661 });
1867018662 }
18671- //cons 是构造方法,并且内部持有 InvocationHandler,在 InvocationHandler 中持有 target 目标对象
18663+ // cons 是构造方法,并且内部持有 InvocationHandler,在 InvocationHandler 中持有 target 目标对象
1867218664 return cons.newInstance(new Object[]{h});
1867318665 } catch (IllegalAccessException|InstantiationException e) {}
1867418666}
@@ -18681,7 +18673,7 @@ private static final class ProxyClassFactory {
1868118673 // 代理类型的名称前缀
1868218674 private static final String proxyClassNamePrefix = "$Proxy";
1868318675
18684- //生成唯一数字使用,结合上面的代理类型名称前缀一起生成
18676+ // 生成唯一数字使用,结合上面的代理类型名称前缀一起生成
1868518677 private static final AtomicLong nextUniqueNumber = new AtomicLong();
1868618678
1868718679 //参数一:Proxy.newInstance 时传递的
@@ -18714,22 +18706,22 @@ private static final class ProxyClassFactory {
1871418706 }
1871518707 }
1871618708
18717- //生成的代理类的包名
18709+ // 生成的代理类的包名
1871818710 String proxyPkg = null;
18719- //生成的代理类访问修饰符 pulic final
18711+ // 【 生成的代理类访问修饰符 public final】
1872018712 int accessFlags = Modifier.PUBLIC | Modifier.FINAL;
1872118713
1872218714 // 检查接口集合内的接口,看看有没有某个接口的访问修饰符不是 public 的 如果不是 public 的接口,
18723- //生成的代理类 class 就必须和它在一个包下,否则访问出现问题
18715+ // 生成的代理类 class 就必须和它在一个包下,否则访问出现问题
1872418716 for (Class<?> intf : interfaces) {
1872518717 // 获取访问修饰符
1872618718 int flags = intf.getModifiers();
1872718719 if (!Modifier.isPublic(flags)) {
1872818720 accessFlags = Modifier.FINAL;
18729- //获取当前接口的全限定名 包名.类名
18721+ // 获取当前接口的全限定名 包名.类名
1873018722 String name = intf.getName();
1873118723 int n = name.lastIndexOf('.');
18732- //获取包名
18724+ // 获取包名
1873318725 String pkg = ((n == -1) ? "" : name.substring(0, n + 1));
1873418726 if (proxyPkg == null) {
1873518727 proxyPkg = pkg;
@@ -18750,11 +18742,11 @@ private static final class ProxyClassFactory {
1875018742 // 包名+ $proxy + 数字,比如 $proxy1
1875118743 String proxyName = proxyPkg + proxyClassNamePrefix + num;
1875218744
18753- // 生成二进制字节码,这个字节码写入到文件内,就是编译好的 class 文件
18745+ // 【 生成二进制字节码,这个字节码写入到文件内】 ,就是编译好的 class 文件
1875418746 byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
1875518747 proxyName, interfaces, accessFlags);
1875618748 try {
18757- //使用加载器加载二进制到 jvm,并且返回 class
18749+ // 【 使用加载器加载二进制到 jvm】 ,并且返回 class
1875818750 return defineClass0(loader, proxyName,
1875918751 proxyClassFile, 0, proxyClassFile.length);
1876018752 } catch (ClassFormatError e) { }
@@ -18831,16 +18823,16 @@ CGLIB 的优缺点
1883118823
1883218824三种方式对比:
1883318825
18834- * JDK 代理和 CGLIB 代理
18835-
18836- 使用 CGLIB 实现动态代理,CGLIB 底层采用 ASM 字节码生成框架,使用字节码技术生成代理类,在 JDK1.6之前比使用 Java 反射效率要高,到 JDK1.8 的时候,JDK 代理效率高于 CGLIB 代理。所以如果有接口使用 JDK 动态代理,如果没有接口使用 CGLIB 代理
18837-
18838- * 动态代理和静态代理
18826+ * 动态代理和静态代理:
1883918827
1884018828 * 动态代理将接口中声明的所有方法都被转移到一个集中的方法中处理(InvocationHandler.invoke),在接口方法数量比较多的时候,可以进行灵活处理,不需要像静态代理那样每一个方法进行中转
1884118829
1884218830 * 静态代理是在编译时就已经将接口、代理类、被代理类的字节码文件确定下来
18843- * 动态代理是程序在运行后通过反射创建字节码文件交由 JVM 加载
18831+ * 动态代理是程序**在运行后通过反射创建字节码文件**交由 JVM 加载
18832+
18833+ * JDK 代理和 CGLIB 代理:
18834+
18835+ JDK 动态代理采用 ProxyGenerator.generateProxyClass() 方法在运行时生成字节码;CGLIB 底层采用 ASM 字节码生成框架,使用字节码技术生成代理类。在 JDK1.6之前比使用 Java 反射效率要高,到 JDK1.8 的时候,JDK 代理效率高于 CGLIB 代理。所以如果有接口或者当前类就是接口使用 JDK 动态代理,如果没有接口使用 CGLIB 代理
1884418836
1884518837代理模式的优缺点:
1884618838
@@ -18853,17 +18845,12 @@ CGLIB 的优缺点
1885318845
1885418846代理模式的使用场景:
1885518847
18856- * 远程(Remote)代理
18857-
18858- 本地服务通过网络请求远程服务,需要实现网络通信,处理其中可能的异常。为了良好的代码设计和可维护性,将网络通信部分隐藏起来,只暴露给本地服务一个接口,通过该接口即可访问远程服务提供的功能
18859-
18860- * 防火墙(Firewall)代理
18848+ * 远程(Remote)代理:本地服务通过网络请求远程服务,需要实现网络通信,处理其中可能的异常。为了良好的代码设计和可维护性,将网络通信部分隐藏起来,只暴露给本地服务一个接口,通过该接口即可访问远程服务提供的功能
1886118849
18862- 当你将浏览器配置成使用代理功能时,防火墙就将你的浏览器的请求转给互联网,当互联网返回响应时,代理服务器再把它转给你的浏览器
18850+ * 防火墙(Firewall)代理: 当你将浏览器配置成使用代理功能时,防火墙就将你的浏览器的请求转给互联网,当互联网返回响应时,代理服务器再把它转给你的浏览器
1886318851
18864- * 保护(Protect or Access)代理
18852+ * 保护(Protect or Access)代理:控制对一个对象的访问,如果需要,可以给不同的用户提供不同级别的使用权限
1886518853
18866- 控制对一个对象的访问,如果需要,可以给不同的用户提供不同级别的使用权限
1886718854
1886818855
1886918856
0 commit comments