泛型: JDK1.5开始使用,允许在定义类和接口时,通过一个标识表示类中某个属性的类型或者是某个方法的返回值及参数类型。
1. 在集合框架中使用泛型
1.1 ArrayList
原先不使用泛型,必须要强转,且对数据的类型没有要求,在类型转换时,可能会报ClassCastException错误。
ArrayList score = new ArrayList();
score.add(24);
score.add("12");
for (Object o : score) {
// java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer
int i = (int) o;
}
现在使用泛型,对添加到集合中的数据的类型加以要求。
ArrayList<Integer> list = new ArrayList<>();
list.add(12);
for (Integer i : score) {
// 避免了强转操作
int j = i;
System.out.println(j);
}
1.2 HashMap
// Map<String, Integer> map = new HashMap<String, Integer>();
Map<String, Integer> map = new HashMap<>(); // JDK7.0 类型推断
map.put("Tom", 12);
map.put("John", 18);
map.put("Jack", 11);
// 泛型嵌套
Set<Map.Entry<String, Integer>> entries = map.entrySet();
Iterator<Map.Entry<String, Integer>> iterator = entries.iterator();
while(iterator.hasNext()) {
Map.Entry<String, Integer> next = iterator.next();
String key = next.getKey();
Integer value = next.getValue();
System.out.println(key + " ---- " + value);
}
2. 泛型在继承中怎么使用?
2.1 全部保留
class Order<K, V> {}
class SubOrder<T, K> extends Order<T, K> {}
2.2 部分保留
class SubOrder<T> extends Order<Integer, T> {}
2.3 擦除
class SubOrder extends Order<Integer, String> {
// 由于子类在继承带泛型的父类时,指明了泛型类型,则实例化子类对象时,不再需要指明泛型
}
class SubOrder extends Order {}
// 等价
class SubOrder extends Order<Object, Object> {}
3. 如何自定义泛型结构?
3.1 泛型类
class Order<K, V, E> {
// ...
}
3.2 泛型接口
public interface Iterator<E> {
// ...
}
3.3 泛型方法
泛型方法和泛型类(或者泛型接口)定义的泛型没有任何关系
class Order<E> {
public <E> E show(E e) { // 此处的E不是泛型类Order的E
return e;
}
}
@Test
public void test() {
Order<Integer, String> order = new Order<>();
Character a = order.show('a');
System.out.println(a); // a
}
4. 通配符
class A<E>{
public void show(List<?> list) {
Iterator<?> iterator = list.iterator();
while(iterator.hasNext()) {
Object next = iterator.next();
System.out.println(next);
}
}
}
class B<E> extends A<E>{}
class C extends B{}
interface Info {}
class D implements Info {}
class F implements Info {}
class G<E extends Info> {}
@Test
public void test3() {
G<D> info = new G<>();
G<F> info1 = new G<>();
}
@Test
public void test() {
Object obj = null;
String str = null;
obj = str;
Object[] obj1 = null;
String[] str1 = null;
obj1 = str1;
A<Object> obj2 = null;
B<Object> str2 = null;
obj2 = str2;
A<String> a = new A<>();
B<String> b = new B<>();
a = b; // A<String> 是 B<String> 的父类
List<A> list1 = new ArrayList<>();
List<B> list2 = new ArrayList<>();
// list1 = list2; // 错误:这两个是并列关系
// list2 = list1;
List<?> list3 = new ArrayList<>();
list3 = list1;
list3 = list2;
}
@Test
public void test1() {
List<?> list1 = null;
List<String> list2 = new ArrayList<>();
list2.add("hello world");
list1 = list2;
// list1.add("a"); // 不能再添加数据了
list1.add(null);
Object o = list1.get(0);
System.out.println(o);
}
@Test
public void test2() {
// 上限是A (-∞, A]:代表List list1要求的数据类型,可能是这个类型区间内的某一个类型
List<? extends A> list1 = new ArrayList<>();
// 下限是B [B, +∞)
List<? super B> list2 = new ArrayList<>();
List<A> list3 = new ArrayList<>();
List<B> list4 = new ArrayList<>();
List<Object> list5 = new ArrayList<>();
list1 = list3;
list1 = list4;
// list1 = list5; // 错误:
Object o = list1.get(0);
A a = list1.get(0);
list2 = list3;
list2 = list4;
list2 = list5;
// 写入
// list1.add(new B()); // 错误:下限不确定,list1要求的数据类型可能比B小,导致B类型的数据不能被添加
// list1.add(new A()); // 同上
list1.add(null);
// list2.add(new A()); // 同上
list2.add(new B());
list2.add(new C());
}
5. 使用泛型的注意点
5.1 不同泛型的引用之间不能相互赋值
// 编译通过
String a = null;
String b = null;
a = b;
ArrayList list1 = new ArrayList();
ArrayList list2 = new ArrayList();
list1 = list2;
// 编译报错:Required type: ArrayList <String> Provided: ArrayList <Integer>
ArrayList<String> strList = new ArrayList<>();
ArrayList<Integer> intList = new ArrayList<>();
strList = intList;
5.2 静态方法中不能访问变量类或者接口的泛型
public class Order<E, K> {
// 编译报错:静态方法不能访问类或者接口的泛型
public static void d(K k) {}
}
5.3 异常类不能是泛型类,也不能在try...catch中将异常的类型定义为泛型
// 编译报错:异常类不能是泛型类
public class MyException<T> extends Exception {}
// 不能在try...catch中将异常的类型定义为泛型
try {
// ...
} catch (T t) { // 编译报错
// ...
}
5.4 泛型的类型必须是类,不能是基本数据类型。需要用到基本数据类型的位置,拿包装类替换。
class Order<K, V> {}
// 编译报错:Type argument cannot be of primitive type
Order<int, int> order = new Order<>();
// 正确写法
Order<Integer, Integer> order = new Order<>();
5.6 没有指明泛型类型的,默认类型为java.lang.Object类型
class Order<K, V> {}
class SubOrder extends Order {}
// 等价于:class SubOrder extends Order<Object, Object> {}
Order order = new Order();
// 等价于:Order<Object, Object> order = new Order<>();
5.7 可能有多个泛型,如果需要,全部都要声明
class Order<K, V> {}
// 编译报错:只提供了K,没有提供V
class SubOrder extends Order<Integer> {}
// 编译报错:只提供了K,没有提供V
Order<Integer> order = new Order<>();