前言
泛型(Generics),从字面的意思理解就是泛化的类型,即参数化类型。
我们都知道,泛型是JDK5提供的一个非常重要的新特性,它有非常多优秀的品质:能够把很多问题从运行期提前到编译器,从而使得程序更加的健壮。
但是因为Java5要保持良好的向下兼容性,所以从推出之际一直到现在,它都是个假东西:只在编译期存在,编译成.class文件后就不存在了,这就是所谓的泛型擦除。
对比下面两个类,一个是普通类,一个是泛型类:
class Generics { Object k; Object v; public Generics(Object k, Object v) { this.k = k; this.v = v; } } class Generics<K, V> { K k; V v; public Generics(K k, V v) { this.k = k; this.v = v; } }
泛型类的声明一般放在类名之后,可以有多个泛型参数,用尖括号括起来形成类型参数列表。
public interface Generator<T> { public T next(); }
这种泛型接口设计,是声明的是一个工厂设计模式常用的生成器接口。比如我们常见的迭代器接口Iterable
就是这样一个接口
public interface Iterable<T> { Iterator<T> iterator(); }
分为实例泛型方法和静态泛型方法。
public <T> T genericMethod(T t){ return t; } // 注意静态方法<T>必须是在static的后面~ public static <T> T genericStaticMethod(T t){ return t; }
这里需要稍微注意一下:
public class Main<T> { // 静态方法不能直接使用类的泛型参数T 而需要自己声明的 // 形如这样书写才正确:public static <T> T genericStaticMethod(T t) { ... } public static T genericStaticMethod(T t) { return t; } // 实例方法可以直接使用类声明的泛型参数 public T genericMethod(T t) { return t; } }
静态方法使用泛型参数需要自己单独声明,否则编译报错。
泛型方法的声明和泛型类的声明略有不同,它是在返回类型之前用尖括号列出类型参数列表(也可以有多个泛型类型),而函数传入的形参类型可以利用泛型来表示。
public class Main { public static void main(String[] args) { List<String> c1 = new ArrayList<>(); List<Integer> c2 = new ArrayList<>(); Class<? extends List> class1 = c1.getClass(); Class<? extends List> class2 = c2.getClass(); System.out.println(class1 == class2); } }
输出结果为:true
其实这里可能有不少小伙伴不能理解了,泛型中明明给它传的类型是不一样的,为何Class还是一样的呢???这里就要说到Java语言实现泛型所独有的——泛型擦除。
本例说明了:当我们声明List<String>和List<Integer>时,在运行时实际上是相同的,都是List,而具体的类型参数信息String和Integer被擦除了。
<? super T>
和<? extends T>
和<?>
原文:https://www.cnblogs.com/deityjian/p/11370166.html