我的好友们, 希望当你们看到我的无知的时候, 将我的懵懂愚昧知无不言的, 或通过结构化知识, 或通过零碎的忠告告诉我. 让我能斧正自己错误的观念以及逻辑. 我想你们的点拨, 也许才是我未来三年成长的开始.
类定义:
public class GenericType<T> {
}
public interface CommonType {
<K, V> V getItem(K t);
}
public class Food {
}
public class Fruit extends Food {
}
public class Apple extends Fruit {
}
public class Orange extends Fruit {
}
范型不能用作 instanceof:
为什么呢?
我也不知道为什么编译器要特别的强调这个. 如果 List<? extends Fruit> 这种写法不代表新定义的数据类型, 降级为 List 判断不可以吗?
请拯救我于黑暗之中吧.
if (fruits instanceof List<? extends Fruit>) {
// Error1: Illegal generic type for instanceof
}
if (fruits instanceof List<Fruit>) { // Error: 同 Error1
}
if (fruits instanceof List) {
}
通配符 ‘?’ 不能作用于类上:
为什么呢?
请拯救我于黑暗之中吧.
public class GenericType<? extends Food> { // Error: Unexpected wildcard
}
范型的使用范围:
作用于类上(循环范型):
注意这里的循环范型, 用在从父类返回子类类型很好用
public class GenericType<T extends GenericType<T>> {
private T t;
public void setData(T t) {
this.t = t;
}
public T getData() {
return t;
}
}
作用于函数:
public interface CommonType {
<K, V> V getItem(K t);
}
作用于属性:
List<? extends Fruit> fruits = new ArrayList<Apple>();
范型转型归纳:
- 不能将涉及 TypeA 的范型赋值给涉及 TypeB 的范型.
List<Fruit> fruits = new ArrayList<Apple>(); // Error: 不能向上转型
- 容易混淆的异常: 对于"? extends Class" 的形式: 可以向上转型
正因为这里可以向上转型, 所以造成了对 fruits 中的 add 方法, 无法判断其范型的具体类型.
核心在于右侧实例的类型, 要能确定右侧实例的范型类型下限, 才知道添加哪些类是安全的.
(PS: add 方法在编译期间, 可以看成 “add(? extends Fruit))”
List<? extends Fruit> fruits = new ArrayList<Apple>();
fruits.add(new Food());// Error: 不能向上转型, 如果说确定了 Fruit 为上界
// 因此 List<? extends Fruit> 接收的实例, 你很难说他到底接收的是什么类型.
// 我们假设存在一种运行时检查机制, 可以判断出实例对象的范型.
// 那么 fruits.add(new xx()) 就都存在类型转换的运行时异常.
fruits.add(new Fruit());// Error: 不能向上转型
fruits.add(new Apple()); // Error: 不能向上转型
// Required type: capture of ? extends Fruit
// Provided: Apple
- 容易混淆的异常: 对于"? super Class" 的形式: 可以向上转型
List<? super Fruit> fruits = new ArrayList<Fruit>();
fruits.add(new Food());// Error: 确定了 Fruit 为下界
// 因此 List<? super Fruit> 接收的实例, 至少可以接受 Fruit
// 因此可以添加 Fruit 以及 Fruit 的子类.
fruits.add(new Fruit());
fruits.add(new Apple());
- 很符合逻辑的类型转换异常.
public class MyMain {
public static void main(String[] args) {
extendsGeneric(new GenericType<Fruit>());
extendsGeneric(new GenericType<Food>()); // Error: Food 不是 Fruit 的子类.
extendsGeneric(new GenericType<Apple>());
}
private static <T> void extendsGeneric(GenericType<? extends Fruit> foods) {
}
}
public class MyMain {
public static void main(String[] args) {
superGeneric(new GenericType<Food>());
superGeneric(new GenericType<Fruit>());
superGeneric(new GenericType<Apple>()); // Error: Apple 不是 Fruit 的父类
}
private static <T> void superGeneric(GenericType<? super Fruit> fruits) {
}
}
使用反射实现无类别函数传递:
嗯... 我也没机会写框架. 那很难.
范型擦除后, 在运行时期还可以获取到范型类型吗, 为什么能拿到呢?
范型擦除后通过 Signature 保留住了范型的信息. 但是方法签名以及方法体中的的范型信息已经被擦除.
希望好心人能指导 Signature 相关的逻辑.
public class MyMain {
private static class MyGenericeType extends GenericType<Integer, Food> {
}
public static void main(String[] args) {
MyGenericeType myGenericeType = new MyGenericeType();
Class myGenericeTypeClass = myGenericeType.getClass();
System.out.println("myGenericeType class: " + myGenericeTypeClass);
System.out.println("myGenericeType getSuperclass: " + myGenericeTypeClass.getSuperclass());
Type type = myGenericeTypeClass.getGenericSuperclass();
System.out.println("myGenericeType getGenericSuperclass: " + type);
Type[] types = ((ParameterizedType) type).getActualTypeArguments();
System.out.println("myGenericeType Type.getActualTypeArguments: " + types.length);
for (int i = 0; i < types.length; i++) {
System.out.println("types[" + i + "] " + types[i] + " " + ((Class)types[i]).getCanonicalName());
}
Method[] methods = myGenericeType.getClass().getMethods();
for (int i = 0; i < methods.length; i++) {
if (methods[i].getName().contains("setData") || methods[i].getName().contains("getData")) {
System.out.println(methods[i]);
}
}
}
// 1. myGenericeType.getClass(): class com.moon_rock.javalib.MyMain$MyGenericeType
// 2. myGenericeType.getSuperclass(): class com.moon_rock.javalib.generic.GenericType
// 3. 通过 getGenericSuperclass() 返回的是: sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl
// myGenericeType.getGenericSuperclass(): com.moon_rock.javalib.generic.GenericType<java.lang.Integer, com.moon_rock.javalib.bean.Food>
// 4. myGenericeType Type.getActualTypeArguments length: 2
// getActualTypeArguments 返回的数组中, 数组元素的类型: types[0] instanceof Class: true
// types[0] class java.lang.Integer java.lang.Integer
// types[1] class com.moon_rock.javalib.bean.Food com.moon_rock.javalib.bean.Food
// 5. 下面为范型擦除
// public void com.moon_rock.javalib.generic.GenericType.setData(java.lang.Object)
// public java.lang.Object com.moon_rock.javalib.generic.GenericType.getData()
// 下面为范型擦除
public class MyMain {
public static void main(String[] args) {
methods = CommonType.class.getMethods();
for (int i = 0; i < methods.length; i++) {
System.out.println(methods[i]);
}
}
}
// public abstract java.lang.Object com.moon_rock.javalib.generic.CommonType.getItem(java.lang.Object)