mirror of
https://github.com/Estom/notes.git
synced 2026-02-03 02:23:31 +08:00
优化JAVA和Script
This commit is contained in:
@@ -154,7 +154,7 @@ Java既需要编译也需要解释执行。
|
||||
|
||||
``` java
|
||||
/**
|
||||
* Java Doc 中的祖师格式
|
||||
* Java Doc 中的注释格式
|
||||
* /
|
||||
```
|
||||
|
||||
@@ -439,7 +439,7 @@ Java定义了位运算符,应用于整数类型(int),长整型(long),短
|
||||
| 操作符 | 描述 | 例子 |
|
||||
|---------------------|--------------------------------------------|--------------------------------|
|
||||
| & | 如果相对应位都是1,则结果为1,否则为0 | (A&B),得到12,即0000 1100 |
|
||||
| | | 如果相对应位都是 0,则结果为 0,否则为 1 | (A | B)得到61,即 0011 1101 |
|
||||
| \| | 如果相对应位都是 0,则结果为 0,否则为 1 | (A \| B)得到61,即 0011 1101 |
|
||||
| ^ | 如果相对应位值相同,则结果为0,否则为1 | (A ^ B)得到49,即 0011 0001 |
|
||||
| 〜 | 按位取反运算符翻转操作数的每一位,即0变成1,1变成0。 | (〜A)得到-61,即1100 0011 |
|
||||
| << | 按位左移运算符。左操作数按位左移右操作数指定的位数。 | A << 2得到240,即 1111 0000 |
|
||||
@@ -453,8 +453,7 @@ Java定义了位运算符,应用于整数类型(int),长整型(long),短
|
||||
| 操作符 | 描述 | 例子 |
|
||||
|------------|--------------------------------------------------|--------------------|
|
||||
| && | 称为逻辑与运算符。当且仅当两个操作数都为真,条件才为真。 | (A&&B)为假。 |
|
||||
|
|
||||
`||` | 称为逻辑或操作符。如果任何两个操作数任何一个为真,条件为真。 | (A`||`B)为真。 |
|
||||
| `\|\|` | 称为逻辑或操作符。如果任何两个操作数任何一个为真,条件为真。 | (A`\|\|`B)为真。 |
|
||||
| ! | 称为逻辑非运算符。用来反转操作数的逻辑状态。如果条件为true,则逻辑非运算符将得到false。 | !(A&&B)为真。 |
|
||||
|
||||
* 短路运算。当使用与逻辑运算符时,在两个操作数都为true时,结果才为true,但是当得到第一个操作为false时,其结果就必定是false,这时候就不会再判断第二个操作了。
|
||||
|
||||
@@ -7,9 +7,6 @@
|
||||
- [数组参数](#数组参数)
|
||||
- [数组返回值](#数组返回值)
|
||||
- [多维数组](#多维数组)
|
||||
- [2 Arrays类](#2-arrays类)
|
||||
- [方法概述](#方法概述)
|
||||
- [具体方法](#具体方法)
|
||||
# Java 数组
|
||||
## 1 概述
|
||||
|
||||
@@ -120,30 +117,3 @@ s[1][0] = new String("to");
|
||||
s[1][1] = new String("you");
|
||||
s[1][2] = new String("!");
|
||||
```
|
||||
|
||||
|
||||
## 2 Arrays类
|
||||
|
||||
### 方法概述
|
||||
|
||||
* 给数组赋值:通过 fill 方法。
|
||||
* 对数组排序:通过 sort 方法,按升序。
|
||||
* 比较数组:通过 equals 方法比较数组中元素值是否相等。
|
||||
* 查找数组元素:通过 binarySearch 方法能对排序好的数组进行二分查找法操作。
|
||||
|
||||
|
||||
### 具体方法
|
||||
```java
|
||||
public static int binarySearch(Object[] a, Object key)
|
||||
用二分查找算法在给定数组中搜索给定值的对象(Byte,Int,double等)。数组在调用前必须排序好的。如果查找值包含在数组中,则返回搜索键的索引;否则返回 (-(插入点) - 1)。
|
||||
public static boolean equals(long[] a, long[] a2)
|
||||
如果两个指定的 long 型数组彼此相等,则返回 true。如果两个数组包含相同数量的元素,并且两个数组中的所有相应元素对都是相等的,则认为这两个数组是相等的。换句话说,如果两个数组以相同顺序包含相同的元素,则两个数组是相等的。同样的方法适用于所有的其他基本数据类型(Byte,short,Int等)。
|
||||
public static void fill(int[] a, int val)
|
||||
将指定的 int 值分配给指定 int 型数组指定范围中的每个元素。同样的方法适用于所有的其他基本数据类型(Byte,short,Int等)。
|
||||
public static void sort(Object[] a)
|
||||
对指定对象数组根据其元素的自然顺序进行升序排列。同样的方法适用于所有的其他基本数据类型(Byte,short,Int等)。
|
||||
public static void toString(array[])
|
||||
依次打印元素
|
||||
public static void stream()
|
||||
转化成一个流
|
||||
```
|
||||
@@ -216,7 +216,7 @@ static{
|
||||
|
||||
- 每次执行类,加载类的时候都会先执行静态代码块一次。
|
||||
- 静态代码块是自动触发执行的,只要程序启动静态代码块就会先执行一次。
|
||||
- 作用:在启动程序之前可以做资源的初始化,一般用于初始化静态资源。
|
||||
- 作用:在启动程序之前可以做资源的初始化,一般用于初始化静态资源。注册驱动、加载 native 库、埋监控;
|
||||
|
||||
**案例演示**
|
||||
|
||||
@@ -242,7 +242,7 @@ public class DaimaKuaiDemo01 {
|
||||
### 实例代码块
|
||||
|
||||
**实例代码块**
|
||||
没有static修饰,必须放在类下。与对象初始化一起加载。
|
||||
没有static修饰,必须放在类下。与对象初始化一起加载。且先于构造函数执行。
|
||||
|
||||
**格式**
|
||||
|
||||
@@ -256,8 +256,8 @@ public class DaimaKuaiDemo01 {
|
||||
|
||||
- 无static修饰。属于对象,与对象的创建一起执行的。
|
||||
- 每次调用构造器初始化对象,实例代码块都要自动触发执行一次。
|
||||
- 实例代码块实际上是提取到每一个构造器中去执行的。
|
||||
- 作用:实例代码块用于初始化对象的资源。
|
||||
- 实例代码块实际上是提取到每一个构造器中去执行的。且先于构造函数执行。
|
||||
- 作用:实例代码块用于初始化对象的资源。例如:设置复杂的初始值,
|
||||
|
||||
**案例演示**
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
### Class对象
|
||||
|
||||
Class对象的作用
|
||||
* 每个类都有一个**Class**对象,包含了与类有关的信息,代表整个字节码。代表一个类型,代表整个类。。当编译一个新类时,会产生一个同名的 .class 文件,该文件内容保存着 Class 对象。
|
||||
* 每个类都有一个**Class**对象,包含了与类有关的信息,代表整个字节码。代表一个类型,代表整个类。当编译一个新类时,会产生一个同名的 .class 文件,该文件内容保存着 Class 对象。
|
||||
|
||||
* 类加载相当于 Class 对象的加载,类在第一次使用时才动态加载到 JVM 中。也可以使用 `Class.forName("com.mysql.jdbc.Driver")` 这种方式来控制类的加载,该方法会返回一个 Class 对象。
|
||||
|
||||
@@ -113,7 +113,6 @@ class ReflectTest02{
|
||||
// 通过反射机制,获取Class,通过Class来实例化对象
|
||||
Class c = Class.forName("javase.reflectBean.User");
|
||||
// newInstance() 这个方法会调用User这个类的无参数构造方法,完成对象的创建。
|
||||
// 重点是:newInstance()调用的是无参构造,必须保证无参构造是存在的!
|
||||
Object obj = c.newInstance();
|
||||
System.out.println(obj);
|
||||
}
|
||||
|
||||
@@ -14,8 +14,31 @@
|
||||
- [4 泛型通配符](#4-泛型通配符)
|
||||
- [5 泛型中的 KTVE](#5-泛型中的-ktve)
|
||||
- [6 泛型的实现原理](#6-泛型的实现原理)
|
||||
- [7 泛型实例化](#7-泛型实例化)
|
||||
- [7 泛型与反射](#7-泛型与反射)
|
||||
- [反射](#反射)
|
||||
- [8 泛型最佳实践](#8-泛型最佳实践)
|
||||
- [8.1 父类泛型化(模板基类)](#81-父类泛型化模板基类)
|
||||
- [8.2 子类保留泛型(继续向下传递)](#82-子类保留泛型继续向下传递)
|
||||
- [8.3 父类想“知道子类类型”:CRTP(自引用泛型)](#83-父类想知道子类类型crtp自引用泛型)
|
||||
- [9 复杂问题](#9-复杂问题)
|
||||
- [复杂问题 1 类型安全地组合“处理器/策略/管道”](#复杂问题-1-类型安全地组合处理器策略管道)
|
||||
- [定义泛型接口](#定义泛型接口)
|
||||
- [组合(关键:通配符)](#组合关键通配符)
|
||||
- [复杂问题 2:泛型 + 继承做“注册表/工厂/插件”](#复杂问题-2泛型--继承做注册表工厂插件)
|
||||
- [Key 用 `Class<T>`(类型令牌)](#key-用-classt类型令牌)
|
||||
- [复杂问题 3:泛型集合 API 设计(复制、merge、填充)](#复杂问题-3泛型集合-api-设计复制merge填充)
|
||||
- [复制:经典 `copy`](#复制经典-copy)
|
||||
- [merge:K/V 继承关系更复杂](#mergekv-继承关系更复杂)
|
||||
- [复杂问题 4:构建泛型数据库框架](#复杂问题-4构建泛型数据库框架)
|
||||
- [复杂问题 5:构建泛型缓存框架](#复杂问题-5构建泛型缓存框架)
|
||||
- [复杂问题 6:构建泛型事件系统](#复杂问题-6构建泛型事件系统)
|
||||
- [复杂问题 7:根据请求值类型定位返回值类型](#复杂问题-7根据请求值类型定位返回值类型)
|
||||
- [9 常见坑与建议](#9-常见坑与建议)
|
||||
- [不要在外部 API 滥用 `T extends Object`](#不要在外部-api-滥用-t-extends-object)
|
||||
- [避免返回 `List<?>` 这种“无法用”的类型](#避免返回-list-这种无法用的类型)
|
||||
- [数组与泛型不兼容](#数组与泛型不兼容)
|
||||
- [`Optional<? extends T>` 通常没必要](#optional-extends-t-通常没必要)
|
||||
- [`Comparable` 的正确写法](#comparable-的正确写法)
|
||||
|
||||
# 泛型机制
|
||||
|
||||
@@ -349,6 +372,11 @@ public class GenericMethodDemo {
|
||||
|
||||
Java 泛型的通配符是用于解决泛型之间引用传递问题的特殊语法。泛型与继承之间的关系
|
||||
|
||||
|
||||
- `? extends T`:**上界**(协变,用于“读”)
|
||||
- `? super T`:**下界**(逆变,用于“写”)
|
||||
|
||||
|
||||
1. 无边界通配符<?>
|
||||
1. 无边界的通配符的主要作用就是让泛型能够接受未知类型的数据.
|
||||
2. 固定上边界的通配符<? extends E>
|
||||
@@ -371,6 +399,29 @@ public class Apple<T extends A>{}
|
||||
public class Apple<T supers A>{}
|
||||
```
|
||||
|
||||
口诀:**PECS**
|
||||
**P**roducer-**E**xtends(生产者用 extends)
|
||||
**C**onsumer-**S**uper(消费者用 super)
|
||||
|
||||
例:读多写少
|
||||
```java
|
||||
static double sum(List<? extends Number> nums) {
|
||||
double s = 0;
|
||||
for (Number n : nums) s += n.doubleValue();
|
||||
return s;
|
||||
}
|
||||
```
|
||||
`List<Integer>`、`List<Double>` 都能传进来。
|
||||
|
||||
例:写入 T
|
||||
```java
|
||||
static void addInts(List<? super Integer> dst) {
|
||||
dst.add(1);
|
||||
dst.add(2);
|
||||
}
|
||||
```
|
||||
`List<Number>`、`List<Object>` 都能接收 Integer。
|
||||
|
||||
## 5 泛型中的 KTVE
|
||||
|
||||
泛型中的规范
|
||||
@@ -391,7 +442,7 @@ public class Apple<T supers A>{}
|
||||
实际上编译器不仅关注一个泛型方法的调用,它还会为某些返回值为限定的泛型类型的方法进行强制类型转换,由于类型擦除,返回值为泛型类型的方法都会擦除成 Object 类型,当这些方法被调用后,编译器会额外插入一行 checkcast 指令用于强制类型转换,这一个过程就叫做『泛型翻译』。
|
||||
|
||||
|
||||
## 7 泛型实例化
|
||||
## 7 泛型与反射
|
||||
|
||||
|
||||
### 反射
|
||||
@@ -459,4 +510,460 @@ Class.forName(className).newInstance()
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
```
|
||||
|
||||
## 8 泛型最佳实践
|
||||
|
||||
继承体系里怎么用泛型:三种典型结构
|
||||
|
||||
### 8.1 父类泛型化(模板基类)
|
||||
让子类指定具体类型:
|
||||
|
||||
```java
|
||||
abstract class Repository<ID, E> {
|
||||
abstract E findById(ID id);
|
||||
abstract void save(E e);
|
||||
}
|
||||
|
||||
class UserRepo extends Repository<Long, User> {
|
||||
@Override User findById(Long id) { ... }
|
||||
@Override void save(User u) { ... }
|
||||
}
|
||||
```
|
||||
|
||||
适合:DAO、Client、Handler 这类“同一个模式,不同实体类型”。
|
||||
|
||||
---
|
||||
|
||||
### 8.2 子类保留泛型(继续向下传递)
|
||||
```java
|
||||
class Box<T> { T value; }
|
||||
|
||||
class TimedBox<T> extends Box<T> {
|
||||
long time;
|
||||
}
|
||||
```
|
||||
|
||||
适合:装饰/增强、公共能力复用(缓存、计时、审计)。
|
||||
|
||||
---
|
||||
|
||||
### 8.3 父类想“知道子类类型”:CRTP(自引用泛型)
|
||||
用于**流式 API / Builder / DSL**,解决“父类方法返回子类类型”的问题:
|
||||
|
||||
```java
|
||||
abstract class BaseBuilder<B extends BaseBuilder<B>> {
|
||||
protected abstract B self();
|
||||
public B withName(String name) { /*...*/ return self(); }
|
||||
}
|
||||
|
||||
class UserBuilder extends BaseBuilder<UserBuilder> {
|
||||
@Override protected UserBuilder self() { return this; }
|
||||
}
|
||||
```
|
||||
|
||||
调用方能得到正确链式类型:`new UserBuilder().withName("a")...`
|
||||
|
||||
---
|
||||
|
||||
## 9 复杂问题
|
||||
|
||||
### 复杂问题 1 类型安全地组合“处理器/策略/管道”
|
||||
目标:一套管道把 `I -> O` 转换串起来,同时支持继承、多态组合。
|
||||
|
||||
#### 定义泛型接口
|
||||
```java
|
||||
interface Handler<I, O> {
|
||||
O handle(I input);
|
||||
}
|
||||
```
|
||||
|
||||
#### 组合(关键:通配符)
|
||||
组合函数:把 `Handler<A,B>` 和 `Handler<B,C>` 组合成 `Handler<A,C>`。
|
||||
|
||||
```java
|
||||
static <A, B, C> Handler<A, C> compose(
|
||||
Handler<? super A, ? extends B> h1,
|
||||
Handler<? super B, ? extends C> h2) {
|
||||
return a -> h2.handle(h1.handle(a));
|
||||
}
|
||||
```
|
||||
|
||||
为什么这么写?
|
||||
- h1 能接收 A 的父类(`? super A`)
|
||||
- h1 的输出是 B 的子类(`? extends B`)
|
||||
- h2 同理
|
||||
这让组合对继承层次更“宽容”。
|
||||
|
||||
---
|
||||
|
||||
### 复杂问题 2:泛型 + 继承做“注册表/工厂/插件”
|
||||
目标:根据类型拿到对应实现,例如 `Service` 按请求类型分发。
|
||||
|
||||
#### Key 用 `Class<T>`(类型令牌)
|
||||
```java
|
||||
interface Processor<T> {
|
||||
void process(T input);
|
||||
}
|
||||
|
||||
class Registry {
|
||||
private final Map<Class<?>, Processor<?>> map = new HashMap<>();
|
||||
|
||||
public <T> void register(Class<T> type, Processor<? super T> p) {
|
||||
map.put(type, p);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> Processor<T> get(Class<T> type) {
|
||||
return (Processor<T>) map.get(type);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
要点:
|
||||
- `register` 用 `Processor<? super T>`:允许用更通用的处理器注册(比如处理 `Number` 的处理器也能处理 `Integer`)。
|
||||
- `get` 由于类型擦除,需要一次受控的强转;对外 API 仍然是类型安全的。
|
||||
|
||||
---
|
||||
|
||||
### 复杂问题 3:泛型集合 API 设计(复制、merge、填充)
|
||||
#### 复制:经典 `copy`
|
||||
```java
|
||||
static <T> void copy(List<? super T> dst, List<? extends T> src) {
|
||||
for (T t : src) dst.add(t);
|
||||
}
|
||||
```
|
||||
- src 生产 T:`extends`
|
||||
- dst 消费 T:`super`
|
||||
|
||||
#### merge:K/V 继承关系更复杂
|
||||
```java
|
||||
static <K, V> void putAll(Map<? super K, ? super V> dst,
|
||||
Map<? extends K, ? extends V> src) {
|
||||
for (var e : src.entrySet()) {
|
||||
dst.put(e.getKey(), e.getValue());
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### 复杂问题 4:构建泛型数据库框架
|
||||
|
||||
```java
|
||||
// 基础实体类
|
||||
public abstract class BaseEntity {
|
||||
private Long id;
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
}
|
||||
|
||||
// 通用Repository接口
|
||||
public interface IRepository<T extends BaseEntity> {
|
||||
void save(T entity);
|
||||
T findById(Long id);
|
||||
List<T> findAll();
|
||||
void update(T entity);
|
||||
void delete(Long id);
|
||||
}
|
||||
|
||||
// 抽象实现
|
||||
public abstract class AbstractRepository<T extends BaseEntity>
|
||||
implements IRepository<T> {
|
||||
|
||||
protected Map<Long, T> database = new HashMap<>();
|
||||
protected Long idCounter = 0L;
|
||||
|
||||
@Override
|
||||
public void save(T entity) {
|
||||
entity.setId(++idCounter);
|
||||
database.put(entity.getId(), entity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T findById(Long id) {
|
||||
return database.get(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<T> findAll() {
|
||||
return new ArrayList<>(database.values());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(T entity) {
|
||||
database.put(entity.getId(), entity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete(Long id) {
|
||||
database.remove(id);
|
||||
}
|
||||
}
|
||||
|
||||
// 具体实现
|
||||
public class UserRepository extends AbstractRepository<User> {
|
||||
public List<User> findByName(String name) {
|
||||
return findAll().stream()
|
||||
.filter(user -> user.getName().equals(name))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
|
||||
public class User extends BaseEntity {
|
||||
private String name;
|
||||
private String email;
|
||||
|
||||
public User(String name, String email) {
|
||||
this.name = name;
|
||||
this.email = email;
|
||||
}
|
||||
|
||||
// getters and setters
|
||||
public String getName() { return name; }
|
||||
public void setName(String name) { this.name = name; }
|
||||
public String getEmail() { return email; }
|
||||
public void setEmail(String email) { this.email = email; }
|
||||
}
|
||||
|
||||
// 使用
|
||||
UserRepository userRepo = new UserRepository();
|
||||
User user = new User("张三", "zhangsan@example.com");
|
||||
userRepo.save(user);
|
||||
System.out.println(userRepo.findById(1L).getName());
|
||||
```
|
||||
|
||||
### 复杂问题 5:构建泛型缓存框架
|
||||
|
||||
```java
|
||||
// 缓存策略接口
|
||||
public interface CacheStrategy<K, V> {
|
||||
void put(K key, V value);
|
||||
V get(K key);
|
||||
void remove(K key);
|
||||
void clear();
|
||||
}
|
||||
|
||||
// LRU缓存实现
|
||||
public class LRUCache<K, V> implements CacheStrategy<K, V> {
|
||||
private final int capacity;
|
||||
private final LinkedHashMap<K, V> cache;
|
||||
|
||||
public LRUCache(int capacity) {
|
||||
this.capacity = capacity;
|
||||
this.cache = new LinkedHashMap<K, V>(capacity, 0.75f, true) {
|
||||
@Override
|
||||
protected boolean removeEldestEntry(Map.Entry eldest) {
|
||||
return size() > capacity;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public void put(K key, V value) {
|
||||
cache.put(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public V get(K key) {
|
||||
return cache.get(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove(K key) {
|
||||
cache.remove(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
cache.clear();
|
||||
}
|
||||
}
|
||||
|
||||
// 缓存管理器
|
||||
public class CacheManager<K, V> {
|
||||
private CacheStrategy<K, V> strategy;
|
||||
|
||||
public CacheManager(CacheStrategy<K, V> strategy) {
|
||||
this.strategy = strategy;
|
||||
}
|
||||
|
||||
public void set(K key, V value) {
|
||||
strategy.put(key, value);
|
||||
}
|
||||
|
||||
public V get(K key) {
|
||||
V value = strategy.get(key);
|
||||
if (value == null) {
|
||||
// 可以从数据库加载
|
||||
System.out.println("从数据库加载: " + key);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
// 使用
|
||||
CacheManager<String, User> userCache =
|
||||
new CacheManager<>(new LRUCache<>(100));
|
||||
|
||||
User user = new User("张三", "zhangsan@example.com");
|
||||
userCache.set("user:1", user);
|
||||
User cached = userCache.get("user:1");
|
||||
```
|
||||
|
||||
### 复杂问题 6:构建泛型事件系统
|
||||
|
||||
```java
|
||||
// 事件基类
|
||||
public abstract class Event {
|
||||
private long timestamp;
|
||||
|
||||
public Event() {
|
||||
this.timestamp = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
public long getTimestamp() {
|
||||
return timestamp;
|
||||
}
|
||||
}
|
||||
|
||||
// 具体事件
|
||||
public class UserCreatedEvent extends Event {
|
||||
private User user;
|
||||
|
||||
public UserCreatedEvent(User user) {
|
||||
this.user = user;
|
||||
}
|
||||
|
||||
public User getUser() {
|
||||
return user;
|
||||
}
|
||||
}
|
||||
|
||||
// 事件监听器接口
|
||||
public interface EventListener<T extends Event> {
|
||||
void onEvent(T event);
|
||||
}
|
||||
|
||||
// 事件发布器
|
||||
public class EventPublisher {
|
||||
private Map<Class<?>, List<EventListener<?>>> listeners =
|
||||
new HashMap<>();
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T extends Event> void subscribe(Class<T> eventType,
|
||||
EventListener<T> listener) {
|
||||
listeners.computeIfAbsent(eventType, k -> new ArrayList<>())
|
||||
.add(listener);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T extends Event> void publish(T event) {
|
||||
List<EventListener<?>> eventListeners =
|
||||
listeners.get(event.getClass());
|
||||
|
||||
if (eventListeners != null) {
|
||||
for (EventListener<?> listener : eventListeners) {
|
||||
((EventListener<T>) listener).onEvent(event);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 使用
|
||||
EventPublisher publisher = new EventPublisher();
|
||||
|
||||
publisher.subscribe(UserCreatedEvent.class, event -> {
|
||||
System.out.println("用户创建事件: " + event.getUser().getName());
|
||||
});
|
||||
|
||||
User user = new User("李四", "lisi@example.com");
|
||||
publisher.publish(new UserCreatedEvent(user));
|
||||
```
|
||||
|
||||
### 复杂问题 7:根据请求值类型定位返回值类型
|
||||
|
||||
“请求-响应对”+“策略分发”
|
||||
|
||||
```java
|
||||
// 1. 标记接口:Request<对应的 Response>
|
||||
public interface Request<R extends Response> {}
|
||||
|
||||
public interface Response {}
|
||||
|
||||
// 2. 具体请求-响应对
|
||||
public class CreateUserReq implements Request<CreateUserRsp> {
|
||||
private String name;
|
||||
// getter/setter
|
||||
}
|
||||
|
||||
public class CreateUserRsp implements Response {
|
||||
private Long id;
|
||||
}
|
||||
|
||||
// 3. 处理器接口
|
||||
public interface Handler<Rq extends Request<Rs>, Rs extends Response> {
|
||||
Rs handle(Rq request);
|
||||
}
|
||||
|
||||
// 4. 处理器实现
|
||||
public class CreateUserHandler implements Handler<CreateUserReq, CreateUserRsp> {
|
||||
@Override
|
||||
public CreateUserRsp handle(CreateUserReq req) {
|
||||
return new CreateUserRsp(1L);
|
||||
}
|
||||
}
|
||||
|
||||
// 5. 分发器(线程安全)
|
||||
public class Dispatcher {
|
||||
private final Map<Class<?>, Handler<?, ?>> map = new ConcurrentHashMap<>();
|
||||
|
||||
public <Rq extends Request<Rs>, Rs extends Response>
|
||||
void register(Class<Rq> reqType, Handler<Rq, Rs> handler) {
|
||||
map.put(reqType, handler);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <Rs extends Response> Rs execute(Request<Rs> request) {
|
||||
Handler<?, ?> h = map.get(request.getClass());
|
||||
if (h == null) throw new IllegalArgumentException("no handler");
|
||||
return ((Handler<Request<Rs>, Rs>) h).handle(request);
|
||||
}
|
||||
}
|
||||
|
||||
// 6. 使用
|
||||
Dispatcher dispatcher = new Dispatcher();
|
||||
dispatcher.register(CreateUserReq.class, new CreateUserHandler());
|
||||
|
||||
CreateUserRsp rsp = dispatcher.execute(new CreateUserReq("tom"));
|
||||
System.out.println(rsp.getId());
|
||||
```
|
||||
|
||||
|
||||
## 9 常见坑与建议
|
||||
|
||||
### 不要在外部 API 滥用 `T extends Object`
|
||||
没意义,默认就是 Object 上界。
|
||||
|
||||
### 避免返回 `List<?>` 这种“无法用”的类型
|
||||
返回 `List<T>` 或 `List<? extends Base>` 更实用。
|
||||
|
||||
### 数组与泛型不兼容
|
||||
`new T[]` 不允许;用 `List<T>` 或传 `IntFunction<T[]>` / `Class<T>` 创建。
|
||||
|
||||
### `Optional<? extends T>` 通常没必要
|
||||
多用 `Optional<T>`;在参数处才常用通配符。
|
||||
|
||||
### `Comparable` 的正确写法
|
||||
```java
|
||||
class A implements Comparable<A> { ... }
|
||||
```
|
||||
如果写工具方法:
|
||||
```java
|
||||
static <T extends Comparable<? super T>> T max(List<? extends T> list) { ... }
|
||||
```
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
|
||||
|
||||
## 1 Arrays类
|
||||
|
||||
### 方法概述
|
||||
|
||||
* 给数组赋值:通过 fill 方法。
|
||||
* 对数组排序:通过 sort 方法,按升序。
|
||||
* 比较数组:通过 equals 方法比较数组中元素值是否相等。
|
||||
* 查找数组元素:通过 binarySearch 方法能对排序好的数组进行二分查找法操作。
|
||||
|
||||
|
||||
### 具体方法
|
||||
```java
|
||||
public static int binarySearch(Object[] a, Object key)
|
||||
用二分查找算法在给定数组中搜索给定值的对象(Byte,Int,double等)。数组在调用前必须排序好的。如果查找值包含在数组中,则返回搜索键的索引;否则返回 (-(插入点) - 1)。
|
||||
public static boolean equals(long[] a, long[] a2)
|
||||
如果两个指定的 long 型数组彼此相等,则返回 true。如果两个数组包含相同数量的元素,并且两个数组中的所有相应元素对都是相等的,则认为这两个数组是相等的。换句话说,如果两个数组以相同顺序包含相同的元素,则两个数组是相等的。同样的方法适用于所有的其他基本数据类型(Byte,short,Int等)。
|
||||
public static void fill(int[] a, int val)
|
||||
将指定的 int 值分配给指定 int 型数组指定范围中的每个元素。同样的方法适用于所有的其他基本数据类型(Byte,short,Int等)。
|
||||
public static void sort(Object[] a)
|
||||
对指定对象数组根据其元素的自然顺序进行升序排列。同样的方法适用于所有的其他基本数据类型(Byte,short,Int等)。
|
||||
public static void toString(array[])
|
||||
依次打印元素
|
||||
public static void stream()
|
||||
转化成一个流
|
||||
```
|
||||
195
Java/09 Java面试总结/自引用泛型概述.md
Normal file
195
Java/09 Java面试总结/自引用泛型概述.md
Normal file
@@ -0,0 +1,195 @@
|
||||
自引用泛型(Self-referential generics / F-bounded polymorphism,很多人也叫 CRTP 风格)指:**类型参数的上界本身又引用了这个类型参数**,典型形态是:
|
||||
|
||||
```java
|
||||
class Base<T extends Base<T>> { ... }
|
||||
```
|
||||
|
||||
含义:`T` 必须是“某个继承自 `Base<T>` 的类型”,从而让 Base 在编译期“知道”子类的精确类型。
|
||||
|
||||
---
|
||||
|
||||
## 1 要解决什么问题:父类方法想返回“子类类型”
|
||||
### 没用自引用泛型时的问题
|
||||
```java
|
||||
class Base {
|
||||
Base withName(String n) { return this; }
|
||||
}
|
||||
class UserBuilder extends Base { }
|
||||
|
||||
UserBuilder b = new UserBuilder();
|
||||
b.withName("a") // 返回 Base
|
||||
.withName("b"); // 链式调用类型会退化成 Base
|
||||
```
|
||||
|
||||
你会失去子类特有方法的链式调用:
|
||||
|
||||
```java
|
||||
b.withName("a").onlyInUser(); // 编译不过,因为 withName 返回 Base
|
||||
```
|
||||
|
||||
### 用自引用泛型(让返回类型保持为子类)
|
||||
```java
|
||||
abstract class Base<B extends Base<B>> {
|
||||
protected abstract B self();
|
||||
|
||||
public B withName(String n) {
|
||||
// ... set field
|
||||
return self();
|
||||
}
|
||||
}
|
||||
|
||||
class UserBuilder extends Base<UserBuilder> {
|
||||
@Override protected UserBuilder self() { return this; }
|
||||
|
||||
public UserBuilder onlyInUser() { return this; }
|
||||
}
|
||||
```
|
||||
|
||||
现在:
|
||||
|
||||
```java
|
||||
new UserBuilder()
|
||||
.withName("a")
|
||||
.onlyInUser()
|
||||
.withName("b");
|
||||
```
|
||||
|
||||
链式调用始终保持 `UserBuilder` 类型。
|
||||
|
||||
---
|
||||
|
||||
## 2 它到底“类型上”在约束什么?
|
||||
这句:
|
||||
|
||||
```java
|
||||
B extends Base<B>
|
||||
```
|
||||
|
||||
表示:`B` 不是随便的类型,它必须满足:
|
||||
|
||||
- `B` 是 `Base<B>` 的子类型
|
||||
|
||||
所以 `class UserBuilder extends Base<UserBuilder>` 合法;
|
||||
但 `class X extends Base<String>` 不合法(String 不是 Base<String>)。
|
||||
|
||||
这种约束让 Base 能安全地把 `this` 视作 `B`(通过 `self()` 或强转),从而在 Base 里写出“返回子类”的 API。
|
||||
|
||||
---
|
||||
|
||||
## 3 为什么需要 `self()`?能不能直接 `(B) this`?
|
||||
可以强转,但不推荐暴露在公共基类里。
|
||||
|
||||
### 方案 A:强转(常见但有风险)
|
||||
```java
|
||||
abstract class Base<B extends Base<B>> {
|
||||
@SuppressWarnings("unchecked")
|
||||
protected B self() { return (B) this; }
|
||||
|
||||
public B withName(String n) { return self(); }
|
||||
}
|
||||
```
|
||||
|
||||
风险在于:如果有人写了“破坏约束”的继承结构(通过原始类型 raw type 绕过),运行期可能 `ClassCastException`。
|
||||
|
||||
### 方案 B:子类实现 self(更稳)
|
||||
```java
|
||||
abstract class Base<B extends Base<B>> {
|
||||
protected abstract B self();
|
||||
}
|
||||
```
|
||||
|
||||
子类返回 `this`,不需要 unchecked cast,更清晰。
|
||||
|
||||
---
|
||||
|
||||
## 4 典型使用场景
|
||||
### 4.1 Builder / Fluent API(最常见)
|
||||
让基类提供通用链式方法(name、id、tags…),子类还能追加自身方法且不中断链式。
|
||||
|
||||
### 4.2 “可比较/可排序”这类自类型约束(JDK 经典)
|
||||
`Comparable` 是个“弱化版”案例:
|
||||
|
||||
```java
|
||||
class MyType implements Comparable<MyType> { ... }
|
||||
```
|
||||
|
||||
工具方法里常见约束:
|
||||
|
||||
```java
|
||||
static <T extends Comparable<? super T>> T max(List<? extends T> list) { ... }
|
||||
```
|
||||
|
||||
这也是为了兼容继承关系(`? super T`)。
|
||||
|
||||
### 4.3 框架基类:返回子类、注册子类、DSL
|
||||
例如:
|
||||
- ORM/Query DSL:`Query<T extends Query<T>> where(...)`
|
||||
- 图结构/节点 API:`Node<N extends Node<N>> addChild(N child)`
|
||||
|
||||
---
|
||||
|
||||
## 5 多层继承时怎么写?
|
||||
你可以把“自类型参数”一路传下去:
|
||||
|
||||
```java
|
||||
abstract class Base<B extends Base<B>> {
|
||||
protected abstract B self();
|
||||
public B common() { return self(); }
|
||||
}
|
||||
|
||||
abstract class Mid<B extends Mid<B>> extends Base<B> {
|
||||
public B mid() { return self(); }
|
||||
}
|
||||
|
||||
class Concrete extends Mid<Concrete> {
|
||||
@Override protected Concrete self() { return this; }
|
||||
public Concrete only() { return this; }
|
||||
}
|
||||
```
|
||||
|
||||
调用:`new Concrete().common().mid().only();` 都保持 `Concrete`。
|
||||
|
||||
---
|
||||
|
||||
## 6 常见坑
|
||||
### 6.1 原始类型(raw type)会破坏类型安全
|
||||
```java
|
||||
class Bad extends Base { // 使用 raw type
|
||||
@Override protected Base self() { return this; }
|
||||
}
|
||||
```
|
||||
这会导致泛型约束失效,可能埋下运行期强转问题。尽量禁止 raw type。
|
||||
|
||||
### 6.2 “写错自类型”导致诡异编译错误
|
||||
```java
|
||||
class A extends Base<B> { ... } // B 不是 A
|
||||
```
|
||||
自引用泛型的关键是:**参数必须是“自己”**(或至少保持一致的自类型),一般写成 `extends Base<当前类名>`。
|
||||
|
||||
### 6.3 组合(composition)有时比继承更简单
|
||||
如果只是想链式配置,有时用组合/返回 `this` 并配合接口也能做,别为了泛型而泛型。
|
||||
|
||||
---
|
||||
|
||||
## 7 一个更完整的“可复用 Builder 基类”例子
|
||||
```java
|
||||
abstract class Builder<B extends Builder<B>> {
|
||||
protected String name;
|
||||
protected int age;
|
||||
|
||||
protected abstract B self();
|
||||
|
||||
public B name(String n) { this.name = n; return self(); }
|
||||
public B age(int a) { this.age = a; return self(); }
|
||||
}
|
||||
|
||||
class UserBuilder extends Builder<UserBuilder> {
|
||||
private String email;
|
||||
|
||||
@Override protected UserBuilder self() { return this; }
|
||||
|
||||
public UserBuilder email(String e) { this.email = e; return this; }
|
||||
|
||||
public User build() { return new User(name, age, email); }
|
||||
}
|
||||
```
|
||||
512
Rust/02 Rust内置工具库/01 指针工具.md
Normal file
512
Rust/02 Rust内置工具库/01 指针工具.md
Normal file
@@ -0,0 +1,512 @@
|
||||
# Rust标准库中的指针使用详解
|
||||
|
||||
## 📌 Rust指针概览
|
||||
|
||||
Rust中有两种主要指针类型:
|
||||
|
||||
| 指针类型 | 符号 | 所有权 | 可变性 | 安全性 | 用途 |
|
||||
|---------|------|--------|--------|--------|------|
|
||||
| **引用** | `&T` / `&mut T` | 借用 | 受控 | 安全 | 日常使用 |
|
||||
| **原始指针** | `*const T` / `*mut T` | 无 | 受控 | 不安全 | FFI、特殊场景 |
|
||||
| **智能指针** | `Box`, `Rc`, `Arc` | 拥有 | 受控 | 安全 | 堆分配、共享所有权 |
|
||||
|
||||
---
|
||||
|
||||
## 1️⃣ 不可变引用 &T
|
||||
|
||||
### 基础用法
|
||||
|
||||
```rust
|
||||
// ✅ 创建不可变引用
|
||||
fn main() {
|
||||
let x = 5;
|
||||
let r = &x; // r是指向x的不可变引用
|
||||
|
||||
println!("x: {}, r: {}", x, *r); // *r 解引用
|
||||
// 输出:x: 5, r: 5
|
||||
}
|
||||
```
|
||||
|
||||
### 多个不可变引用
|
||||
|
||||
```rust
|
||||
fn main() {
|
||||
let x = 5;
|
||||
|
||||
// ✅ 可以有多个不可变引用
|
||||
let r1 = &x;
|
||||
let r2 = &x;
|
||||
let r3 = &x;
|
||||
|
||||
println!("r1: {}, r2: {}, r3: {}", r1, r2, r3);
|
||||
// 都指向同一个x,互不干扰
|
||||
}
|
||||
```
|
||||
|
||||
### 引用指针的特性
|
||||
|
||||
```rust
|
||||
fn main() {
|
||||
let x = vec![1, 2, 3];
|
||||
let r = &x;
|
||||
|
||||
// ✅ 不可变引用可以调用只读方法
|
||||
println!("len: {}", r.len());
|
||||
println!("first: {:?}", r.first());
|
||||
|
||||
// ❌ 不能通过不可变引用修改
|
||||
// r.push(4); // 编译错误
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2️⃣ 可变引用 &mut T
|
||||
|
||||
### 基础用法
|
||||
|
||||
```rust
|
||||
// ✅ 创建可变引用
|
||||
fn main() {
|
||||
let mut x = 5;
|
||||
let r = &mut x; // r是指向x的可变引用
|
||||
|
||||
*r += 1; // 通过可变引用修改值
|
||||
println!("x: {}", x); // 输出:x: 6
|
||||
}
|
||||
```
|
||||
|
||||
### 独占性规则
|
||||
|
||||
```rust
|
||||
fn main() {
|
||||
let mut x = 5;
|
||||
|
||||
let r1 = &mut x;
|
||||
// ❌ 不能有第二个可变引用
|
||||
// let r2 = &mut x; // 编译错误
|
||||
|
||||
*r1 += 1;
|
||||
println!("r1: {}", r1);
|
||||
|
||||
// ✅ r1作用域结束后,可以创建新的可变引用
|
||||
let r2 = &mut x;
|
||||
*r2 += 1;
|
||||
println!("r2: {}", r2);
|
||||
}
|
||||
```
|
||||
|
||||
### 可变引用和不可变引用不能共存
|
||||
|
||||
```rust
|
||||
fn main() {
|
||||
let mut x = 5;
|
||||
|
||||
let r1 = &x; // ✅ 不可变引用
|
||||
let r2 = &x; // ✅ 不可变引用
|
||||
|
||||
// ❌ 有了不可变引用后,不能创建可变引用
|
||||
// let r3 = &mut x; // 编译错误
|
||||
|
||||
println!("r1: {}, r2: {}", r1, r2);
|
||||
|
||||
// ✅ r1, r2的作用域结束后,可以创建可变引用
|
||||
let r3 = &mut x;
|
||||
*r3 += 1;
|
||||
println!("r3: {}", r3);
|
||||
}
|
||||
```
|
||||
|
||||
### 修改容器内容
|
||||
|
||||
```rust
|
||||
fn main() {
|
||||
let mut vec = vec![1, 2, 3];
|
||||
let r = &mut vec;
|
||||
|
||||
// ✅ 可以修改容器内容
|
||||
r.push(4);
|
||||
r[0] = 10;
|
||||
|
||||
println!("vec: {:?}", vec); // [10, 2, 3, 4]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3️⃣ 原始指针 *const T 和 *mut T
|
||||
|
||||
### 创建原始指针
|
||||
|
||||
```rust
|
||||
fn main() {
|
||||
let x = 5;
|
||||
|
||||
// ✅ 创建不可变原始指针(安全)
|
||||
let p1: *const i32 = &x as *const i32;
|
||||
|
||||
let mut y = 10;
|
||||
// ✅ 创建可变原始指针(安全)
|
||||
let p2: *mut i32 = &mut y as *mut i32;
|
||||
|
||||
// ❌ 解引用原始指针必须在unsafe块中
|
||||
unsafe {
|
||||
println!("*p1: {}", *p1); // 5
|
||||
println!("*p2: {}", *p2); // 10
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 原始指针的特点
|
||||
|
||||
```rust
|
||||
fn main() {
|
||||
let x = 5;
|
||||
let p1 = &x as *const i32;
|
||||
|
||||
// ✅ 原始指针可以被忽视借用规则
|
||||
let p2 = &x as *const i32; // 可以创建多个
|
||||
|
||||
// ✅ 原始指针可以为null
|
||||
let null_ptr: *const i32 = std::ptr::null();
|
||||
|
||||
unsafe {
|
||||
if null_ptr.is_null() {
|
||||
println!("指针为null");
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 原始指针的风险
|
||||
|
||||
```rust
|
||||
// ❌ 危险用法:悬垂指针
|
||||
fn dangle() -> *const i32 {
|
||||
let x = 5;
|
||||
&x as *const i32 // ❌ x在函数结束后被释放
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let p = dangle();
|
||||
unsafe {
|
||||
// ❌ 访问已释放的内存(未定义行为)
|
||||
// println!("{}", *p);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 有效的原始指针用法
|
||||
|
||||
```rust
|
||||
// ✅ 与FFI交互
|
||||
extern "C" {
|
||||
fn some_c_function(ptr: *const u8);
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let x = vec![1, 2, 3];
|
||||
|
||||
unsafe {
|
||||
// ✅ 传递给C函数
|
||||
some_c_function(x.as_ptr());
|
||||
}
|
||||
}
|
||||
|
||||
// ✅ 手动内存管理
|
||||
fn manual_allocation() {
|
||||
unsafe {
|
||||
let ptr = std::alloc::alloc(std::alloc::Layout::new::<i32>());
|
||||
*(ptr as *mut i32) = 42;
|
||||
println!("值: {}", *(ptr as *const i32));
|
||||
std::alloc::dealloc(ptr, std::alloc::Layout::new::<i32>());
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4️⃣ Box<T>(堆分配)
|
||||
|
||||
### 基础用法
|
||||
|
||||
```rust
|
||||
fn main() {
|
||||
// ✅ Box分配在堆上
|
||||
let b = Box::new(5);
|
||||
println!("b: {}", b); // 5
|
||||
|
||||
// ✅ Box实现了Deref,可以直接使用
|
||||
let x = *b;
|
||||
println!("x: {}", x); // 5
|
||||
}
|
||||
```
|
||||
|
||||
### 递归类型
|
||||
|
||||
```rust
|
||||
// ❌ 普通递归类型无限大小
|
||||
// enum List {
|
||||
// Cons(i32, List), // 错误:大小无限
|
||||
// Nil,
|
||||
// }
|
||||
|
||||
// ✅ 使用Box使递归类型可行
|
||||
#[derive(Debug)]
|
||||
enum List {
|
||||
Cons(i32, Box<List>),
|
||||
Nil,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let list = List::Cons(1,
|
||||
Box::new(List::Cons(2,
|
||||
Box::new(List::Cons(3,
|
||||
Box::new(List::Nil)
|
||||
))
|
||||
))
|
||||
);
|
||||
|
||||
println!("{:?}", list);
|
||||
}
|
||||
```
|
||||
|
||||
### Box的转移所有权
|
||||
|
||||
```rust
|
||||
fn main() {
|
||||
let b = Box::new(5);
|
||||
|
||||
// ✅ Box实现了Move语义
|
||||
let x = b; // 所有权转移
|
||||
|
||||
// ❌ b不再可用
|
||||
// println!("{}", b); // 编译错误
|
||||
|
||||
println!("x: {}", x);
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5️⃣ Rc<T>(引用计数)
|
||||
|
||||
### 基础用法
|
||||
|
||||
```rust
|
||||
use std::rc::Rc;
|
||||
|
||||
fn main() {
|
||||
// ✅ 创建Rc
|
||||
let rc1 = Rc::new(5);
|
||||
let rc2 = rc1.clone(); // 克隆引用(不是数据)
|
||||
let rc3 = rc1.clone();
|
||||
|
||||
println!("rc1: {}, rc2: {}, rc3: {}", rc1, rc2, rc3);
|
||||
|
||||
// ✅ 所有Rc共享同一个数据
|
||||
println!("引用计数: {}", Rc::strong_count(&rc1)); // 3
|
||||
}
|
||||
```
|
||||
|
||||
### Rc的共享所有权
|
||||
|
||||
```rust
|
||||
use std::rc::Rc;
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Node {
|
||||
value: i32,
|
||||
next: Option<Rc<Node>>,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
// ✅ 多个所有者共享一个Node
|
||||
let node = Rc::new(Node {
|
||||
value: 1,
|
||||
next: None,
|
||||
});
|
||||
|
||||
let node2 = Rc::clone(&node);
|
||||
let node3 = node.clone();
|
||||
|
||||
println!("引用计数: {}", Rc::strong_count(&node)); // 3
|
||||
}
|
||||
```
|
||||
|
||||
### Rc配合RefCell实现内部可变性
|
||||
|
||||
```rust
|
||||
use std::rc::Rc;
|
||||
use std::cell::RefCell;
|
||||
|
||||
fn main() {
|
||||
// ✅ Rc<RefCell<T>>允许共享且可变的数据
|
||||
let data = Rc::new(RefCell::new(vec![1, 2, 3]));
|
||||
|
||||
let data1 = data.clone();
|
||||
let data2 = data.clone();
|
||||
|
||||
// ✅ 修改数据
|
||||
data1.borrow_mut().push(4);
|
||||
data2.borrow_mut().push(5);
|
||||
|
||||
println!("data: {:?}", data.borrow()); // [1, 2, 3, 4, 5]
|
||||
}
|
||||
```
|
||||
|
||||
### ❌ Rc不是线程安全的
|
||||
|
||||
```rust
|
||||
use std::rc::Rc;
|
||||
use std::thread;
|
||||
|
||||
fn main() {
|
||||
let rc = Rc::new(5);
|
||||
|
||||
// ❌ Rc不实现Send和Sync
|
||||
// let handle = thread::spawn(move || {
|
||||
// println!("{}", rc); // 编译错误
|
||||
// });
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6️⃣ Arc<T>(原子引用计数)
|
||||
|
||||
### 基础用法
|
||||
|
||||
```rust
|
||||
use std::sync::Arc;
|
||||
use std::thread;
|
||||
|
||||
fn main() {
|
||||
// ✅ Arc是线程安全的
|
||||
let arc = Arc::new(vec![1, 2, 3]);
|
||||
|
||||
let mut handles = vec![];
|
||||
|
||||
for i in 0..3 {
|
||||
let arc_clone = arc.clone();
|
||||
let handle = thread::spawn(move || {
|
||||
println!("线程{}: {:?}", i, arc_clone);
|
||||
});
|
||||
handles.push(handle);
|
||||
}
|
||||
|
||||
for handle in handles {
|
||||
handle.join().unwrap();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Arc的性能
|
||||
|
||||
```rust
|
||||
use std::sync::Arc;
|
||||
|
||||
fn main() {
|
||||
let arc = Arc::new(vec![1, 2, 3, 4, 5]);
|
||||
|
||||
// ✅ Arc使用原子操作更新计数(线程安全但有开销)
|
||||
let clone1 = arc.clone(); // 原子操作增加计数
|
||||
let clone2 = arc.clone(); // 原子操作增加计数
|
||||
|
||||
println!("强引用计数: {}", Arc::strong_count(&arc)); // 3
|
||||
|
||||
drop(clone1); // 原子操作减少计数
|
||||
println!("强引用计数: {}", Arc::strong_count(&arc)); // 2
|
||||
}
|
||||
```
|
||||
|
||||
### Arc配合Mutex实现线程安全的共享可变数据
|
||||
|
||||
```rust
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::thread;
|
||||
|
||||
fn main() {
|
||||
// ✅ Arc<Mutex<T>>是线程安全的共享可变数据
|
||||
let counter = Arc::new(Mutex::new(0));
|
||||
let mut handles = vec![];
|
||||
|
||||
for _ in 0..10 {
|
||||
let counter = Arc::clone(&counter);
|
||||
let handle = thread::spawn(move || {
|
||||
let mut num = counter.lock().unwrap();
|
||||
*num += 1;
|
||||
});
|
||||
handles.push(handle);
|
||||
}
|
||||
|
||||
for handle in handles {
|
||||
handle.join().unwrap();
|
||||
}
|
||||
|
||||
println!("计数: {}", *counter.lock().unwrap()); // 10
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7️⃣ 内部可变性模式
|
||||
|
||||
### RefCell<T>
|
||||
|
||||
```rust
|
||||
use std::cell::RefCell;
|
||||
|
||||
fn main() {
|
||||
let x = RefCell::new(5);
|
||||
|
||||
// ✅ 通过不可变引用修改值
|
||||
*x.borrow_mut() = 10;
|
||||
|
||||
println!("x: {}", x.borrow()); // 10
|
||||
}
|
||||
|
||||
// ❌ 运行时借用检查失败
|
||||
fn runtime_borrow_panic() {
|
||||
let x = RefCell::new(5);
|
||||
|
||||
let r1 = x.borrow();
|
||||
// ❌ 在不可变借用存在时进行可变借用
|
||||
// let r2 = x.borrow_mut(); // panic!
|
||||
}
|
||||
```
|
||||
|
||||
### Cell<T>(Copy类型)
|
||||
|
||||
```rust
|
||||
use std::cell::Cell;
|
||||
|
||||
fn main() {
|
||||
let x = Cell::new(5);
|
||||
|
||||
// ✅ Cell<T>无运行时开销
|
||||
x.set(10);
|
||||
println!("x: {}", x.get()); // 10
|
||||
}
|
||||
```
|
||||
|
||||
### UnsafeCell<T>(基础构块)
|
||||
|
||||
```rust
|
||||
use std::cell::UnsafeCell;
|
||||
|
||||
fn main() {
|
||||
let x = UnsafeCell::new(5);
|
||||
|
||||
unsafe {
|
||||
// ✅ UnsafeCell允许通过不可变引用修改
|
||||
*x.get() = 10;
|
||||
println!("x: {}", *x.get()); // 10
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8️⃣ Weak<T>(弱引用)
|
||||
|
||||
10
Script/network/tinyproxy.sh
Normal file
10
Script/network/tinyproxy.sh
Normal file
@@ -0,0 +1,10 @@
|
||||
sudo yum install tinyproxy -y # 或 dnf install tinyproxy -y
|
||||
sudo apt update && sudo apt install tinyproxy -y
|
||||
|
||||
sudo vim /etc/tinyproxy/tinyproxy.conf
|
||||
|
||||
sudo systemctl restart tinyproxy
|
||||
sudo systemctl enable tinyproxy
|
||||
|
||||
|
||||
curl -x http://服务器IP:8888 http://httpbin.org/ip
|
||||
@@ -4,7 +4,7 @@ git push git@github.com:Estom/notes.git
|
||||
|
||||
|
||||
# 统计代码的数量
|
||||
find . -name "*.java" -exec wc -l {} \;#利用exec参数
|
||||
find . -name "*.java" -exec wc -l {} \; # 利用exec参数
|
||||
find . -name "*.java" |xargs wc -l # 利用xargs参数
|
||||
find . -name "*.java" -exec wc -l {} \; | awk 'BEGIN{num=0} {num+=$1;print $1;}END{print num}'
|
||||
|
||||
13
test.sh
Normal file
13
test.sh
Normal file
@@ -0,0 +1,13 @@
|
||||
#!/bin/sh
|
||||
# 保存为 git-time.sh && chmod +x git-time.sh
|
||||
echo "file,create_time,modify_time"
|
||||
git ls-files | while read f; do
|
||||
# 最早一次提交时间(近似创建)
|
||||
c_time=$(git log --diff-filter=A --format=%ct -1 -- "$f" 2>/dev/null || echo '')
|
||||
# 最近一次提交时间(变更)
|
||||
m_time=$(git log -1 --format=%ct -- "$f")
|
||||
# 转成可读格式(去掉下一行则保持 Unix 秒)
|
||||
[ -n "$c_time" ] && c_time=$(date -d @$c_time '+%F %T') || c_time='MISSING'
|
||||
m_time=$(date -d @$m_time '+%F %T')
|
||||
echo "\"$f\",\"$c_time\",\"$m_time\""
|
||||
done
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
## 1 基础
|
||||
|
||||
### 位运算
|
||||
### 位运算基础
|
||||
|
||||
符号|说明|特性
|
||||
|----|----|---|
|
||||
@@ -13,7 +13,14 @@
|
||||
\>\> | 右移|
|
||||
<< | 左移|
|
||||
|
||||
## 2 特殊性质
|
||||
负数在计算机中使用补码表示,主要目标就是实现了最小值到最大值之间,位运算的连续性。
|
||||
|
||||
在字面数字运算中,-2 加1为-1,-1 加1为0,0+1为1。是连续计算的。
|
||||
在二级制补码计算中。也满足上述的计算规则。1111表示-1,加一通过溢出一位,变为0000,成为0.
|
||||
|
||||
实际上-1是按位绝对值最大的数,即1111。
|
||||
|
||||
### 特殊性质
|
||||
操作 | 性质
|
||||
|-----| -----|
|
||||
n & (n - 1) | n中的最后一个1变成0。
|
||||
@@ -24,7 +31,7 @@ n*2 | 等价于 左移一位 n << 1
|
||||
n % 2 |等价于 判断二进制最右一位值 n \& 1
|
||||
|
||||
|
||||
## 3 常见算法
|
||||
## 2 常见算法
|
||||
|
||||
### 快速幂
|
||||
* 使用二进制方法,将幂转换成二进制。二进制每个位的权重就是可以递推计算,与二分法效果相同。
|
||||
@@ -90,7 +97,7 @@ int add(int a,int b){
|
||||
}
|
||||
```
|
||||
|
||||
## 4 位运算与编码
|
||||
## 3 位运算与编码
|
||||
|
||||
* 编码有两种计算方式,一种是数值上计算负数的补码。另一种是按位运算计算负数的补码。前者是运算关系。后者是根据定义。
|
||||
|
||||
@@ -116,4 +123,428 @@ $$
|
||||
X = (\sim |X|)+1
|
||||
$$
|
||||
|
||||
* 为了满足数值计算,使得正数负数能够在同一的编码下进行加减计算。正数的机器数,原码,反码,补码,都是在固定字长下讨论的负数的补码是在其原码的基础上, 符号位不变, 其余各位取反, 最后+1。机器中只有加法而没有减法。
|
||||
* 为了满足数值计算,使得正数负数能够在同一的编码下进行加减计算。正数的机器数,原码,反码,补码,都是在固定字长下讨论的负数的补码是在其原码的基础上, 符号位不变, 其余各位取反, 最后+1。机器中只有加法而没有减法。
|
||||
|
||||
|
||||
## 4 位运算实现加减乘除
|
||||
|
||||
|
||||
|
||||
### 1️⃣ 加法(Addition)
|
||||
|
||||
#### 基本思路
|
||||
|
||||
```
|
||||
加法的本质:
|
||||
1. XOR(^)用来计算不进位的加法
|
||||
2. AND(&)用来计算进位
|
||||
3. 左移(<<)用来进位
|
||||
|
||||
例如:5 + 3 = 8
|
||||
5 = 0101
|
||||
3 = 0011
|
||||
|
||||
步骤1:不进位加法 (5 ^ 3)
|
||||
0101 ^ 0011 = 0110 = 6
|
||||
|
||||
步骤2:进位 (5 & 3) << 1
|
||||
(0101 & 0011) << 1 = 0001 << 1 = 0010 = 2
|
||||
|
||||
步骤3:继续加法 6 + 2
|
||||
重复上述步骤直到进位为0
|
||||
```
|
||||
|
||||
#### 实现
|
||||
|
||||
```java
|
||||
public class BitwiseOperations {
|
||||
|
||||
// ✅ 位运算实现加法
|
||||
public static int add(int a, int b) {
|
||||
while (b != 0) {
|
||||
// 计算进位
|
||||
int carry = (a & b) << 1;
|
||||
|
||||
// 计算不进位的和
|
||||
a = a ^ b;
|
||||
|
||||
// 进位加到结果中
|
||||
b = carry;
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println("5 + 3 = " + add(5, 3)); // 8
|
||||
System.out.println("10 + 20 = " + add(10, 20)); // 30
|
||||
System.out.println("-5 + 3 = " + add(-5, 3)); // -2
|
||||
}
|
||||
}
|
||||
|
||||
/* 执行过程演示:5 + 3
|
||||
第一次循环:
|
||||
a = 0101, b = 0011
|
||||
carry = (0101 & 0011) << 1 = 0010 = 2
|
||||
a = 0101 ^ 0011 = 0110 = 6
|
||||
b = 2
|
||||
|
||||
第二次循环:
|
||||
a = 0110, b = 0010
|
||||
carry = (0110 & 0010) << 1 = 0100 = 4
|
||||
a = 0110 ^ 0010 = 0100 = 4
|
||||
b = 4
|
||||
|
||||
第三次循环:
|
||||
a = 0100, b = 0100
|
||||
carry = (0100 & 0100) << 1 = 1000 = 8
|
||||
a = 0100 ^ 0100 = 0000 = 0
|
||||
b = 8
|
||||
|
||||
第四次循环:
|
||||
a = 0000, b = 1000
|
||||
carry = (0000 & 1000) << 1 = 0
|
||||
a = 0000 ^ 1000 = 1000 = 8
|
||||
b = 0
|
||||
|
||||
b = 0,退出循环
|
||||
结果 a = 8
|
||||
*/
|
||||
```
|
||||
|
||||
#### 简洁版本
|
||||
|
||||
```java
|
||||
public class BitwiseAdd {
|
||||
public static int add(int a, int b) {
|
||||
return b == 0 ? a : add(a ^ b, (a & b) << 1);
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println(add(5, 3)); // 8
|
||||
System.out.println(add(-1, 1)); // 0
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 2️⃣ 减法(Subtraction)
|
||||
|
||||
#### 基本思路
|
||||
|
||||
```
|
||||
减法的本质:a - b = a + (-b)
|
||||
|
||||
-b的补码计算:
|
||||
-b = ~b + 1
|
||||
|
||||
例如:5 - 3 = 5 + (-3) = 5 + (~3 + 1) = 5 + (-4) = 1
|
||||
3 = 0011
|
||||
~3 = 1100 = -4(补码表示)
|
||||
-3 = ~3 + 1 = 1101 = -3
|
||||
|
||||
5 - 3 = 5 + (-3)(使用位运算加法)
|
||||
```
|
||||
|
||||
#### 实现
|
||||
|
||||
```java
|
||||
public class BitwiseSubtraction {
|
||||
|
||||
// ✅ 位运算实现加法
|
||||
private static int add(int a, int b) {
|
||||
while (b != 0) {
|
||||
int carry = (a & b) << 1;
|
||||
a = a ^ b;
|
||||
b = carry;
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
// ✅ 位运算实现减法
|
||||
public static int subtract(int a, int b) {
|
||||
// a - b = a + (-b)
|
||||
// -b = ~b + 1 = ~b + add(0, 1)
|
||||
return add(a, add(~b, 1));
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println("5 - 3 = " + subtract(5, 3)); // 2
|
||||
System.out.println("10 - 20 = " + subtract(10, 20)); // -10
|
||||
System.out.println("-5 - 3 = " + subtract(-5, 3)); // -8
|
||||
}
|
||||
}
|
||||
|
||||
/* 执行过程演示:5 - 3
|
||||
1. 计算 -3 = ~3 + 1
|
||||
~3 = 1111...1100 (补码)
|
||||
~3 + 1 = 1111...1101 = -3
|
||||
|
||||
2. 计算 5 + (-3) = 2
|
||||
*/
|
||||
```
|
||||
|
||||
#### 简洁版本
|
||||
|
||||
```java
|
||||
public static int subtract(int a, int b) {
|
||||
return add(a, add(~b, 1));
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 3️⃣ 乘法(Multiplication)
|
||||
|
||||
#### 基本思路
|
||||
|
||||
```
|
||||
乘法的本质:a * b = a * (2^n + ... + 2^1 + 2^0)
|
||||
|
||||
例如:5 * 3 = 5 * 2 + 5 * 1 = 10 + 5 = 15
|
||||
|
||||
3 的二进制:0011
|
||||
= 2^1 + 2^0
|
||||
= 2 + 1
|
||||
|
||||
所以 5 * 3 = 5 * 2 + 5 * 1
|
||||
= 5 << 1 + 5 << 0
|
||||
= 10 + 5
|
||||
= 15
|
||||
|
||||
算法:
|
||||
1. 检查b的每一位
|
||||
2. 如果该位是1,就把a左移相应位数,加到结果中
|
||||
3. 重复直到b变为0
|
||||
```
|
||||
|
||||
#### 实现
|
||||
|
||||
```java
|
||||
public class BitwiseMultiplication {
|
||||
|
||||
private static int add(int a, int b) {
|
||||
while (b != 0) {
|
||||
int carry = (a & b) << 1;
|
||||
a = a ^ b;
|
||||
b = carry;
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
// ✅ 位运算实现乘法
|
||||
public static int multiply(int a, int b) {
|
||||
if (b == 0) return 0;
|
||||
|
||||
int result = 0;
|
||||
int absA = a < 0 ? add(~a, 1) : a; // 获取绝对值
|
||||
int absB = b < 0 ? add(~b, 1) : b;
|
||||
|
||||
// 遍历b的每一位
|
||||
while (absB != 0) {
|
||||
// 如果b的最低位是1
|
||||
if ((absB & 1) == 1) {
|
||||
result = add(result, absA);
|
||||
}
|
||||
|
||||
// a左移,b右移
|
||||
absA = absA << 1;
|
||||
absB = absB >> 1;
|
||||
}
|
||||
|
||||
// 处理符号
|
||||
if ((a < 0) ^ (b < 0)) { // 异号
|
||||
result = add(~result, 1);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println("5 * 3 = " + multiply(5, 3)); // 15
|
||||
System.out.println("5 * 0 = " + multiply(5, 0)); // 0
|
||||
System.out.println("-5 * 3 = " + multiply(-5, 3)); // -15
|
||||
System.out.println("5 * -3 = " + multiply(5, -3)); // -15
|
||||
}
|
||||
}
|
||||
|
||||
/* 执行过程演示:5 * 3
|
||||
5 = 0101
|
||||
3 = 0011
|
||||
|
||||
第一次循环(b最低位是1):
|
||||
result = 0 + 5 = 5
|
||||
absA = 5 << 1 = 10
|
||||
absB = 3 >> 1 = 1 (0001)
|
||||
|
||||
第二次循环(b最低位是1):
|
||||
result = 5 + 10 = 15
|
||||
absA = 10 << 1 = 20
|
||||
absB = 1 >> 1 = 0
|
||||
|
||||
b = 0,退出
|
||||
结果 = 15
|
||||
*/
|
||||
```
|
||||
|
||||
#### 高效版本(利用左移快速乘以2)
|
||||
|
||||
```java
|
||||
public static int multiply(int a, int b) {
|
||||
if (b == 0) return 0;
|
||||
|
||||
int result = 0;
|
||||
|
||||
while (b != 0) {
|
||||
// 如果b的最低位是1
|
||||
if ((b & 1) == 1) {
|
||||
result = add(result, a);
|
||||
}
|
||||
|
||||
a = a << 1; // 相当于a * 2
|
||||
b = b >> 1; // 相当于b / 2
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 4️⃣ 除法(Division)
|
||||
|
||||
#### 基本思路
|
||||
|
||||
```
|
||||
除法的本质:a / b = 找出最大的q,使得 b * q <= a
|
||||
|
||||
例如:15 / 3 = ?
|
||||
找最大的q,使得 3 * q <= 15
|
||||
3 * 5 = 15 <= 15 ✓
|
||||
3 * 6 = 18 > 15 ✗
|
||||
所以 15 / 3 = 5
|
||||
|
||||
使用二分查找或逐步减法:
|
||||
15 - 3 = 12
|
||||
12 - 3 = 9
|
||||
9 - 3 = 6
|
||||
6 - 3 = 3
|
||||
3 - 3 = 0
|
||||
共减了5次,所以15 / 3 = 5
|
||||
```
|
||||
|
||||
#### 实现版本1:逐步减法(效率低)
|
||||
|
||||
```java
|
||||
public class BitwiseDivision {
|
||||
|
||||
private static int add(int a, int b) {
|
||||
while (b != 0) {
|
||||
int carry = (a & b) << 1;
|
||||
a = a ^ b;
|
||||
b = carry;
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
private static int subtract(int a, int b) {
|
||||
return add(a, add(~b, 1));
|
||||
}
|
||||
|
||||
private static int multiply(int a, int b) {
|
||||
if (b == 0) return 0;
|
||||
int result = 0;
|
||||
while (b != 0) {
|
||||
if ((b & 1) == 1) {
|
||||
result = add(result, a);
|
||||
}
|
||||
a = a << 1;
|
||||
b = b >> 1;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// ✅ 位运算实现除法(逐步减法)
|
||||
public static int divide(int a, int b) {
|
||||
if (b == 0) throw new ArithmeticException("除数不能为0");
|
||||
|
||||
int absA = a < 0 ? add(~a, 1) : a;
|
||||
int absB = b < 0 ? add(~b, 1) : b;
|
||||
|
||||
int result = 0;
|
||||
|
||||
// 逐步减法
|
||||
while (absA >= absB) {
|
||||
absA = subtract(absA, absB);
|
||||
result = add(result, 1);
|
||||
}
|
||||
|
||||
// 处理符号
|
||||
if ((a < 0) ^ (b < 0)) {
|
||||
result = add(~result, 1);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println("15 / 3 = " + divide(15, 3)); // 5
|
||||
System.out.println("10 / 3 = " + divide(10, 3)); // 3
|
||||
System.out.println("20 / 4 = " + divide(20, 4)); // 5
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 实现版本2:二分查找(效率高)⭐⭐⭐⭐⭐
|
||||
|
||||
```java
|
||||
public class BitwiseDivisionBinary {
|
||||
|
||||
private static int add(int a, int b) {
|
||||
while (b != 0) {
|
||||
int carry = (a & b) << 1;
|
||||
a = a ^ b;
|
||||
b = carry;
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
private static int subtract(int a, int b) {
|
||||
return add(a, add(~b, 1));
|
||||
}
|
||||
|
||||
private static int multiply(int a, int b) {
|
||||
if (b == 0) return 0;
|
||||
int result = 0;
|
||||
while (b != 0) {
|
||||
if ((b & 1) == 1) {
|
||||
result = add(result, a);
|
||||
}
|
||||
a = a << 1;
|
||||
b = b >> 1;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// ✅ 位运算实现除法(二分查找,高效)
|
||||
public static int divide(int a, int b) {
|
||||
if (b == 0) throw new ArithmeticException("除数不能为0");
|
||||
|
||||
boolean negative = (a < 0) ^ (b < 0);
|
||||
|
||||
long absA = a < 0 ? -(long)a : a;
|
||||
long absB = b < 0 ? -(long)b : b;
|
||||
|
||||
long result = 0;
|
||||
|
||||
// 从高位到低位进行二分
|
||||
for (int i = 31; i >= 0; i--) {
|
||||
// 如果 absB << i <= absA,则第i位为1
|
||||
if ((absB << i) <= absA) {
|
||||
absA = subtract(absA, absB << i);
|
||||
result = result | (1L << i); // 设置第i位为1
|
||||
}
|
||||
}
|
||||
|
||||
return (int)(negative
|
||||
```
|
||||
Reference in New Issue
Block a user