更广泛更统一
Java泛型的目的:
通用性,可应用于多种类型,而不是一个具体的接口或类。 又为了保证唯一性,即容器的唯一类型
JAVA1.5的补充。
用来指定容器要持有什么类型的对象,而且由编译器来保证类型的正确性。
Java泛型的核心概念:
告诉编译器想使用什么类型,然后编译器帮你处理一切细节。
Java 泛型的局限性:
1,不能使用基本类型作为类型参数。
(只有当你希望使用的类型参数比某个具体类型以及它的所有子类型更加“泛化”时, 也就是说,当你希望代码能够跨多个类工作时,使用泛型才有所帮助。)
Java泛型方法 :
能使用泛型方法,尽量使用泛型方法。
static的方法,不能访问泛型类的类型参数。
定义泛型方法:将泛型参数列表定义在返回值之前
public static <T> void test() {
}
(使用泛型类时,必须在创建对象时指定类型参数的值,使用泛型方法时,通常不必指明参数类型,因为编译器会为为们找出具体的类型。这称为类型参数推断。)
具体实现时,编译器无法推断类型如
List<Person> list = new ArrayList<Person>();
调用泛型方法,显示的类型说明,在.操作符与方法名之间插入类型
new Generator().<SubOrder>test(new SubOrder());
擦除
在泛型代码内部,无法获得任何有关泛型参数类型的信息。
Class clazz1 = new ArrayList<Integer>().getClass();
Class clazz2 = new ArrayList<String>().getClass();
System.out.println(clazz1.equals(clazz2)); // true
Java泛型是使用擦除来实现的,任何具体的类型信息都被擦除了,唯一知道的就是你在使用一个对象。
因此,List<String> 和 List<Integer> 在运行时事实上是相同的类型 .这两种形式都被擦除成他们的"原生"类型,即List。
泛型类型参数将擦除到它的第一个边界,(编译器实际上会把类型参数替换为它的擦除)
由于擦除的特性,所以我们必须协助泛型类, 给定泛型类的边界, extends super
擦除的目的是为了迁移兼容性。
擦除不是一个语言的特性,它是java的泛型实现的一种折中, 因为泛型不是java语言出现时就有的组成部分,所以这种这种是必须的。
擦除减少了泛型的泛化性。
***泛型类型只有在静态类型检查期间才出现,在此之后,程序重的所有泛型类型都将被擦除,替换为他们的非泛型上界。如 List<T> 将被擦除为List 而普通的类型变量在未指定边界的情况下被擦除为Object 。
擦出的核心动机,是它使得泛化的客户端可以用非泛化的类库来使用。(迁移兼容性)
允许非泛型代码与泛型代码共存,擦除使得这种向着泛型的迁移成为可能。
因为擦除在方法体重移除了类型信息,所以在运行时的问题就是边界,即对象进入和离开方法的地点,这些正是编译器在编译期执行类型检查并插入转型代码的地点。
边界就是发生动作的地方。
边界
因为擦除移除了类型信息,所以,可以用无界泛型参数调用的方法只是那些可以用Object调用的方法。
永远记住 泛型是为了保持容器的统一类型。 用java的思想去思考,而不是字面的意思去思考。 ,不要试图去记,要理解,站在语言的角度去理解。
List<? extends Fruit> list0 = new ArrayList<Fruit>();
//list0.add(new Apple()); compile error // 之所以不能add ,是因为有很多个Fruit的子类,不能保证统一
List<? super Apple> list = new ArrayList<Fruit>();// 和 Apple 和 Apple的父类
list.add(new Apple());
//list.add(new Fruit());compile error // 这里不能add 父类,是因为apple可能有很多个父类,同样不能保证统一
list.add(new SApple());// 多态
List
List<?>
List<Object>
List<? extends Object>
static void test0(List list) {
list.add(2);
}
static void test1(List<?> list) {
list.add(2);
list.add(null);
}
static void test2(List<Object> list) {
list.add(2);
}
static void test3(List<? extends Object> list) {
list.add();
}
泛型的通用语言特性的目的在于可表达性,而不仅仅是为了创建类型安全的容器。类型安全的容器是能够创建更通用代码的这一能力所带来的副作用。