湖畔镇

Java——泛型

泛型是指参数化类型的能力,定义带泛型类型的类或方法,随后编译器会使用具体类型来替换他
主要优点是在编译期而不是运行时检测出错误

泛型类和接口

public class Stack<T> {
    private List<T> list = new ArrayList<T>();

    public void push(T o) {
        list.add(o);
    }

    public T pop() {
        T o = list.get(list.size() - 1);
        list.remove(list.size() - 1);
        return o;
    }
}

泛型方法

public static <T> void print()

可以将泛型指定为另一种类型的子类型,被称为受限的

public static <T extends GeometricObject> boolean equalArea(T object1, T object2) {
    reutrn object1.getArea() == object2.getArea();
}

原始类型和向后兼容

可以使用泛型类而不指定具体类型,称为原始类型,这是不安全的

Stack stack = new Stack();

通配泛型

public static void main(String[] args) {
    Stack<Integer> stack = new Stack<Integer>();
    max(stack);
}

public static double max(Stack<Number> stack) {
    ...
}

尽管IntegerNumber的子类型,但Stack<Integer>不是Stack<Number>的子类型,为避免这个问题,可以使用通配泛型类型

有三种形式:

  • ?
    非受限通配,和? extends Object是一样的
  • ? extends T
    受限通配,表示T或T的一个未知子类型
  • ? super T
    下限通配,表示T或T的一个未知父类型

使用下面的语句可以修复上面的错误:

public static double max(Stack<? extends Number> stack) {
    ...
}

消除泛型和对泛型的限制

泛型使用一种称为类型消除的方法来实现,编译器使用泛型类型信息来编译代码,泛型存在于编译时,一旦编译器确认泛型类型是安全使用的,随后会翻译成原始类型

不管实际的具体类型是什么,泛型类是被它所有实例共享的

ArrayList<String> list1 = new ArrayList<String>();
ArrayList<Integer> list2 = new ArrayList<Integer>();

编译时是两种类型,但是运行时只有一个ArrayList类被加载到JVM中,list1和list2都是ArrayList的实例

泛型在运行时会被消除,所以使用上是有限制的:

  1. 不能使用new T(),运行时泛型类型不可用
  2. 不能使用new T[]

    T[] arrays = new T[10];
    

    可以使用类型转换方法来规避限制

    T[] arrays = (T[]) new Object[10];
    
  3. 不能使用泛型类创建泛型数组

    ArrayList<String>[] list = new ArrayList<String>[10];
    

    可以使用类型转换方法来规避限制

    ArrayList<String>[] list = (ArrayList<String[]) new ArrayList[10]
    

    2和3都将会的一个编译警告

  4. 在静态环境下不允许类的参数是泛型类型

    public class Test<T> {
        public static void m(T o1) {
    
        }
    
        public static T o1;
    
        static {
            T o2;
        }
    }
    
  5. 异常类型不能是泛型的

基本类型无法做为类型参数,但是有自动打包和自动拆包的功能,可以方便的在基本类型和对应包装类型之间转换

可以在类中包含泛型方法,而这个类可以是泛型类,也可以不是泛型类,尽量只使用泛型方法,而不是将整个类泛型化

对于static方法而言,无法访问泛型类的类型参数,如果static方法需要使用泛型能力,必须使其成为泛型方法

JAVA的泛型和其他语言比起来很弱

分享