mirror of
https://github.com/Snailclimb/JavaGuide
synced 2025-08-01 16:28:03 +08:00
style: update linter
This commit is contained in:
parent
7ea99a88d7
commit
114342995c
@ -79,7 +79,7 @@ export default hopeTheme({
|
||||
return path.resolve(
|
||||
__dirname,
|
||||
"../snippets",
|
||||
file.replace("@", "./")
|
||||
file.replace("@", "./"),
|
||||
);
|
||||
|
||||
return path.resolve(cwd, file);
|
||||
|
@ -86,9 +86,9 @@ public abstract class ClassLoader {
|
||||
|
||||
JVM 中内置了三个重要的 `ClassLoader`:
|
||||
|
||||
1. **`BootstrapClassLoader`(启动类加载器)**:最顶层的加载类,由 C++实现,通常表示为 null,并且没有父级,主要用来加载 JDK 内部的核心类库( `%JAVA_HOME%/lib`目录下的 `rt.jar`、`resources.jar`、`charsets.jar`等 jar 包和类)以及被 `-Xbootclasspath`参数指定的路径下的所有类。
|
||||
2. **`ExtensionClassLoader`(扩展类加载器)**:主要负责加载 `%JRE_HOME%/lib/ext` 目录下的 jar 包和类以及被 `java.ext.dirs` 系统变量所指定的路径下的所有类。
|
||||
3. **`AppClassLoader`(应用程序类加载器)**:面向我们用户的加载器,负责加载当前应用 classpath 下的所有 jar 包和类。
|
||||
1. **`BootstrapClassLoader`(启动类加载器)**:最顶层的加载类,由 C++实现,通常表示为 null,并且没有父级,主要用来加载 JDK 内部的核心类库( `%JAVA_HOME%/lib`目录下的 `rt.jar`、`resources.jar`、`charsets.jar`等 jar 包和类)以及被 `-Xbootclasspath`参数指定的路径下的所有类。
|
||||
2. **`ExtensionClassLoader`(扩展类加载器)**:主要负责加载 `%JRE_HOME%/lib/ext` 目录下的 jar 包和类以及被 `java.ext.dirs` 系统变量所指定的路径下的所有类。
|
||||
3. **`AppClassLoader`(应用程序类加载器)**:面向我们用户的加载器,负责加载当前应用 classpath 下的所有 jar 包和类。
|
||||
|
||||
> 🌈 拓展一下:
|
||||
>
|
||||
@ -341,10 +341,10 @@ cl = Thread.currentThread().getContextClassLoader();
|
||||
## 推荐阅读
|
||||
|
||||
- 《深入拆解 Java 虚拟机》
|
||||
- 深入分析 Java ClassLoader 原理:https://blog.csdn.net/xyang81/article/details/7292380
|
||||
- Java 类加载器(ClassLoader):http://gityuan.com/2016/01/24/java-classloader/
|
||||
- Class Loaders in Java:https://www.baeldung.com/java-classloaders
|
||||
- Class ClassLoader - Oracle 官方文档:https://docs.oracle.com/javase/8/docs/api/java/lang/ClassLoader.html
|
||||
- 老大难的 Java ClassLoader 再不理解就老了:https://zhuanlan.zhihu.com/p/51374915
|
||||
- 深入分析 Java ClassLoader 原理:<https://blog.csdn.net/xyang81/article/details/7292380>
|
||||
- Java 类加载器(ClassLoader):<http://gityuan.com/2016/01/24/java-classloader/>
|
||||
- Class Loaders in Java:<https://www.baeldung.com/java-classloaders>
|
||||
- Class ClassLoader - Oracle 官方文档:<https://docs.oracle.com/javase/8/docs/api/java/lang/ClassLoader.html>
|
||||
- 老大难的 Java ClassLoader 再不理解就老了:<https://zhuanlan.zhihu.com/p/51374915>
|
||||
|
||||
<!-- @include: @article-footer.snippet.md -->
|
||||
|
@ -507,7 +507,7 @@ $ java -XX:+UseZGC className
|
||||
## 参考
|
||||
|
||||
- 《深入理解 Java 虚拟机:JVM 高级特性与最佳实践(第二版》
|
||||
- https://my.oschina.net/hosee/blog/644618
|
||||
- <https://my.oschina.net/hosee/blog/644618>
|
||||
- <https://docs.oracle.com/javase/specs/jvms/se8/html/index.html>
|
||||
|
||||
<!-- @include: @article-footer.snippet.md -->
|
||||
|
@ -5,7 +5,7 @@ tag:
|
||||
- JVM
|
||||
---
|
||||
|
||||
> 来自[说出你的愿望吧丷](https://juejin.im/user/5c2400afe51d45451758aa96)投稿,原文地址:https://juejin.im/post/5e1505d0f265da5d5d744050 。
|
||||
> 来自[说出你的愿望吧丷](https://juejin.im/user/5c2400afe51d45451758aa96)投稿,原文地址:<https://juejin.im/post/5e1505d0f265da5d5d744050>。
|
||||
|
||||
## 前言
|
||||
|
||||
@ -71,12 +71,12 @@ JVM 是 Java Virtual Machine 的缩写,它是一个虚构出来的计算机,
|
||||
|
||||
执行 main 方法的步骤如下:
|
||||
|
||||
1. 编译好 App.java 后得到 App.class 后,执行 App.class,系统会启动一个 JVM 进程,从 classpath 路径中找到一个名为 App.class 的二进制文件,将 App 的类信息加载到运行时数据区的方法区内,这个过程叫做 App 类的加载
|
||||
2. JVM 找到 App 的主程序入口,执行 main 方法
|
||||
3. 这个 main 中的第一条语句为 Student student = new Student("tellUrDream") ,就是让 JVM 创建一个 Student 对象,但是这个时候方法区中是没有 Student 类的信息的,所以 JVM 马上加载 Student 类,把 Student 类的信息放到方法区中
|
||||
4. 加载完 Student 类后,JVM 在堆中为一个新的 Student 实例分配内存,然后调用构造函数初始化 Student 实例,这个 Student 实例持有 **指向方法区中的 Student 类的类型信息** 的引用
|
||||
5. 执行 student.sayName();时,JVM 根据 student 的引用找到 student 对象,然后根据 student 对象持有的引用定位到方法区中 student 类的类型信息的方法表,获得 sayName() 的字节码地址。
|
||||
6. 执行 sayName()
|
||||
1. 编译好 App.java 后得到 App.class 后,执行 App.class,系统会启动一个 JVM 进程,从 classpath 路径中找到一个名为 App.class 的二进制文件,将 App 的类信息加载到运行时数据区的方法区内,这个过程叫做 App 类的加载
|
||||
2. JVM 找到 App 的主程序入口,执行 main 方法
|
||||
3. 这个 main 中的第一条语句为 Student student = new Student("tellUrDream") ,就是让 JVM 创建一个 Student 对象,但是这个时候方法区中是没有 Student 类的信息的,所以 JVM 马上加载 Student 类,把 Student 类的信息放到方法区中
|
||||
4. 加载完 Student 类后,JVM 在堆中为一个新的 Student 实例分配内存,然后调用构造函数初始化 Student 实例,这个 Student 实例持有 **指向方法区中的 Student 类的类型信息** 的引用
|
||||
5. 执行 student.sayName();时,JVM 根据 student 的引用找到 student 对象,然后根据 student 对象持有的引用定位到方法区中 student 类的类型信息的方法表,获得 sayName() 的字节码地址。
|
||||
6. 执行 sayName()
|
||||
|
||||
其实也不用管太多,只需要知道对象实例初始化时会去方法区中找类信息,完成后再到栈那里去运行方法。找方法就在方法表中找。
|
||||
|
||||
@ -90,15 +90,15 @@ JVM 是 Java Virtual Machine 的缩写,它是一个虚构出来的计算机,
|
||||
|
||||
#### 2.1.1 加载
|
||||
|
||||
1. 将 class 文件加载到内存
|
||||
2. 将静态数据结构转化成方法区中运行时的数据结构
|
||||
3. 在堆中生成一个代表这个类的 java.lang.Class 对象作为数据访问的入口
|
||||
1. 将 class 文件加载到内存
|
||||
2. 将静态数据结构转化成方法区中运行时的数据结构
|
||||
3. 在堆中生成一个代表这个类的 java.lang.Class 对象作为数据访问的入口
|
||||
|
||||
#### 2.1.2 链接
|
||||
|
||||
1. 验证:确保加载的类符合 JVM 规范和安全,保证被校验类的方法在运行时不会做出危害虚拟机的事件,其实就是一个安全检查
|
||||
2. 准备:为 static 变量在方法区中分配内存空间,设置变量的初始值,例如 static int a = 3 (注意:准备阶段只设置类中的静态变量(方法区中),不包括实例变量(堆内存中),实例变量是对象初始化时赋值的)
|
||||
3. 解析:虚拟机将常量池内的符号引用替换为直接引用的过程(符号引用比如我现在 import java.util.ArrayList 这就算符号引用,直接引用就是指针或者对象地址,注意引用对象一定是在内存进行)
|
||||
1. 验证:确保加载的类符合 JVM 规范和安全,保证被校验类的方法在运行时不会做出危害虚拟机的事件,其实就是一个安全检查
|
||||
2. 准备:为 static 变量在方法区中分配内存空间,设置变量的初始值,例如 static int a = 3 (注意:准备阶段只设置类中的静态变量(方法区中),不包括实例变量(堆内存中),实例变量是对象初始化时赋值的)
|
||||
3. 解析:虚拟机将常量池内的符号引用替换为直接引用的过程(符号引用比如我现在 import java.util.ArrayList 这就算符号引用,直接引用就是指针或者对象地址,注意引用对象一定是在内存进行)
|
||||
|
||||
#### 2.1.3 初始化
|
||||
|
||||
@ -114,10 +114,10 @@ GC 将无用对象从内存中卸载
|
||||
|
||||
加载一个 Class 类的顺序也是有优先级的,类加载器从最底层开始往上的顺序是这样的
|
||||
|
||||
1. BootStrap ClassLoader:rt.jar
|
||||
2. Extension ClassLoader: 加载扩展的 jar 包
|
||||
3. App ClassLoader:指定的 classpath 下面的 jar 包
|
||||
4. Custom ClassLoader:自定义的类加载器
|
||||
1. BootStrap ClassLoader:rt.jar
|
||||
2. Extension ClassLoader: 加载扩展的 jar 包
|
||||
3. App ClassLoader:指定的 classpath 下面的 jar 包
|
||||
4. Custom ClassLoader:自定义的类加载器
|
||||
|
||||
### 2.3 双亲委派机制
|
||||
|
||||
@ -190,7 +190,7 @@ public class Person{
|
||||
|
||||
局部变量表用于存放方法参数和方法内部所定义的局部变量。它的容量是以 Slot 为最小单位,一个 slot 可以存放 32 位以内的数据类型。
|
||||
|
||||
虚拟机通过索引定位的方式使用局部变量表,范围为[0,局部变量表的 slot 的数量]。方法中的参数就会按一定顺序排列在这个局部变量表中,至于怎么排的我们可以先不关心。而为了节省栈帧空间,这些 slot 是可以复用的,当方法执行位置超过了某个变量,那么这个变量的 slot 可以被其它变量复用。当然如果需要复用,那我们的垃圾回收自然就不会去动这些内存。
|
||||
虚拟机通过索引定位的方式使用局部变量表,范围为 `[0,局部变量表的 slot 的数量]`。方法中的参数就会按一定顺序排列在这个局部变量表中,至于怎么排的我们可以先不关心。而为了节省栈帧空间,这些 slot 是可以复用的,当方法执行位置超过了某个变量,那么这个变量的 slot 可以被其它变量复用。当然如果需要复用,那我们的垃圾回收自然就不会去动这些内存。
|
||||
|
||||
#### 3.3.6 虚拟机堆的概念
|
||||
|
||||
@ -239,11 +239,11 @@ MaxMetaspaceSize:限制元空间大小上限,防止占用过多物理内存
|
||||
|
||||
(了解一下即可)在 Java 语言汇总能作为 GC Roots 的对象分为以下几种:
|
||||
|
||||
1. 虚拟机栈(栈帧中的本地方法表)中引用的对象(局部变量)
|
||||
2. 方法区中静态变量所引用的对象(静态变量)
|
||||
3. 方法区中常量引用的对象
|
||||
4. 本地方法栈(即 native 修饰的方法)中 JNI 引用的对象(JNI 是 Java 虚拟机调用对应的 C 函数的方式,通过 JNI 函数也可以创建新的 Java 对象。且 JNI 对于对象的局部引用或者全局引用都会把它们指向的对象都标记为不可回收)
|
||||
5. 已启动的且未终止的 Java 线程
|
||||
1. 虚拟机栈(栈帧中的本地方法表)中引用的对象(局部变量)
|
||||
2. 方法区中静态变量所引用的对象(静态变量)
|
||||
3. 方法区中常量引用的对象
|
||||
4. 本地方法栈(即 native 修饰的方法)中 JNI 引用的对象(JNI 是 Java 虚拟机调用对应的 C 函数的方式,通过 JNI 函数也可以创建新的 Java 对象。且 JNI 对于对象的局部引用或者全局引用都会把它们指向的对象都标记为不可回收)
|
||||
5. 已启动的且未终止的 Java 线程
|
||||
|
||||
这种方法的优点是能够解决循环引用的问题,可它的实现需要耗费大量资源和时间,也需要 GC(它的分析过程引用关系不能发生变化,所以需要停止所有进程)
|
||||
|
||||
@ -259,8 +259,8 @@ finalize()是 Object 类的一个方法、一个对象的 finalize()方法只会
|
||||
|
||||
判断一个对象的死亡至少需要两次标记
|
||||
|
||||
1. 如果对象进行可达性分析之后没发现与 GC Roots 相连的引用链,那它将会第一次标记并且进行一次筛选。判断的条件是决定这个对象是否有必要执行 finalize()方法。如果对象有必要执行 finalize()方法,则被放入 F-Queue 队列中。
|
||||
2. GC 对 F-Queue 队列中的对象进行二次标记。如果对象在 finalize()方法中重新与引用链上的任何一个对象建立了关联,那么二次标记时则会将它移出“即将回收”集合。如果此时对象还没成功逃脱,那么只能被回收了。
|
||||
1. 如果对象进行可达性分析之后没发现与 GC Roots 相连的引用链,那它将会第一次标记并且进行一次筛选。判断的条件是决定这个对象是否有必要执行 finalize()方法。如果对象有必要执行 finalize()方法,则被放入 F-Queue 队列中。
|
||||
2. GC 对 F-Queue 队列中的对象进行二次标记。如果对象在 finalize()方法中重新与引用链上的任何一个对象建立了关联,那么二次标记时则会将它移出“即将回收”集合。如果此时对象还没成功逃脱,那么只能被回收了。
|
||||
|
||||
如果确定对象已经死亡,我们又该如何回收这些垃圾呢
|
||||
|
||||
|
@ -133,7 +133,7 @@ Java 堆是垃圾收集器管理的主要区域,因此也被称作 **GC 堆(
|
||||
>
|
||||
> ```c++
|
||||
> uint ageTable::compute_tenuring_threshold(size_t survivor_capacity) {
|
||||
> //survivor_capacity是survivor空间的大小
|
||||
> //survivor_capacity是survivor空间的大小
|
||||
> size_t desired_survivor_size = (size_t)((((double) survivor_capacity)*TargetSurvivorRatio)/100);
|
||||
> size_t total = 0;
|
||||
> uint age = 1;
|
||||
@ -143,7 +143,7 @@ Java 堆是垃圾收集器管理的主要区域,因此也被称作 **GC 堆(
|
||||
> age++;
|
||||
> }
|
||||
> uint result = age < MaxTenuringThreshold ? age : MaxTenuringThreshold;
|
||||
> ...
|
||||
> ...
|
||||
> }
|
||||
> ```
|
||||
|
||||
@ -344,10 +344,10 @@ HotSpot 虚拟机主要使用的就是这种方式来进行对象访问。
|
||||
|
||||
- 《深入理解 Java 虚拟机:JVM 高级特性与最佳实践(第二版》
|
||||
- 《自己动手写 Java 虚拟机》
|
||||
- Chapter 2. The Structure of the Java Virtual Machine:https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-2.html
|
||||
- JVM 栈帧内部结构-动态链接:https://chenxitag.com/archives/368
|
||||
- Java 中 new String("字面量") 中 "字面量" 是何时进入字符串常量池的? - 木女孩的回答 - 知乎:https://www.zhihu.com/question/55994121/answer/147296098
|
||||
- JVM 常量池中存储的是对象还是引用呢? - RednaxelaFX 的回答 - 知乎:https://www.zhihu.com/question/57109429/answer/151717241
|
||||
- Chapter 2. The Structure of the Java Virtual Machine:<https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-2.html>
|
||||
- JVM 栈帧内部结构-动态链接:<https://chenxitag.com/archives/368>
|
||||
- Java 中 new String("字面量") 中 "字面量" 是何时进入字符串常量池的? - 木女孩的回答 - 知乎:<https://www.zhihu.com/question/55994121/answer/147296098>
|
||||
- JVM 常量池中存储的是对象还是引用呢? - RednaxelaFX 的回答 - 知乎:<https://www.zhihu.com/question/57109429/answer/151717241>
|
||||
- <http://www.pointsoftware.ch/en/under-the-hood-runtime-data-areas-javas-memory-model/>
|
||||
- <https://dzone.com/articles/jvm-permgen-%E2%80%93-where-art-thou>
|
||||
- <https://stackoverflow.com/questions/9095748/method-area-and-permgen>
|
||||
|
@ -110,10 +110,10 @@ Oracle 的 HotSpot VM 便附带两个用 C++ 实现的 JIT compiler:C1 及 C2
|
||||
|
||||
## 参考
|
||||
|
||||
- Java 10 Features and Enhancements : https://howtodoinjava.com/java10/java10-features/
|
||||
- Java 10 Features and Enhancements : <https://howtodoinjava.com/java10/java10-features/>
|
||||
|
||||
- Guide to Java10 : <https://www.baeldung.com/java-10-overview>
|
||||
|
||||
- 4 Class Data Sharing : https://docs.oracle.com/javase/10/vm/class-data-sharing.htm#JSJVM-GUID-7EAA3411-8CF0-4D19-BD05-DF5E1780AA91
|
||||
- 4 Class Data Sharing : <https://docs.oracle.com/javase/10/vm/class-data-sharing.htm#JSJVM-GUID-7EAA3411-8CF0-4D19-BD05-DF5E1780AA91>
|
||||
|
||||
<!-- @include: @article-footer.snippet.md -->
|
||||
|
@ -125,7 +125,7 @@ Consumer<String> consumer = (String i) -> System.out.println(i);
|
||||
|
||||
## 参考
|
||||
|
||||
- JDK 11 Release Notes:https://www.oracle.com/java/technologies/javase/11-relnote-issues.html
|
||||
- JDK 11 Release Notes:<https://www.oracle.com/java/technologies/javase/11-relnote-issues.html>
|
||||
- Java 11 – Features and Comparison:<https://www.geeksforgeeks.org/java-11-features-and-comparison/>
|
||||
|
||||
<!-- @include: @article-footer.snippet.md -->
|
||||
|
@ -115,9 +115,9 @@ if (o instanceof String s) {
|
||||
|
||||
```java
|
||||
public class Outer {
|
||||
class Inner {
|
||||
static int age;
|
||||
}
|
||||
class Inner {
|
||||
static int age;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -7,7 +7,7 @@
|
||||
|
||||
欢迎阅读我对 Java 8 的介绍。本教程将逐步指导您完成所有新语言功能。 在简短的代码示例的基础上,您将学习如何使用默认接口方法,lambda 表达式,方法引用和可重复注释。 在本文的最后,您将熟悉最新的 API 更改,如流,函数式接口(Functional Interfaces),Map 类的扩展和新的 Date API。 没有大段枯燥的文字,只有一堆注释的代码片段。
|
||||
|
||||
### 接口的默认方法(Default Methods for Interfaces)
|
||||
## 接口的默认方法(Default Methods for Interfaces)
|
||||
|
||||
Java 8 使我们能够通过使用 `default` 关键字向接口添加非抽象方法实现。 此功能也称为[虚拟扩展方法](http://stackoverflow.com/a/24102730)。
|
||||
|
||||
@ -51,7 +51,7 @@ formula 是作为匿名对象实现的。该代码非常容易理解,6 行代
|
||||
|
||||
**译者注:** 不管是抽象类还是接口,都可以通过匿名内部类的方式访问。不能通过抽象类或者接口直接创建对象。对于上面通过匿名内部类方式访问接口,我们可以这样理解:一个内部类实现了接口里的抽象方法并且返回一个内部类对象,之后我们让接口的引用来指向这个对象。
|
||||
|
||||
### Lambda 表达式(Lambda expressions)
|
||||
## Lambda 表达式(Lambda expressions)
|
||||
|
||||
首先看看在老版本的 Java 中是如何排列字符串的:
|
||||
|
||||
@ -90,7 +90,7 @@ names.sort((a, b) -> b.compareTo(a));
|
||||
|
||||
List 类本身就有一个 `sort` 方法。并且 Java 编译器可以自动推导出参数类型,所以你可以不用再写一次类型。接下来我们看看 lambda 表达式还有什么其他用法。
|
||||
|
||||
### 函数式接口(Functional Interfaces)
|
||||
## 函数式接口(Functional Interfaces)
|
||||
|
||||
**译者注:** 原文对这部分解释不太清楚,故做了修改!
|
||||
|
||||
@ -116,7 +116,7 @@ public interface Converter<F, T> {
|
||||
|
||||
**译者注:** 大部分函数式接口都不用我们自己写,Java8 都给我们实现好了,这些接口都在 java.util.function 包里。
|
||||
|
||||
### 方法和构造函数引用(Method and Constructor References)
|
||||
## 方法和构造函数引用(Method and Constructor References)
|
||||
|
||||
前一节中的代码还可以通过静态方法引用来表示:
|
||||
|
||||
@ -176,9 +176,9 @@ Person person = personFactory.create("Peter", "Parker");
|
||||
|
||||
我们只需要使用 `Person::new` 来获取 Person 类构造函数的引用,Java 编译器会自动根据`PersonFactory.create`方法的参数类型来选择合适的构造函数。
|
||||
|
||||
### Lambda 表达式作用域(Lambda Scopes)
|
||||
## Lambda 表达式作用域(Lambda Scopes)
|
||||
|
||||
#### 访问局部变量
|
||||
### 访问局部变量
|
||||
|
||||
我们可以直接在 lambda 表达式中访问外部的局部变量:
|
||||
|
||||
@ -209,7 +209,7 @@ Converter<Integer, String> stringConverter =
|
||||
num = 3;//在lambda表达式中试图修改num同样是不允许的。
|
||||
```
|
||||
|
||||
#### 访问字段和静态变量
|
||||
### 访问字段和静态变量
|
||||
|
||||
与局部变量相比,我们在 lambda 表达式中对实例字段和静态变量都有读写访问权限。 该行为和匿名对象是一致的。
|
||||
|
||||
@ -232,7 +232,7 @@ class Lambda4 {
|
||||
}
|
||||
```
|
||||
|
||||
#### 访问默认接口方法
|
||||
### 访问默认接口方法
|
||||
|
||||
还记得第一节中的 formula 示例吗? `Formula` 接口定义了一个默认方法`sqrt`,可以从包含匿名对象的每个 formula 实例访问该方法。 这不适用于 lambda 表达式。
|
||||
|
||||
@ -242,13 +242,13 @@ class Lambda4 {
|
||||
Formula formula = (a) -> sqrt(a * 100);
|
||||
```
|
||||
|
||||
### 内置函数式接口(Built-in Functional Interfaces)
|
||||
## 内置函数式接口(Built-in Functional Interfaces)
|
||||
|
||||
JDK 1.8 API 包含许多内置函数式接口。 其中一些接口在老版本的 Java 中是比较常见的比如:`Comparator` 或`Runnable`,这些接口都增加了`@FunctionalInterface`注解以便能用在 lambda 表达式上。
|
||||
|
||||
但是 Java 8 API 同样还提供了很多全新的函数式接口来让你的编程工作更加方便,有一些接口是来自 [Google Guava](https://code.google.com/p/guava-libraries/) 库里的,即便你对这些很熟悉了,还是有必要看看这些是如何扩展到 lambda 上使用的。
|
||||
|
||||
#### Predicate
|
||||
### Predicate
|
||||
|
||||
Predicate 接口是只有一个参数的返回布尔类型值的 **断言型** 接口。该接口包含多种默认方法来将 Predicate 组合成其他复杂的逻辑(比如:与,或,非):
|
||||
|
||||
@ -301,7 +301,7 @@ Predicate<String> isEmpty = String::isEmpty;
|
||||
Predicate<String> isNotEmpty = isEmpty.negate();
|
||||
```
|
||||
|
||||
#### Function
|
||||
### Function
|
||||
|
||||
Function 接口接受一个参数并生成结果。默认方法可用于将多个函数链接在一起(compose, andThen):
|
||||
|
||||
@ -341,7 +341,7 @@ Function<String, String> backToString = toInteger.andThen(String::valueOf);
|
||||
backToString.apply("123"); // "123"
|
||||
```
|
||||
|
||||
#### Supplier
|
||||
### Supplier
|
||||
|
||||
Supplier 接口产生给定泛型类型的结果。 与 Function 接口不同,Supplier 接口不接受参数。
|
||||
|
||||
@ -350,7 +350,7 @@ Supplier<Person> personSupplier = Person::new;
|
||||
personSupplier.get(); // new Person
|
||||
```
|
||||
|
||||
#### Consumer
|
||||
### Consumer
|
||||
|
||||
Consumer 接口表示要对单个输入参数执行的操作。
|
||||
|
||||
@ -359,7 +359,7 @@ Consumer<Person> greeter = (p) -> System.out.println("Hello, " + p.firstName);
|
||||
greeter.accept(new Person("Luke", "Skywalker"));
|
||||
```
|
||||
|
||||
#### Comparator
|
||||
### Comparator
|
||||
|
||||
Comparator 是老 Java 中的经典接口, Java 8 在此之上添加了多种默认方法:
|
||||
|
||||
|
@ -145,29 +145,29 @@ JSP 有 9 个内置对象:
|
||||
|
||||
## Request 对象的主要方法有哪些
|
||||
|
||||
- setAttribute(String name,Object):设置名字为 name 的 request 的参数值
|
||||
- getAttribute(String name):返回由 name 指定的属性值
|
||||
- getAttributeNames():返回 request 对象所有属性的名字集合,结果是一个枚举的实例
|
||||
- getCookies():返回客户端的所有 Cookie 对象,结果是一个 Cookie 数组
|
||||
- getCharacterEncoding():返回请求中的字符编码方式 = getContentLength():返回请求的 Body 的长度
|
||||
- getHeader(String name):获得 HTTP 协议定义的文件头信息
|
||||
- getHeaders(String name):返回指定名字的 request Header 的所有值,结果是一个枚举的实例
|
||||
- getHeaderNames():返回所以 request Header 的名字,结果是一个枚举的实例
|
||||
- getInputStream():返回请求的输入流,用于获得请求中的数据
|
||||
- getMethod():获得客户端向服务器端传送数据的方法
|
||||
- getParameter(String name):获得客户端传送给服务器端的有 name 指定的参数值
|
||||
- getParameterNames():获得客户端传送给服务器端的所有参数的名字,结果是一个枚举的实例
|
||||
- getParameterValues(String name):获得有 name 指定的参数的所有值
|
||||
- getProtocol():获取客户端向服务器端传送数据所依据的协议名称
|
||||
- getQueryString():获得查询字符串
|
||||
- getRequestURI():获取发出请求字符串的客户端地址
|
||||
- getRemoteAddr():获取客户端的 IP 地址
|
||||
- getRemoteHost():获取客户端的名字
|
||||
- getSession([Boolean create]):返回和请求相关 Session
|
||||
- getServerName():获取服务器的名字
|
||||
- getServletPath():获取客户端所请求的脚本文件的路径
|
||||
- getServerPort():获取服务器的端口号
|
||||
- removeAttribute(String name):删除请求中的一个属性
|
||||
- `setAttribute(String name,Object)`:设置名字为 name 的 request 的参数值
|
||||
- `getAttribute(String name)`:返回由 name 指定的属性值
|
||||
- `getAttributeNames()`:返回 request 对象所有属性的名字集合,结果是一个枚举的实例
|
||||
- `getCookies()`:返回客户端的所有 Cookie 对象,结果是一个 Cookie 数组
|
||||
- `getCharacterEncoding()`:返回请求中的字符编码方式 = getContentLength()`:返回请求的 Body 的长度
|
||||
- `getHeader(String name)`:获得 HTTP 协议定义的文件头信息
|
||||
- `getHeaders(String name)`:返回指定名字的 request Header 的所有值,结果是一个枚举的实例
|
||||
- `getHeaderNames()`:返回所以 request Header 的名字,结果是一个枚举的实例
|
||||
- `getInputStream()`:返回请求的输入流,用于获得请求中的数据
|
||||
- `getMethod()`:获得客户端向服务器端传送数据的方法
|
||||
- `getParameter(String name)`:获得客户端传送给服务器端的有 name 指定的参数值
|
||||
- `getParameterNames()`:获得客户端传送给服务器端的所有参数的名字,结果是一个枚举的实例
|
||||
- `getParameterValues(String name)`:获得有 name 指定的参数的所有值
|
||||
- `getProtocol()`:获取客户端向服务器端传送数据所依据的协议名称
|
||||
- `getQueryString()`:获得查询字符串
|
||||
- `getRequestURI()`:获取发出请求字符串的客户端地址
|
||||
- `getRemoteAddr()`:获取客户端的 IP 地址
|
||||
- `getRemoteHost()`:获取客户端的名字
|
||||
- `getSession([Boolean create])`:返回和请求相关 Session
|
||||
- `getServerName()`:获取服务器的名字
|
||||
- `getServletPath()`:获取客户端所请求的脚本文件的路径
|
||||
- `getServerPort()`:获取服务器的端口号
|
||||
- `removeAttribute(String name)`:删除请求中的一个属性
|
||||
|
||||
## request.getAttribute()和 request.getParameter()有何区别
|
||||
|
||||
|
@ -42,8 +42,8 @@ package org.springframework.boot.autoconfigure;
|
||||
@SpringBootConfiguration
|
||||
@EnableAutoConfiguration
|
||||
@ComponentScan(excludeFilters = {
|
||||
@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
|
||||
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
|
||||
@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
|
||||
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
|
||||
public @interface SpringBootApplication {
|
||||
......
|
||||
}
|
||||
@ -582,33 +582,33 @@ jpa 提供的主键生成策略有如下几种:
|
||||
|
||||
```java
|
||||
public class DefaultIdentifierGeneratorFactory
|
||||
implements MutableIdentifierGeneratorFactory, Serializable, ServiceRegistryAwareService {
|
||||
implements MutableIdentifierGeneratorFactory, Serializable, ServiceRegistryAwareService {
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public DefaultIdentifierGeneratorFactory() {
|
||||
register( "uuid2", UUIDGenerator.class );
|
||||
register( "guid", GUIDGenerator.class ); // can be done with UUIDGenerator + strategy
|
||||
register( "uuid", UUIDHexGenerator.class ); // "deprecated" for new use
|
||||
register( "uuid.hex", UUIDHexGenerator.class ); // uuid.hex is deprecated
|
||||
register( "assigned", Assigned.class );
|
||||
register( "identity", IdentityGenerator.class );
|
||||
register( "select", SelectGenerator.class );
|
||||
register( "sequence", SequenceStyleGenerator.class );
|
||||
register( "seqhilo", SequenceHiLoGenerator.class );
|
||||
register( "increment", IncrementGenerator.class );
|
||||
register( "foreign", ForeignGenerator.class );
|
||||
register( "sequence-identity", SequenceIdentityGenerator.class );
|
||||
register( "enhanced-sequence", SequenceStyleGenerator.class );
|
||||
register( "enhanced-table", TableGenerator.class );
|
||||
}
|
||||
@SuppressWarnings("deprecation")
|
||||
public DefaultIdentifierGeneratorFactory() {
|
||||
register( "uuid2", UUIDGenerator.class );
|
||||
register( "guid", GUIDGenerator.class ); // can be done with UUIDGenerator + strategy
|
||||
register( "uuid", UUIDHexGenerator.class ); // "deprecated" for new use
|
||||
register( "uuid.hex", UUIDHexGenerator.class ); // uuid.hex is deprecated
|
||||
register( "assigned", Assigned.class );
|
||||
register( "identity", IdentityGenerator.class );
|
||||
register( "select", SelectGenerator.class );
|
||||
register( "sequence", SequenceStyleGenerator.class );
|
||||
register( "seqhilo", SequenceHiLoGenerator.class );
|
||||
register( "increment", IncrementGenerator.class );
|
||||
register( "foreign", ForeignGenerator.class );
|
||||
register( "sequence-identity", SequenceIdentityGenerator.class );
|
||||
register( "enhanced-sequence", SequenceStyleGenerator.class );
|
||||
register( "enhanced-table", TableGenerator.class );
|
||||
}
|
||||
|
||||
public void register(String strategy, Class generatorClass) {
|
||||
LOG.debugf( "Registering IdentifierGenerator strategy [%s] -> [%s]", strategy, generatorClass.getName() );
|
||||
final Class previous = generatorStrategyToClassNameMap.put( strategy, generatorClass );
|
||||
if ( previous != null ) {
|
||||
LOG.debugf( " - overriding [%s]", previous.getName() );
|
||||
}
|
||||
}
|
||||
public void register(String strategy, Class generatorClass) {
|
||||
LOG.debugf( "Registering IdentifierGenerator strategy [%s] -> [%s]", strategy, generatorClass.getName() );
|
||||
final Class previous = generatorStrategyToClassNameMap.put( strategy, generatorClass );
|
||||
if ( previous != null ) {
|
||||
LOG.debugf( " - overriding [%s]", previous.getName() );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
```
|
||||
|
@ -51,13 +51,13 @@ import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.support.FileSystemXmlApplicationContext;
|
||||
|
||||
public class App {
|
||||
public static void main(String[] args) {
|
||||
ApplicationContext context = new FileSystemXmlApplicationContext(
|
||||
"C:/work/IOC Containers/springframework.applicationcontext/src/main/resources/bean-factory-config.xml");
|
||||
public static void main(String[] args) {
|
||||
ApplicationContext context = new FileSystemXmlApplicationContext(
|
||||
"C:/work/IOC Containers/springframework.applicationcontext/src/main/resources/bean-factory-config.xml");
|
||||
|
||||
HelloApplicationContext obj = (HelloApplicationContext) context.getBean("helloApplicationContext");
|
||||
obj.getMsg();
|
||||
}
|
||||
HelloApplicationContext obj = (HelloApplicationContext) context.getBean("helloApplicationContext");
|
||||
obj.getMsg();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -16,7 +16,7 @@ head:
|
||||
|
||||
> 作者:转转技术团队
|
||||
>
|
||||
> 原文:https://mp.weixin.qq.com/s/ONMuELjdHYa0yQceTj01Iw
|
||||
> 原文:<https://mp.weixin.qq.com/s/ONMuELjdHYa0yQceTj01Iw>
|
||||
|
||||
## 老权限系统的问题与现状
|
||||
|
||||
@ -208,6 +208,6 @@ head:
|
||||
|
||||
## 参考
|
||||
|
||||
- 选择合适的权限模型:https://docs.authing.cn/v2/guides/access-control/choose-the-right-access-control-model.html
|
||||
- 选择合适的权限模型:<https://docs.authing.cn/v2/guides/access-control/choose-the-right-access-control-model.html>
|
||||
|
||||
<!-- @include: @article-footer.snippet.md -->
|
||||
|
Loading…
x
Reference in New Issue
Block a user