Skip to content

Commit 8bd2754

Browse files
committed
Update README
1 parent 18823ce commit 8bd2754

File tree

3 files changed

+72
-101
lines changed

3 files changed

+72
-101
lines changed

Java.md

Lines changed: 51 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -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
768756
public 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
66986687
public 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
67766766
public 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

1078810778
Parallel 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
![](https://gitee.com/seazean/images/raw/master/Java/JVM-ParallelScavenge收集器.png)
1080610796

@@ -10845,7 +10835,7 @@ Par 是 Parallel 并行的缩写,New:只能处理的是新生代
1084510835
ParNew 是很多 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

1858618577
ProxyFactory 不是代理模式中的代理类,而代理类是程序在运行过程中动态的在内存中生成的类,可以通过 Arthas 工具查看代理类结构:
1858718578

1858818579
* 代理类($Proxy0)实现了 SellTickets 接口,真实类和代理类实现同样的接口
1858918580
* 代理类($Proxy0)将提供了的匿名内部类对象传递给了父类
18581+
* 代理类($Proxy0)的修饰符是 public final
1859018582

1859118583
```java
18592-
//程序运行过程中动态生成的代理类
18584+
// 程序运行过程中动态生成的代理类
1859318585
public 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

Comments
 (0)