3 changed files with 0 additions and 204 deletions
@ -1,97 +0,0 @@ |
|||
import java.util.HashMap; |
|||
import java.util.Map; |
|||
|
|||
public class Cache<K, V> { |
|||
private Map<K, CacheEntry> cacheMap; |
|||
|
|||
public Cache() { |
|||
cacheMap = new HashMap<>(); |
|||
} |
|||
|
|||
public void put(K key, V value) { |
|||
cacheMap.put(key, new CacheEntry(value)); |
|||
} |
|||
|
|||
public void put(K key, V value, long expireTimeMs) { |
|||
cacheMap.put(key, new CacheEntry(value, expireTimeMs)); |
|||
} |
|||
|
|||
public V get(K key) { |
|||
CacheEntry entry = cacheMap.get(key); |
|||
if (entry == null) { |
|||
return null; |
|||
} |
|||
if (entry.isExpired()) { |
|||
cacheMap.remove(key); |
|||
return null; |
|||
} |
|||
entry.updateAccessTime(); |
|||
return entry.getValue(); |
|||
} |
|||
|
|||
public boolean containsKey(K key) { |
|||
CacheEntry entry = cacheMap.get(key); |
|||
if (entry == null) { |
|||
return false; |
|||
} |
|||
if (entry.isExpired()) { |
|||
cacheMap.remove(key); |
|||
return false; |
|||
} |
|||
return true; |
|||
} |
|||
|
|||
public V remove(K key) { |
|||
CacheEntry entry = cacheMap.remove(key); |
|||
return entry != null ? entry.getValue() : null; |
|||
} |
|||
|
|||
public int size() { |
|||
return cacheMap.size(); |
|||
} |
|||
|
|||
public void clear() { |
|||
cacheMap.clear(); |
|||
} |
|||
|
|||
private class CacheEntry { |
|||
private V value; |
|||
private long createTime; |
|||
private long accessTime; |
|||
private long expireTimeMs; |
|||
|
|||
public CacheEntry(V value) { |
|||
this(value, -1); |
|||
} |
|||
|
|||
public CacheEntry(V value, long expireTimeMs) { |
|||
this.value = value; |
|||
this.expireTimeMs = expireTimeMs; |
|||
this.createTime = System.currentTimeMillis(); |
|||
this.accessTime = this.createTime; |
|||
} |
|||
|
|||
public V getValue() { |
|||
return value; |
|||
} |
|||
|
|||
public void updateAccessTime() { |
|||
this.accessTime = System.currentTimeMillis(); |
|||
} |
|||
|
|||
public boolean isExpired() { |
|||
if (expireTimeMs <= 0) { |
|||
return false; |
|||
} |
|||
return System.currentTimeMillis() > createTime + expireTimeMs; |
|||
} |
|||
|
|||
public long getCreateTime() { |
|||
return createTime; |
|||
} |
|||
|
|||
public long getAccessTime() { |
|||
return accessTime; |
|||
} |
|||
} |
|||
} |
|||
@ -1,70 +0,0 @@ |
|||
AI协同学习:Java泛型 |
|||
|
|||
1. 泛型擦除后如何通过反射获取泛型信息? |
|||
|
|||
Java泛型擦除后,泛型类型信息会被擦除为它们的边界或Object。但在某些情况下(如继承泛型类或实现泛型接口),可以通过反射获取泛型信息的Type。 |
|||
|
|||
关键API: |
|||
- Class.getGenericSuperclass() - 获取带泛型的父类 |
|||
- Method.getGenericReturnType() - 获取方法返回值的泛型类型 |
|||
- ParameterizedType.getActualTypeArguments() - 获取泛型参数的实际类型 |
|||
|
|||
示例代码: |
|||
```java |
|||
import java.lang.reflect.*; |
|||
import java.util.*; |
|||
|
|||
// 方法1:通过子类获取泛型父类的Type |
|||
class StringList extends ArrayList<String> {} |
|||
Type parentType = StringList.class.getGenericSuperclass(); |
|||
// parentType = java.util.ArrayList<java.lang.String> |
|||
|
|||
if (parentType instanceof ParameterizedType) { |
|||
ParameterizedType pt = (ParameterizedType) parentType; |
|||
Type[] typeArgs = pt.getActualTypeArguments(); |
|||
for (Type typeArg : typeArgs) { |
|||
System.out.println("Type arg: " + typeArg); // java.lang.String |
|||
} |
|||
} |
|||
|
|||
// 方法2:通过方法返回值获取泛型信息 |
|||
Method method = GenericReflection.class.getMethod("getCache"); |
|||
Type returnType = method.getGenericReturnType(); |
|||
if (returnType instanceof ParameterizedType) { |
|||
ParameterizedType pt = (ParameterizedType) returnType; |
|||
System.out.println("Return type args: " + Arrays.toString(pt.getActualTypeArguments())); |
|||
} |
|||
``` |
|||
|
|||
|
|||
2. Cache 代码审查 |
|||
|
|||
Cache 实现分析: |
|||
|
|||
优点: |
|||
- 使用了合理的缓存数据结构 |
|||
- 实现了过期机制 |
|||
- 包含 containsKey、remove、clear 等完整API |
|||
- 内部类 CacheEntry 封装良好 |
|||
|
|||
问题和建议: |
|||
1. 线程不安全 - 如果多线程并发访问会有问题,建议添加同步或使用 ConcurrentHashMap |
|||
2. 泛型信息丢失 - CacheEntry 中保存了 V value,但由于类型擦除,无法在运行时获取 V 的具体类型 |
|||
3. remove 方法在并发场景下可能有空指针问题 |
|||
|
|||
|
|||
思考题:为什么Java泛型不支持基本类型? |
|||
|
|||
核心原因:历史兼容性和类型系统设计 |
|||
|
|||
1. 类型擦除机制 - Java泛型在运行时会被擦除为 Object。基本类型(如 int、long)不是对象,不能赋值给 Object,所以无法进行类型擦除。 |
|||
|
|||
编译后变成: |
|||
ArrayList<int> → ArrayList<Object> // int不是Object |
|||
ArrayList<Integer> → ArrayList<Object> // Integer是Object |
|||
|
|||
2. 自动装箱的性能开销 - 虽然有 int ↔ Integer 自动装箱,但这会带来额外的性能开销。Java设计者选择不让泛型支持基本类型,以保持性能。 |
|||
|
|||
3. 向后兼容性 - Java 1.5 才引入泛型,为了兼容旧代码(没有泛型时 ArrayList 可以存任何对象),选择用类型擦除实现。 |
|||
|
|||
简单记忆:Java泛型本质是"伪泛型",它只在编译期提供类型检查,运行时没有泛型信息。基本类型不是对象,无法参与类型擦除。 |
|||
@ -1,37 +0,0 @@ |
|||
public class Pair<K, V> { |
|||
private K key; |
|||
private V value; |
|||
|
|||
public Pair(K key, V value) { |
|||
this.key = key; |
|||
this.value = value; |
|||
} |
|||
|
|||
public K getKey() { |
|||
return key; |
|||
} |
|||
|
|||
public void setKey(K key) { |
|||
this.key = key; |
|||
} |
|||
|
|||
public V getValue() { |
|||
return value; |
|||
} |
|||
|
|||
public void setValue(V value) { |
|||
this.value = value; |
|||
} |
|||
|
|||
public Pair<V, K> swap() { |
|||
return new Pair<>(value, key); |
|||
} |
|||
|
|||
@Override |
|||
public String toString() { |
|||
return "Pair{" + |
|||
"key=" + key + |
|||
", value=" + value + |
|||
'}'; |
|||
} |
|||
} |
|||
Loading…
Reference in new issue