diff --git a/w8/AI.txt b/w8/AI.txt new file mode 100644 index 0000000..14c8dca --- /dev/null +++ b/w8/AI.txt @@ -0,0 +1,100 @@ +问题:Java泛型擦除后如何通过反射获取泛型信息? +答:虽然 Java 在编译时会进行类型擦除(Type Erasure),将泛型替换为原始类型(通常是 Object 或边界类型),但某些情况下泛型信息会被保留在字节码中,可以通过反射获取: + +1. 获取父类/接口的泛型参数 +Java +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.util.List; + +// 继承泛型类时指定具体类型 +public class StringList extends ArrayList {} + +public class GenericReflectionDemo { + public static void main(String[] args) { + // 获取父类的泛型参数 + Class clazz = StringList.class; + Type genericSuperclass = clazz.getGenericSuperclass(); + + if (genericSuperclass instanceof ParameterizedType) { + ParameterizedType pt = (ParameterizedType) genericSuperclass; + Type[] actualTypeArgs = pt.getActualTypeArguments(); + for (Type type : actualTypeArgs) { + System.out.println("泛型参数类型: " + type); + // 输出: class java.lang.String + } + } + } +} +2. 获取字段的泛型类型 +Java +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +public class GenericField { + private List names; + private Map mapping; +} + +// 获取字段泛型 +Field field = GenericField.class.getDeclaredField("names"); +Type genericType = field.getGenericType(); +if (genericType instanceof ParameterizedType) { + ParameterizedType pt = (ParameterizedType) genericType; + System.out.println("字段泛型参数: " + + Arrays.toString(pt.getActualTypeArguments())); + // 输出: [class java.lang.String] +} +3. 获取方法参数的泛型类型 +Java +1 +2 +3 +4 +public void process(List items, Map map) {} + +Method method = clazz.getMethod("process", List.class, Map.class); +Type[] paramTypes = method.getGenericParameterTypes(); +4. 核心 API 总结 +反射方法 用途 +getGenericSuperclass() 获取父类的泛型类型 +getGenericInterfaces() 获取接口的泛型类型 +Field.getGenericType() 获取字段的泛型类型 +Method.getGenericReturnType() 获取返回值的泛型类型 +Method.getGenericParameterTypes() 获取方法参数的泛型类型 +ParameterizedType.getActualTypeArguments() 获取实际泛型参数 +⚠️ 限制:局部变量和方法参数的泛型信息在运行时是完全擦除的,无法通过反射获取。 diff --git a/w8/Cache.java b/w8/Cache.java new file mode 100644 index 0000000..330a2c7 --- /dev/null +++ b/w8/Cache.java @@ -0,0 +1,155 @@ +import java.util.Map; +import java.util.HashMap; +import java.util.Set; +import java.util.Collection; +import java.util.Optional; +import java.util.HashSet; +import java.util.ArrayList; + +/** + * 泛型缓存类 Cache + * 提供简单的键值缓存机制(非线程安全) + * @param 键的类型 + * @param 值的类型 + */ +public class Cache { + private final Map cache; + private final int maxSize; + + // 统计信息 + private long hitCount = 0; + private long missCount = 0; + + /** + * 默认构造方法 - 无容量限制 + */ + public Cache() { + this(Integer.MAX_VALUE); + } + + /** + * 带容量限制的构造方法 + */ + public Cache(int maxSize) { + this.maxSize = maxSize; + this.cache = new HashMap<>(); + } + + /** + * 存入缓存 + */ + public void put(K key, V value) { + if (key == null) { + throw new IllegalArgumentException("Key cannot be null"); + } + if (cache.size() >= maxSize && !cache.containsKey(key)) { + throw new IllegalStateException("Cache is full, no eviction strategy implemented"); + } + cache.put(key, value); + } + + /** + * 从缓存获取 + */ + public V get(K key) { + if (cache.containsKey(key)) { + hitCount++; + return cache.get(key); + } else { + missCount++; + return null; + } + } + + /** + * 使用 Optional 包装返回值(更安全的API) + */ + public Optional getOptional(K key) { + return Optional.ofNullable(get(key)); + } + + /** + * 判断缓存中是否存在键 + */ + public boolean containsKey(K key) { + return cache.containsKey(key); + } + + /** + * 从缓存中移除 + */ + public V remove(K key) { + return cache.remove(key); + } + + /** + * 清空缓存 + */ + public void clear() { + cache.clear(); + hitCount = 0; + missCount = 0; + } + + /** + * 获取缓存大小 + */ + public int size() { + return cache.size(); + } + + /** + * 判断缓存是否为空 + */ + public boolean isEmpty() { + return cache.isEmpty(); + } + + /** + * 获取所有键 + */ + public Set keySet() { + return new HashSet<>(cache.keySet()); + } + + /** + * 获取所有值 + */ + public Collection values() { + return new ArrayList<>(cache.values()); + } + + /** + * 获取命中率 + */ + public double getHitRate() { + long total = hitCount + missCount; + return total == 0 ? 0.0 : (double) hitCount / total; + } + + /** + * 获取统计信息 + */ + public CacheStats getStats() { + return new CacheStats(hitCount, missCount, getHitRate()); + } + + // 统计信息内部类 + public static class CacheStats { + public final long hits; + public final long misses; + public final double hitRate; + + public CacheStats(long hits, long misses, double hitRate) { + this.hits = hits; + this.misses = misses; + this.hitRate = hitRate; + } + + @Override + public String toString() { + return String.format("CacheStats{hits=%d, misses=%d, hitRate=%.2f%%}", + hits, misses, hitRate * 100); + } + } +} \ No newline at end of file diff --git a/w8/CacheTest.java b/w8/CacheTest.java new file mode 100644 index 0000000..8b04cd2 --- /dev/null +++ b/w8/CacheTest.java @@ -0,0 +1,27 @@ +public class CacheTest { + public static void main(String[] args) { + // 创建缓存实例 + Cache ageCache = new Cache<>(100); + + // 存入数据 + ageCache.put("Alice", 25); + ageCache.put("Bob", 30); + ageCache.put("Charlie", 35); + + // 获取数据 + System.out.println("Alice's age: " + ageCache.get("Alice")); + + // 测试缓存未命中 + Integer davidAge = ageCache.get("David"); + System.out.println("David's age: " + davidAge); + + // 查看统计信息 + System.out.println(ageCache.getStats()); + + // 使用 Optional API + ageCache.getOptional("Eve").ifPresentOrElse( + age -> System.out.println("Found: " + age), + () -> System.out.println("Eve not found") + ); + } +} diff --git a/w8/Pair.java b/w8/Pair.java new file mode 100644 index 0000000..e1249fd --- /dev/null +++ b/w8/Pair.java @@ -0,0 +1,67 @@ +/** + * 泛型 Pair 类 - 用于存储键值对 + * @param 键的类型 + * @param 值的类型 + */ +public class Pair { + private K key; + private V value; + + // 构造方法 + public Pair(K key, V value) { + this.key = key; + this.value = value; + } + + // Getter 方法 + public K getKey() { + return key; + } + + public V getValue() { + return value; + } + + // Setter 方法 + public void setKey(K key) { + this.key = key; + } + + public void setValue(V value) { + this.value = value; + } + + /** + * swap 方法 - 交换当前 Pair 的 key 和 value + * 注意:只有当 K 和 V 类型相同时才能交换,否则返回新 Pair + */ + public Pair swap() { + return new Pair<>(value, key); + } + + /** + * 静态泛型方法 - 交换任意两个 Pair 对象 + */ + public static Pair swap(Pair pair) { + return new Pair<>(pair.getValue(), pair.getKey()); + } + + @Override + public String toString() { + return "Pair{" + "key=" + key + ", value=" + value + '}'; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null || getClass() != obj.getClass()) return false; + Pair pair = (Pair) obj; + return java.util.Objects.equals(key, pair.key) && + java.util.Objects.equals(value, pair.value); + } + + @Override + public int hashCode() { + return java.util.Objects.hash(key, value); + } +} diff --git a/w8/PairTest.java b/w8/PairTest.java new file mode 100644 index 0000000..f81268b --- /dev/null +++ b/w8/PairTest.java @@ -0,0 +1,20 @@ +public class PairTest { + public static void main(String[] args) { + // 测试整数-字符串 Pair + Pair pair1 = new Pair<>(1, "One"); + System.out.println("原 Pair: " + pair1); + + // 使用实例方法 swap + Pair swapped = pair1.swap(); + System.out.println("交换后: " + swapped); + + // 使用静态方法 swap + Pair swapped2 = Pair.swap(pair1); + System.out.println("静态交换: " + swapped2); + + // 测试相同类型的 Pair 交换 + Pair pair2 = new Pair<>("A", "B"); + Pair swappedSame = pair2.swap(); + System.out.println("同类型交换: " + swappedSame); + } +} \ No newline at end of file diff --git a/w8/QQ20260430-092036.png b/w8/QQ20260430-092036.png new file mode 100644 index 0000000..065e0bc Binary files /dev/null and b/w8/QQ20260430-092036.png differ diff --git a/w8/QQ20260430-092544.png b/w8/QQ20260430-092544.png new file mode 100644 index 0000000..074e5a3 Binary files /dev/null and b/w8/QQ20260430-092544.png differ