1
This commit is contained in:
commit
e6fa0a5afe
|
@ -1,3 +1,4 @@
|
|||
<<<<<<< HEAD
|
||||
# 一、数据类型
|
||||
|
||||
## 基本类型
|
||||
|
@ -17,6 +18,69 @@ boolean 只有两个值:true、false,可以使用 1 bit 来存储,但
|
|||
- [The Java® Virtual Machine Specification](https://docs.oracle.com/javase/specs/jvms/se8/jvms8.pdf)
|
||||
|
||||
## 包装类型
|
||||
=======
|
||||
<!-- GFM-TOC -->
|
||||
* [一、数据类型](#一数据类型)
|
||||
* [基本类型](#基本类型)
|
||||
* [包装类型](#包装类型)
|
||||
* [缓存池](#缓存池)
|
||||
* [二、String](#二string)
|
||||
* [概览](#概览)
|
||||
* [不可变的好处](#不可变的好处)
|
||||
* [String, StringBuffer and StringBuilder](#string,-stringbuffer-and-stringbuilder)
|
||||
* [String Pool](#string-pool)
|
||||
* [new String("abc")](#new-string"abc")
|
||||
* [三、运算](#三运算)
|
||||
* [参数传递](#参数传递)
|
||||
* [float 与 double](#float-与-double)
|
||||
* [隐式类型转换](#隐式类型转换)
|
||||
* [switch](#switch)
|
||||
* [四、继承](#四继承)
|
||||
* [访问权限](#访问权限)
|
||||
* [抽象类与接口](#抽象类与接口)
|
||||
* [super](#super)
|
||||
* [重写与重载](#重写与重载)
|
||||
* [五、Object 通用方法](#五object-通用方法)
|
||||
* [概览](#概览)
|
||||
* [equals()](#equals)
|
||||
* [hashCode()](#hashcode)
|
||||
* [toString()](#tostring)
|
||||
* [clone()](#clone)
|
||||
* [六、关键字](#六关键字)
|
||||
* [final](#final)
|
||||
* [static](#static)
|
||||
* [七、反射](#七反射)
|
||||
* [八、异常](#八异常)
|
||||
* [九、泛型](#九泛型)
|
||||
* [十、注解](#十注解)
|
||||
* [十一、特性](#十一特性)
|
||||
* [Java 各版本的新特性](#java-各版本的新特性)
|
||||
* [Java 与 C++ 的区别](#java-与-c-的区别)
|
||||
* [JRE or JDK](#jre-or-jdk)
|
||||
* [参考资料](#参考资料)
|
||||
<!-- GFM-TOC -->
|
||||
|
||||
|
||||
# 一、数据类型
|
||||
|
||||
## 基本类型
|
||||
|
||||
- byte/8
|
||||
- char/16
|
||||
- short/16
|
||||
- int/32
|
||||
- float/32
|
||||
- long/64
|
||||
- double/64
|
||||
- boolean/\~
|
||||
|
||||
boolean 只有两个值:true、false,可以使用 1 bit 来存储,但是具体大小没有明确规定。JVM 会在编译时期将 boolean 类型的数据转换为 int,使用 1 来表示 true,0 表示 false。JVM 支持 boolean 数组,但是是通过读写 byte 数组来实现的。
|
||||
|
||||
- [Primitive Data Types](https://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html)
|
||||
- [The Java® Virtual Machine Specification](https://docs.oracle.com/javase/specs/jvms/se8/jvms8.pdf)
|
||||
|
||||
## 包装类型
|
||||
>>>>>>> 9f680db0cc99bd992c7f979442ecf458a33f9c1b
|
||||
|
||||
基本类型都有对应的包装类型,基本类型与其对应的包装类型之间的赋值使用自动装箱与拆箱完成。
|
||||
|
||||
|
@ -626,8 +690,9 @@ SuperExtendExample.func()
|
|||
|
||||
存在于继承体系中,指子类实现了一个与父类在方法声明上完全相同的一个方法。
|
||||
|
||||
为了满足里式替换原则,重写有有以下两个限制:
|
||||
为了满足里式替换原则,重写有以下三个限制:
|
||||
|
||||
<<<<<<< HEAD
|
||||
使用 @Override 注解,可以让编译器帮忙检查是否满足上面的三个限制条件。
|
||||
|
||||
下面的示例中,SubClass 为 SuperClass 的子类,SubClass 重写了 SuperClass 的 func() 方法。其中:
|
||||
|
@ -649,6 +714,33 @@ class SubClass extends SuperClass {
|
|||
public ArrayList<Integer> func() throws Exception {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
=======
|
||||
- 子类方法的访问权限必须大于等于父类方法;
|
||||
- 子类方法的返回类型必须是父类方法返回类型或为其子类型。
|
||||
- 子类方法抛出的异常类型必须是父类抛出异常类型或为其子类型。
|
||||
|
||||
使用 @Override 注解,可以让编译器帮忙检查是否满足上面的三个限制条件。
|
||||
|
||||
下面的示例中,SubClass 为 SuperClass 的子类,SubClass 重写了 SuperClass 的 func() 方法。其中:
|
||||
|
||||
- 子类方法访问权限为 public,大于父类的 protected。
|
||||
- 子类的返回类型为 ArrayList<Integer>,是父类返回类型 List<Integer> 的子类。
|
||||
- 子类抛出的异常类型为 Exception,是父类抛出异常 Throwable 的子类。
|
||||
- 子类重写方法使用 @Override 注解,从而让编译器自动检查是否满足限制条件。
|
||||
|
||||
```java
|
||||
class SuperClass {
|
||||
protected List<Integer> func() throws Throwable {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
}
|
||||
|
||||
class SubClass extends SuperClass {
|
||||
@Override
|
||||
public ArrayList<Integer> func() throws Exception {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
>>>>>>> 9f680db0cc99bd992c7f979442ecf458a33f9c1b
|
||||
}
|
||||
```
|
||||
|
||||
|
|
|
@ -1,8 +1,77 @@
|
|||
<<<<<<< HEAD
|
||||
# 一、线程状态转换
|
||||
|
||||
![](index_files/96706658-b3f8-4f32-8eb3-dcb7fc8d5381.jpg)
|
||||
|
||||
## 新建(New)
|
||||
=======
|
||||
<!-- GFM-TOC -->
|
||||
* [一、线程状态转换](#一线程状态转换)
|
||||
* [新建(New)](#新建new)
|
||||
* [可运行(Runnable)](#可运行runnable)
|
||||
* [阻塞(Blocking)](#阻塞blocking)
|
||||
* [无限期等待(Waiting)](#无限期等待waiting)
|
||||
* [限期等待(Timed Waiting)](#限期等待timed-waiting)
|
||||
* [死亡(Terminated)](#死亡terminated)
|
||||
* [二、使用线程](#二使用线程)
|
||||
* [实现 Runnable 接口](#实现-runnable-接口)
|
||||
* [实现 Callable 接口](#实现-callable-接口)
|
||||
* [继承 Thread 类](#继承-thread-类)
|
||||
* [实现接口 VS 继承 Thread](#实现接口-vs-继承-thread)
|
||||
* [三、基础线程机制](#三基础线程机制)
|
||||
* [Executor](#executor)
|
||||
* [Daemon](#daemon)
|
||||
* [sleep()](#sleep)
|
||||
* [yield()](#yield)
|
||||
* [四、中断](#四中断)
|
||||
* [InterruptedException](#interruptedexception)
|
||||
* [interrupted()](#interrupted)
|
||||
* [Executor 的中断操作](#executor-的中断操作)
|
||||
* [五、互斥同步](#五互斥同步)
|
||||
* [synchronized](#synchronized)
|
||||
* [ReentrantLock](#reentrantlock)
|
||||
* [比较](#比较)
|
||||
* [使用选择](#使用选择)
|
||||
* [六、线程之间的协作](#六线程之间的协作)
|
||||
* [join()](#join)
|
||||
* [wait() notify() notifyAll()](#wait-notify-notifyall)
|
||||
* [await() signal() signalAll()](#await-signal-signalall)
|
||||
* [七、J.U.C - AQS](#七juc---aqs)
|
||||
* [CountDownLatch](#countdownlatch)
|
||||
* [CyclicBarrier](#cyclicbarrier)
|
||||
* [Semaphore](#semaphore)
|
||||
* [八、J.U.C - 其它组件](#八juc---其它组件)
|
||||
* [FutureTask](#futuretask)
|
||||
* [BlockingQueue](#blockingqueue)
|
||||
* [ForkJoin](#forkjoin)
|
||||
* [九、线程不安全示例](#九线程不安全示例)
|
||||
* [十、Java 内存模型](#十java-内存模型)
|
||||
* [主内存与工作内存](#主内存与工作内存)
|
||||
* [内存间交互操作](#内存间交互操作)
|
||||
* [内存模型三大特性](#内存模型三大特性)
|
||||
* [先行发生原则](#先行发生原则)
|
||||
* [十一、线程安全](#十一线程安全)
|
||||
* [不可变](#不可变)
|
||||
* [互斥同步](#互斥同步)
|
||||
* [非阻塞同步](#非阻塞同步)
|
||||
* [无同步方案](#无同步方案)
|
||||
* [十二、锁优化](#十二锁优化)
|
||||
* [自旋锁](#自旋锁)
|
||||
* [锁消除](#锁消除)
|
||||
* [锁粗化](#锁粗化)
|
||||
* [轻量级锁](#轻量级锁)
|
||||
* [偏向锁](#偏向锁)
|
||||
* [十三、多线程开发良好的实践](#十三多线程开发良好的实践)
|
||||
* [参考资料](#参考资料)
|
||||
<!-- GFM-TOC -->
|
||||
|
||||
|
||||
# 一、线程状态转换
|
||||
|
||||
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/96706658-b3f8-4f32-8eb3-dcb7fc8d5381.jpg"/> </div><br>
|
||||
|
||||
## 新建(New)
|
||||
>>>>>>> 9f680db0cc99bd992c7f979442ecf458a33f9c1b
|
||||
|
||||
创建后尚未启动。
|
||||
|
||||
|
@ -203,7 +272,11 @@ public void run() {
|
|||
|
||||
## InterruptedException
|
||||
|
||||
<<<<<<< HEAD
|
||||
通过调用一个线程的 interrupt() 来中断该线程,如果该线程处于阻塞、限期等待或者无限期等待状态,那么就会抛出 InterruptedException,从而提前结束该线程。但是不能中断 I/O 阻塞和 synchronized 锁阻塞。
|
||||
=======
|
||||
通过调用一个线程的 interrupt() 来中断该线程,如果该线程处于阻塞、有限期等待或者无限期等待状态,那么就会抛出 InterruptedException,从而提前结束该线程。但是不能中断 I/O 阻塞和 synchronized 锁阻塞。
|
||||
>>>>>>> 9f680db0cc99bd992c7f979442ecf458a33f9c1b
|
||||
|
||||
对于以下代码,在 main() 中启动一个线程之后再中断它,由于线程中调用了 Thread.sleep() 方法,因此会抛出一个 InterruptedException,从而提前结束线程,不执行之后的语句。
|
||||
|
||||
|
@ -1508,7 +1581,19 @@ public static String concatString(String s1, String s2, String s3) {
|
|||
|
||||
如果一系列的连续操作都对同一个对象反复加锁和解锁,频繁的加锁操作就会导致性能损耗。
|
||||
|
||||
<<<<<<< HEAD
|
||||
上一节的示例代码中连续的 append() 方法就属于这类情况。如果虚拟机探测到由这样的一串零碎的操作都对同一个对象加锁,将会把加锁的范围扩展(粗化)到整个操作序列的外部。对于上一节的示例代码就是扩展到第一个 append() 操作之前直至最后一个 append() 操作之后,这样只需要加锁一次就可以了。
|
||||
=======
|
||||
上一节的示例代码中连续的 append() 方法就属于这类情况。如果虚拟机探测到由这样的一串零碎的操作都对同一个对象加锁,将会把加锁的范围扩展(粗化)到整个操作序列的外部。对于上一节的示例代码就是扩展到第一个 append() 操作之前直至最后一个 append() 操作之后,这样只需要加锁一次就可以了。
|
||||
|
||||
## 轻量级锁
|
||||
|
||||
JDK 1.6 引入了偏向锁和轻量级锁,从而让锁拥有了四个状态:无锁状态(unlocked)、偏向锁状态(biased)、轻量级锁状态(lightweight locked)和重量级锁状态(inflated)。
|
||||
|
||||
以下是 HotSpot 虚拟机对象头的内存布局,这些数据被称为 Mark Word。其中 tag bits 对应了五个状态,这些状态在右侧的 state 表格中给出。除了 marked for gc 状态,其它四个状态已经在前面介绍过了。
|
||||
|
||||
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/bb6a49be-00f2-4f27-a0ce-4ed764bc605c.png" width="500"/> </div><br>
|
||||
>>>>>>> 9f680db0cc99bd992c7f979442ecf458a33f9c1b
|
||||
|
||||
## 轻量级锁
|
||||
|
||||
|
|
|
@ -216,7 +216,19 @@ obj = null;
|
|||
|
||||
- 需要移动大量对象,处理效率比较低。
|
||||
|
||||
<<<<<<< HEAD
|
||||
### 3. 复制
|
||||
=======
|
||||
优点:
|
||||
|
||||
- 不会产生内存碎片
|
||||
|
||||
不足:
|
||||
|
||||
- 在标记-清除的基础上还需进行对象的移动,成本相对较高
|
||||
|
||||
### 3. 复制
|
||||
>>>>>>> 9f680db0cc99bd992c7f979442ecf458a33f9c1b
|
||||
|
||||
![](index_files/4_2001550547640585.png)
|
||||
|
||||
|
@ -490,7 +502,11 @@ public static final int value = 123;
|
|||
|
||||
初始化阶段才真正开始执行类中定义的 Java 程序代码。初始化阶段是虚拟机执行类构造器 <clinit>() 方法的过程。在准备阶段,类变量已经赋过一次系统要求的初始值,而在初始化阶段,根据程序员通过程序制定的主观计划去初始化类变量和其它资源。
|
||||
|
||||
<<<<<<< HEAD
|
||||
<clinit>() 是由编译器自动收集类中所有类变量的赋值动作和静态语句块中的语句合并产生的,编译器收集的顺序由语句在源文件中出现的顺序决定。特别注意的是,静态语句块只能访问到定义在它之前的类变量,定义在它之后的类变量只能赋值,不能访问。例如以下代码:
|
||||
=======
|
||||
<clinit>() 是由编译器自动收集类中所有类变量的赋值动作和静态语句块中的语句合并产生的,编译器收集的顺序由语句在源文件中出现的顺序决定。特别注意的是,静态语句块只能访问到定义在它之前的类变量,定义在它之后的类变量只能赋值,不能访问。例如以下代码:
|
||||
>>>>>>> 9f680db0cc99bd992c7f979442ecf458a33f9c1b
|
||||
|
||||
```java
|
||||
public class Test {
|
||||
|
|
|
@ -1,6 +1,59 @@
|
|||
<<<<<<< HEAD
|
||||
# 一、概述
|
||||
|
||||
Redis 是速度非常快的非关系型(NoSQL)内存键值数据库,可以存储键和五种不同类型的值之间的映射。
|
||||
=======
|
||||
<!-- GFM-TOC -->
|
||||
* [一、概述](#一概述)
|
||||
* [二、数据类型](#二数据类型)
|
||||
* [STRING](#string)
|
||||
* [LIST](#list)
|
||||
* [SET](#set)
|
||||
* [HASH](#hash)
|
||||
* [ZSET](#zset)
|
||||
* [三、数据结构](#三数据结构)
|
||||
* [字典](#字典)
|
||||
* [跳跃表](#跳跃表)
|
||||
* [四、使用场景](#四使用场景)
|
||||
* [计数器](#计数器)
|
||||
* [缓存](#缓存)
|
||||
* [查找表](#查找表)
|
||||
* [消息队列](#消息队列)
|
||||
* [会话缓存](#会话缓存)
|
||||
* [分布式锁实现](#分布式锁实现)
|
||||
* [其它](#其它)
|
||||
* [五、Redis 与 Memcached](#五redis-与-memcached)
|
||||
* [数据类型](#数据类型)
|
||||
* [数据持久化](#数据持久化)
|
||||
* [分布式](#分布式)
|
||||
* [内存管理机制](#内存管理机制)
|
||||
* [六、键的过期时间](#六键的过期时间)
|
||||
* [七、数据淘汰策略](#七数据淘汰策略)
|
||||
* [八、持久化](#八持久化)
|
||||
* [RDB 持久化](#rdb-持久化)
|
||||
* [AOF 持久化](#aof-持久化)
|
||||
* [九、事务](#九事务)
|
||||
* [十、事件](#十事件)
|
||||
* [文件事件](#文件事件)
|
||||
* [时间事件](#时间事件)
|
||||
* [事件的调度与执行](#事件的调度与执行)
|
||||
* [十一、复制](#十一复制)
|
||||
* [连接过程](#连接过程)
|
||||
* [主从链](#主从链)
|
||||
* [十二、Sentinel](#十二sentinel)
|
||||
* [十三、分片](#十三分片)
|
||||
* [十四、一个简单的论坛系统分析](#十四一个简单的论坛系统分析)
|
||||
* [文章信息](#文章信息)
|
||||
* [点赞功能](#点赞功能)
|
||||
* [对文章进行排序](#对文章进行排序)
|
||||
* [参考资料](#参考资料)
|
||||
<!-- GFM-TOC -->
|
||||
|
||||
|
||||
# 一、概述
|
||||
|
||||
Redis 是速度非常快的非关系型(NoSQL)内存键值数据库,可以存储键和五种不同类型的值之间的映射。
|
||||
>>>>>>> 9f680db0cc99bd992c7f979442ecf458a33f9c1b
|
||||
|
||||
键的类型只能为字符串,值支持五种数据类型:字符串、列表、集合、散列表、有序集合。
|
||||
|
||||
|
@ -316,7 +369,11 @@ List 是一个双向链表,可以通过 lpop 和 lpush 写入和读取消
|
|||
|
||||
在分布式场景下,无法使用单机环境下的锁来对多个节点上的进程进行同步。
|
||||
|
||||
<<<<<<< HEAD
|
||||
可以使用 Redis 自带的 SETNX 命令实现分布式锁,除此之外,还可以使用官方提供的 RedLock 分布式锁实现。
|
||||
=======
|
||||
可以使用 Redis 自带的 SETNX 命令实现分布式锁,除此之外,还可以使用官方提供的 RedLock 分布式锁实现。
|
||||
>>>>>>> 9f680db0cc99bd992c7f979442ecf458a33f9c1b
|
||||
|
||||
## 其它
|
||||
|
||||
|
@ -358,7 +415,11 @@ Redis 可以为每个键设置过期时间,当键过期时,会自动删除
|
|||
|
||||
可以设置内存最大使用量,当内存使用量超出时,会施行数据淘汰策略。
|
||||
|
||||
<<<<<<< HEAD
|
||||
Redis 具体有 6 种淘汰策略:
|
||||
=======
|
||||
Redis 具体有 6 种淘汰策略:
|
||||
>>>>>>> 9f680db0cc99bd992c7f979442ecf458a33f9c1b
|
||||
|
||||
| 策略 | 描述 |
|
||||
| :--: | :--: |
|
||||
|
@ -508,7 +569,11 @@ Sentinel(哨兵)可以监听集群中的服务器,并在主服务器进入
|
|||
|
||||
分片是将数据划分为多个部分的方法,可以将数据存储到多台机器里面,这种方法在解决某些问题时可以获得线性级别的性能提升。
|
||||
|
||||
<<<<<<< HEAD
|
||||
假设有 4 个 Redis 实例 R0,R1,R2,R3,还有很多表示用户的键 user:1,user:2,... ,有不同的方式来选择一个指定的键存储在哪个实例中。
|
||||
=======
|
||||
假设有 4 个 Redis 实例 R0,R1,R2,R3,还有很多表示用户的键 user:1,user:2,... ,有不同的方式来选择一个指定的键存储在哪个实例中。
|
||||
>>>>>>> 9f680db0cc99bd992c7f979442ecf458a33f9c1b
|
||||
|
||||
- 最简单的方式是范围分片,例如用户 id 从 0~1000 的存储到实例 R0 中,用户 id 从 1001~2000 的存储到实例 R1 中,等等。但是这样需要维护一张映射范围表,维护操作代价很高。
|
||||
- 还有一种方式是哈希分片,使用 CRC32 哈希函数将键转换为一个数字,再对实例数量求模就能知道应该存储的实例。
|
||||
|
|
|
@ -1,4 +1,44 @@
|
|||
<<<<<<< HEAD
|
||||
# 20. 表示数值的字符串
|
||||
=======
|
||||
<!-- GFM-TOC -->
|
||||
* [20. 表示数值的字符串](#20-表示数值的字符串)
|
||||
* [题目描述](#题目描述)
|
||||
* [解题思路](#解题思路)
|
||||
* [21. 调整数组顺序使奇数位于偶数前面](#21-调整数组顺序使奇数位于偶数前面)
|
||||
* [题目描述](#题目描述)
|
||||
* [解题思路](#解题思路)
|
||||
* [22. 链表中倒数第 K 个结点](#22-链表中倒数第-k-个结点)
|
||||
* [解题思路](#解题思路)
|
||||
* [23. 链表中环的入口结点](#23-链表中环的入口结点)
|
||||
* [题目描述](#题目描述)
|
||||
* [解题思路](#解题思路)
|
||||
* [24. 反转链表](#24-反转链表)
|
||||
* [解题思路](#解题思路)
|
||||
* [递归](#递归)
|
||||
* [迭代](#迭代)
|
||||
* [25. 合并两个排序的链表](#25-合并两个排序的链表)
|
||||
* [题目描述](#题目描述)
|
||||
* [解题思路](#解题思路)
|
||||
* [递归](#递归)
|
||||
* [迭代](#迭代)
|
||||
* [26. 树的子结构](#26-树的子结构)
|
||||
* [题目描述](#题目描述)
|
||||
* [解题思路](#解题思路)
|
||||
* [27. 二叉树的镜像](#27-二叉树的镜像)
|
||||
* [题目描述](#题目描述)
|
||||
* [解题思路](#解题思路)
|
||||
* [28 对称的二叉树](#28-对称的二叉树)
|
||||
* [题目描述](#题目描述)
|
||||
* [解题思路](#解题思路)
|
||||
* [29. 顺时针打印矩阵](#29-顺时针打印矩阵)
|
||||
* [题目描述](#题目描述)
|
||||
* [解题思路](#解题思路)
|
||||
<!-- GFM-TOC -->
|
||||
|
||||
|
||||
# 20. 表示数值的字符串
|
||||
>>>>>>> 9f680db0cc99bd992c7f979442ecf458a33f9c1b
|
||||
|
||||
[NowCoder](https://www.nowcoder.com/practice/6f8c901d091949a5837e24bb82a731f2?tpId=13&tqId=11206&tPage=1&rp=1&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking)
|
||||
|
||||
|
|
|
@ -1,4 +1,14 @@
|
|||
<<<<<<< HEAD
|
||||
# 一、跨站脚本攻击
|
||||
=======
|
||||
<!-- GFM-TOC -->
|
||||
* [一、跨站脚本攻击](#一跨站脚本攻击)
|
||||
* [二、跨站请求伪造](#二跨站请求伪造)
|
||||
* [三、SQL 注入攻击](#三sql-注入攻击)
|
||||
* [四、拒绝服务攻击](#四拒绝服务攻击)
|
||||
* [参考资料](#参考资料)
|
||||
<!-- GFM-TOC -->
|
||||
>>>>>>> 9f680db0cc99bd992c7f979442ecf458a33f9c1b
|
||||
|
||||
## 概念
|
||||
|
||||
|
@ -34,7 +44,11 @@
|
|||
|
||||
### 2. 过滤特殊字符
|
||||
|
||||
<<<<<<< HEAD
|
||||
例如将 `<` 转义为 `<`,将 `>` 转义为 `>`,从而避免 HTML 和 Jascript 代码的运行。
|
||||
=======
|
||||
例如将 `<` 转义为 `<`,将 `>` 转义为 `>`,从而避免 HTML 和 Javascript 代码的运行。
|
||||
>>>>>>> 9f680db0cc99bd992c7f979442ecf458a33f9c1b
|
||||
|
||||
富文本编辑器允许用户输入 HTML 代码,就不能简单地将 `<` 等字符进行过滤了,极大地提高了 XSS 攻击的可能性。
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user