From 4c5c6e8e5ba1484d2aacf27e33b47cc9ce3405cb Mon Sep 17 00:00:00 2001 From: Zhuhuairui <3180158655@qq.com> Date: Wed, 20 May 2026 18:55:19 +0800 Subject: [PATCH] =?UTF-8?q?=E4=B8=8A=E4=BC=A0=E6=96=87=E4=BB=B6=E8=87=B3?= =?UTF-8?q?=20'w8'?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ========== 问题回答 ========== 问题一:Java泛型擦除后如何通过反射获取泛型信息? 答: Java的泛型擦除指的是在编译时,泛型类型信息会被擦除,替换为它们的上限类型(通常是Object), 以保证与Java 1.5之前的代码兼容。然而,反射API仍然提供了一些方法来在运行时获取泛型信息: 1. 通过ParameterizedType接口: - 使用 Class.getGenericSuperclass() 获取父类的泛型类型 - 使用 Field.getGenericType() 获取字段的泛型类型 - 这些方法返回ParameterizedType类型,可以调用 getActualTypeArguments() 获取具体类型参数 2. 示例: ```java Type type = MyClass.class.getGenericSuperclass(); if (type instanceof ParameterizedType) { ParameterizedType pt = (ParameterizedType) type; Type[] args = pt.getActualTypeArguments(); Class keyType = (Class) args[0]; // 获取K Class valueType = (Class) args[1]; // 获取V } ``` 3. 注意事项: - 只有继承泛型类或实现泛型接口的子类才能获取到泛型信息 - 泛型数组类型可以通过 getGenericSuperclass() 获取 - 擦除后的原始类型信息可以通过 Class.getTypeParameters() 获取泛型参数声明 问题二:为什么Java泛型不支持基本类型? 答: Java泛型不支持基本类型(如int、double、char等),主要有以下原因: 1. 历史兼容性问题: - Java泛型是Java 1.5才引入的,为了向后兼容,泛型采用"类型擦除"实现 - 如果允许基本类型作为泛型参数,需要修改JVM字节码指令,工作量巨大 2. JVM对象模型限制: - JVM中的泛型类型参数期望的是对象引用,而不是基本类型值 - 基本类型在JVM中存储在栈中,而对象存储在堆中 3. 类型擦除的实现机制: - 擦除后泛型被替换为Object,而Object只能存储引用类型 - 基本类型无法直接赋值给Object引用 4. 性能考量: - 如果支持int这样的基本类型,泛型需要自动装箱为Integer - 这会增加额外的装箱/拆箱开销 5. 替代方案: - 使用包装类(如Integer、Double)代替基本类型 - Java 1.5之后提供了自动装箱功能,简化了基本类型与包装类之间的转换 例如,Cache 是不允许的,但 Cache 是可以的。 --- w8/Cache.java | 83 +++++++++++++++++++++++++++++++++++++++ w8/CacheTest.java | 33 ++++++++++++++++ w8/GenericReflection.java | 54 +++++++++++++++++++++++++ w8/Pair.java | 37 +++++++++++++++++ w8/PairTest.java | 20 ++++++++++ 5 files changed, 227 insertions(+) create mode 100644 w8/Cache.java create mode 100644 w8/CacheTest.java create mode 100644 w8/GenericReflection.java create mode 100644 w8/Pair.java create mode 100644 w8/PairTest.java diff --git a/w8/Cache.java b/w8/Cache.java new file mode 100644 index 0000000..0ca78fb --- /dev/null +++ b/w8/Cache.java @@ -0,0 +1,83 @@ +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.util.HashMap; +import java.util.Map; + +public class Cache { + private final int capacity; + private final Map cache; + + public Cache(int capacity) { + this.capacity = capacity; + this.cache = new HashMap<>(); + } + + public void put(K key, V value) { + if (key == null) { + return; + } + if (cache.size() >= capacity && !cache.containsKey(key)) { + K oldestKey = cache.keySet().iterator().next(); + cache.remove(oldestKey); + } + cache.put(key, value); + } + + public V get(K key) { + return cache.get(key); + } + + public void remove(K key) { + cache.remove(key); + } + + public void clear() { + cache.clear(); + } + + public int getCapacity() { + return capacity; + } + + public int getSize() { + return cache.size(); + } + + public boolean containsKey(K key) { + return cache.containsKey(key); + } + + @SuppressWarnings("unchecked") + public Class getKeyType() { + Type type = getClass().getGenericSuperclass(); + if (type instanceof ParameterizedType) { + ParameterizedType paramType = (ParameterizedType) type; + Type[] typeArgs = paramType.getActualTypeArguments(); + if (typeArgs != null && typeArgs.length > 0 && typeArgs[0] instanceof Class) { + return (Class) typeArgs[0]; + } + } + return null; + } + + @SuppressWarnings("unchecked") + public Class getValueType() { + Type type = getClass().getGenericSuperclass(); + if (type instanceof ParameterizedType) { + ParameterizedType paramType = (ParameterizedType) type; + Type[] typeArgs = paramType.getActualTypeArguments(); + if (typeArgs != null && typeArgs.length > 1 && typeArgs[1] instanceof Class) { + return (Class) typeArgs[1]; + } + } + return null; + } + + @Override + public String toString() { + return "Cache{" + + "capacity=" + capacity + + ", cache=" + cache + + '}'; + } +} \ No newline at end of file diff --git a/w8/CacheTest.java b/w8/CacheTest.java new file mode 100644 index 0000000..5d86e03 --- /dev/null +++ b/w8/CacheTest.java @@ -0,0 +1,33 @@ +public class CacheTest { + public static void main(String[] args) { + System.out.println("========== Cache 测试 =========="); + + Cache cache1 = new Cache<>(3); + cache1.put("name", "Alice"); + cache1.put("age", "20"); + cache1.put("city", "Beijing"); + System.out.println("Cache(容量3)添加3个元素: " + cache1); + + cache1.put("country", "China"); + System.out.println("Cache(容量3)添加第4个元素: " + cache1); + + System.out.println("获取name: " + cache1.get("name")); + System.out.println("删除age后: "); + cache1.remove("age"); + System.out.println(cache1); + + Cache cache2 = new Cache<>(2); + cache2.put("a", 1); + cache2.put("b", 2); + cache2.put("c", 3); + System.out.println("\nCache(容量2)添加3个元素(触发LRU淘汰): " + cache2); + + Cache cache3 = new Cache<>(4); + cache3.put(1, 1.1); + cache3.put(2, 2.2); + System.out.println("\nCache(容量4)添加2个元素: " + cache3); + + System.out.println("\n测试包含键: " + cache3.containsKey(1)); + System.out.println("测试不包含键: " + cache3.containsKey(5)); + } +} \ No newline at end of file diff --git a/w8/GenericReflection.java b/w8/GenericReflection.java new file mode 100644 index 0000000..709c193 --- /dev/null +++ b/w8/GenericReflection.java @@ -0,0 +1,54 @@ +import java.lang.reflect.Field; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.util.Map; + +public class GenericReflection { + public static void main(String[] args) { + System.out.println("========== Java泛型擦除后通过反射获取泛型信息 ==========\n"); + + System.out.println("1. 获取字段的泛型类型:"); + try { + Field mapField = Cache.class.getDeclaredField("cache"); + System.out.println(" 字段名: " + mapField.getName()); + System.out.println(" 原始类型: " + mapField.getType()); + + Type genericType = mapField.getGenericType(); + if (genericType instanceof ParameterizedType) { + ParameterizedType pt = (ParameterizedType) genericType; + System.out.println(" 参数化类型: " + pt.getTypeName()); + System.out.println(" 泛型参数[0]: " + pt.getActualTypeArguments()[0]); + System.out.println(" 泛型参数[1]: " + pt.getActualTypeArguments()[1]); + } + } catch (NoSuchFieldException e) { + e.printStackTrace(); + } + + System.out.println("\n2. 获取子类的泛型类型(通过ParameterizedType):"); + StringCache cache = new StringCache(); + cache.put("test", "value"); + + Type superType = cache.getClass().getGenericSuperclass(); + if (superType instanceof ParameterizedType) { + ParameterizedType pt = (ParameterizedType) superType; + System.out.println(" 父类类型: " + pt.getTypeName()); + System.out.println(" K类型: " + pt.getActualTypeArguments()[0]); + System.out.println(" V类型: " + pt.getActualTypeArguments()[1]); + } + + System.out.println("\n3. 总结:"); + System.out.println(" - 泛型信息在编译时被擦除到上限类型(Object或指定上限)"); + System.out.println(" - 通过反射可以在运行时获取以下泛型信息:"); + System.out.println(" * Field.getGenericType() 获取字段的泛型类型"); + System.out.println(" * Method.getGenericParameterTypes() 获取方法参数的泛型类型"); + System.out.println(" * Method.getGenericReturnType() 获取方法返回值的泛型类型"); + System.out.println(" * Class.getGenericSuperclass() 获取父类的泛型类型"); + System.out.println(" - 子类继承泛型类时,泛型信息会保留在子类的Class对象中"); + } +} + +class StringCache extends Cache { + public StringCache() { + super(10); + } +} \ No newline at end of file diff --git a/w8/Pair.java b/w8/Pair.java new file mode 100644 index 0000000..3c1b7ea --- /dev/null +++ b/w8/Pair.java @@ -0,0 +1,37 @@ +public class Pair { + private K key; + private V value; + + public Pair(K key, V value) { + this.key = key; + this.value = value; + } + + public K getKey() { + return key; + } + + public V getValue() { + return value; + } + + public void setKey(K key) { + this.key = key; + } + + public void setValue(V value) { + this.value = value; + } + + public Pair swap() { + return new Pair<>(this.value, this.key); + } + + @Override + public String toString() { + return "Pair{" + + "key=" + key + + ", value=" + value + + '}'; + } +} \ No newline at end of file diff --git a/w8/PairTest.java b/w8/PairTest.java new file mode 100644 index 0000000..e3148b1 --- /dev/null +++ b/w8/PairTest.java @@ -0,0 +1,20 @@ +public class PairTest { + public static void main(String[] args) { + System.out.println("========== Pair 测试 =========="); + + Pair pair1 = new Pair<>("apple", 1); + System.out.println("原始 Pair: " + pair1); + + Pair swappedPair = pair1.swap(); + System.out.println("交换后 Pair: " + swappedPair); + + Pair pair2 = new Pair<>(3.14, "PI"); + System.out.println("原始 Pair: " + pair2); + + Pair swappedPair2 = pair2.swap(); + System.out.println("交换后 Pair: " + swappedPair2); + + System.out.println("\n交换方法的键值类型: " + + "Pair -> Pair 成功!"); + } +} \ No newline at end of file