Browse Source
========== 问题回答 ==========
问题一: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<int, String> 是不允许的,但 Cache<Integer, String> 是可以的。
main
5 changed files with 227 additions and 0 deletions
@ -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<K, V> { |
||||
|
private final int capacity; |
||||
|
private final Map<K, V> 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<K> 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<K>) typeArgs[0]; |
||||
|
} |
||||
|
} |
||||
|
return null; |
||||
|
} |
||||
|
|
||||
|
@SuppressWarnings("unchecked") |
||||
|
public Class<V> 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<V>) typeArgs[1]; |
||||
|
} |
||||
|
} |
||||
|
return null; |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public String toString() { |
||||
|
return "Cache{" + |
||||
|
"capacity=" + capacity + |
||||
|
", cache=" + cache + |
||||
|
'}'; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,33 @@ |
|||||
|
public class CacheTest { |
||||
|
public static void main(String[] args) { |
||||
|
System.out.println("========== Cache<K,V> 测试 =========="); |
||||
|
|
||||
|
Cache<String, String> 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<String, Integer> 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<Integer, Double> 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)); |
||||
|
} |
||||
|
} |
||||
@ -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<String, String> { |
||||
|
public StringCache() { |
||||
|
super(10); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,37 @@ |
|||||
|
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 V getValue() { |
||||
|
return value; |
||||
|
} |
||||
|
|
||||
|
public void setKey(K key) { |
||||
|
this.key = key; |
||||
|
} |
||||
|
|
||||
|
public void setValue(V value) { |
||||
|
this.value = value; |
||||
|
} |
||||
|
|
||||
|
public Pair<V, K> swap() { |
||||
|
return new Pair<>(this.value, this.key); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public String toString() { |
||||
|
return "Pair{" + |
||||
|
"key=" + key + |
||||
|
", value=" + value + |
||||
|
'}'; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,20 @@ |
|||||
|
public class PairTest { |
||||
|
public static void main(String[] args) { |
||||
|
System.out.println("========== Pair<K,V> 测试 =========="); |
||||
|
|
||||
|
Pair<String, Integer> pair1 = new Pair<>("apple", 1); |
||||
|
System.out.println("原始 Pair: " + pair1); |
||||
|
|
||||
|
Pair<Integer, String> swappedPair = pair1.swap(); |
||||
|
System.out.println("交换后 Pair: " + swappedPair); |
||||
|
|
||||
|
Pair<Double, String> pair2 = new Pair<>(3.14, "PI"); |
||||
|
System.out.println("原始 Pair: " + pair2); |
||||
|
|
||||
|
Pair<String, Double> swappedPair2 = pair2.swap(); |
||||
|
System.out.println("交换后 Pair: " + swappedPair2); |
||||
|
|
||||
|
System.out.println("\n交换方法的键值类型: " + |
||||
|
"Pair<Double,String> -> Pair<String,Double> 成功!"); |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue