第15章_泛型:
0:优秀博客:https://www.cnblogs.com/fengmingyue/p/6087031.html
1:泛型的目的之一:用来指定容器要持有什么类型的对象,而且由编译器来保证类型的正确性。
2:泛型案例:
例1:“泛型类”
public class Holder<T>{ private T t; public Holder(T t){this.t = t;} public T getHolder(){return this.t;} }
3:使用泛型告诉编译器你想使用什么类型,然后由编译器处理细节,在类上定义的泛型,不能在今天方法中使用。
4:“元组”:将一组对象存储在一个对象中。通常元组具有任意长度,可以存储任意类型。(也叫做信使)
5:一段有意思的代码:
Class c1 = New ArrayList<String>().getClass(); Class c2 = New ArrayList<Integer>().getClass(); System.out.println(c1 == c2); //true
**这里需要注意:在泛型代码内部,无法获取任何有关泛型类型参数的信息。
6:java泛型是使用擦除来实现的。当你使用泛型时,任何具体的类型都被擦除了。
你唯一知道的是:你规范了一个类型。因此上面的ArrayList<String>和ArrayList<Integer>都被擦除成为了ArrayList类型。
泛型信息只存在于代码编译阶段,在进入 JVM 之前,与泛型相关的信息会被擦除掉,专业术语叫做类型擦除。
7:“边界”:类似<T extends HasF>这种重用了extends的泛型。它表示规范的类型是继承自HasF。
8:泛型在擦除时,将擦除到第一个边界(可能有多个边界),<T extends HasF>会擦除到HasF,这就像在类的声明中使用HasF代替了T一样。
9:泛型在java1.0中是没有的,由于之后要添加进去,所以使用了擦除这种折中的解决方案。
10:“泛型方法”:
例1: private static<T> void exchange(T[] arr, int i, int j) { T temp=arr[i]; arr[i]=arr[j]; arr[j]=temp; } 例2: public <T> T get(T[] ts) { return ts[ts.length / 2]; }
11:通配符“?”:
public static void fun(List<Object> list) {…} List<String> list1 = new ArrayList<String>(); List<Integer> list2 = new ArrayList<Integer>(); fun(list1);//编译不通过 fun(list2);//编译不通过
//上面的调用都是编译不通过的!这说明想写一个即可以打印list1,又可以打印list2的方法是不可能的!
public static void fun(List<?> list) {…} //如果这里不使用泛型会警告,使用通配符即可。
但是使用通配符后,不能确定要类型,相关方法不能使用,例如:list.add("字符串");编译不通过。
通配符有 3 种形式。
1、<?>
被称作无限定的通配符。
2、<? extends T>
被称作有上限的通配符。
3、<? super T>
被称作有下限的通配符。
12:基本类型不能写在泛型中(例如:ArrayList<int>)。
13:一个类不能同时实现一个泛型的两个变体。
例如:
Interface A<T>{} Class B implements A<B>{} Class C extends B implements A<C>{}
//由于擦除的原因,会将A<B>和A<C>都变为A。这样意味着C实现了两次A接口,编译不通过。
//但是将A接口的两个实现的泛型都去掉后,编译通过。(在使用java的一些基本接口时会遇到:Comparable<T>)
14:泛型方法重载
一下代码不能编译通过:
public Class A(){ void f(List<W> w); void f(List<V> v) }
//由于擦除的原因,上面的两个方法产生的签名是一样的。
¥¥此时正好听到了这首歌的这句话,颇有感慨。《明天会更好》:青春不解红尘。
15:“混型”:最基本的概念是:混合多个类的能力。
16、参数类型化:
//类型参数化 public class Cache<T> { T value; public Object getValue() { return value; } public void setValue(T value) { this.value = value; } }
代码:
泛型类: class ClassGenericity<T> { //在类里面可以直接使用T的类型 T aa; public void test11(T bb) { //................ } //静态方法 在类上面定义的泛型,不能再静态方法里面使用 public static <A> void test12(A cc) { //.................. }
泛型使用在参数和返回值中。 public class MethodGenericity { //泛型使用在参数中 private static<T> void exchange(T[] arr, int i, int j) { T temp=arr[i]; arr[i]=arr[j]; arr[j]=temp; } //泛型使用在返回值中 public <T> T get(T[] ts) { return ts[ts.length / 2]; } }
通配符 public static void fun(List<?> list) {…}
带有上边界的通配符 public static void fun(List<? extends Number> list) {…} fun(new ArrayList<Integer>());//ok fun(new ArrayList<Double>());//ok fun(new ArrayList<String>());//不ok
带有下边界的通配符 public static void fun(List<? super Integer> list) {…} fun(new ArrayList<Integer>());//ok fun(new ArrayList<Number>());//ok fun(new ArrayList<Object>());//ok fun(new ArrayList<String>());//不ok