Browse Source

上传文件至 'w8'

========== 问题回答 ==========

问题一: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
Zhuhuairui 4 weeks ago
parent
commit
4c5c6e8e5b
  1. 83
      w8/Cache.java
  2. 33
      w8/CacheTest.java
  3. 54
      w8/GenericReflection.java
  4. 37
      w8/Pair.java
  5. 20
      w8/PairTest.java

83
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<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 +
'}';
}
}

33
w8/CacheTest.java

@ -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));
}
}

54
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<String, String> {
public StringCache() {
super(10);
}
}

37
w8/Pair.java

@ -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 +
'}';
}
}

20
w8/PairTest.java

@ -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…
Cancel
Save