文章目录
- 1、概念
- 2、好处
- 3、泛型的定义与使用
- 3.1、含有泛型的类
- 3.2、含有泛型的方法
- 3.3、含有泛型的接口
- 4、泛型通配符
- 5、通配符高级使用--受限泛型
- 5.1、泛型的上限
- 5.2、泛型的下限
集合中可以存放任意对象,只要把对象存储集合后,那么他们都会被提升为Object类型。当取出每一个对象,并且进行相应的操作,则必须进行类型转换。程序在运行时可能会发生java.lang.ClassCastException异常。
Collection虽然可以存储各种对象,但实际上通常Collection只存储同一类型对象。例如都是存储字符串对象。因此在JDK5之后,新增了泛型(Generic)语法,在设计API时可以指定类或方法支持泛型,这样使用API的时候也变得更为简洁,并得到了编译时期的语法检查。
1、概念
泛型是一种未知的数据类型。泛型也可以看作是一个变量,用来接收数据类型。创建集合对象是,会确定泛型的数据类型。如果集合不使用泛型,则默认是Object类型。
2、好处
- 将运行时期的ClassCastException,转移到了编译时期,变成了编译失败。
- 避免了类型强转的麻烦。
【弊端】泛型是什么类型,则集合就只能存储什么类型的数据。
3、泛型的定义与使用
3.1、含有泛型的类
- 格式
修饰符 class 类名<代表泛型的变量> {
//
}
- 创建对象时确定泛型
- 示例
// 自定义泛型类
public class Test23<E> {
private E e;
public E getE() {
return e;
}
public void setE(E e) {
this.e = e;
}
}
// 调用
public class Test24 {
public static void main(String[] args) {
// 创建泛型为String的对象
Test23<String> myObj = new Test23<>();
// 调用setE
myObj.setE("小学妹");
// 调用getE
String e = myObj.getE();
System.out.println(e);
// 创建泛型为Integer的对象
Test23<Integer> myObj1 = new Test23<>();
// 调用setE
myObj1.setE(123);
// 调用getE
Integer e1 = myObj1.getE();
System.out.println(e1);
}
}
3.2、含有泛型的方法
- 格式
修饰符 <代表泛型的变量> 返回值类型 方法名(参数列表) {
//
}
- 调用方法时确定泛型,传递什么类型的参数,泛型就是什么类型
- 示例
// 自定义泛型方法
public class Test25 {
public <E> void show(E e) {
System.out.println(e.getClass());
}
public <E> E show2(E e) {
return e;
}
}
// 调用
public class Test26 {
public static void main(String[] args) {
Test25 myObj = new Test25();
myObj.show("hello");
myObj.show(123);
myObj.show(12.34);
System.out.println(myObj.show2("hello"));
System.out.println(myObj.show2(123));
System.out.println(myObj.show2(12.34));
}
}
3.3、含有泛型的接口
- 格式
修饰符 interface 接口名<代表泛型的变量> {
//
}
- 定义类时确定泛型
- 始终不确定泛型,创建对象时确定泛型
- 示例
// 定义泛型接口
public interface Test27<E> {
public abstract void add(E e);
public abstract E get();
}
// 创建类时确定泛型
public class Test28 implements Test27<String> {
@Override
public void add(String s) {
System.out.println(s);
}
@Override
public String get() {
return null;
}
}
// 始终不确定泛型,创建对象时确定泛型
public class Test29<E> implements Test27<E> {
@Override
public void add(E e) {
System.out.println(e.getClass());
}
@Override
public E get() {
return null;
}
}
// 创建对象时确定泛型
public class Test30 {
public static void main(String[] args) {
Test29<String> myObj = new Test29<String>();
myObj.add("hello");
Test29<Integer> myObj1 = new Test29<Integer>();
myObj1.add(123);
}
}
4、泛型通配符
当使用泛型类或者接口时,传递的数据中,泛型类型不确定,可以通过通配符表示。但是一旦使用泛型的通配 符后,只能使用Object类中的共性方法,集合中元素自身方法无法使用。
【注意】
- 使用泛型通配符时,不能创建对象
- 使用泛型通配符时,只能作为方法的参数使用
- 泛型不存在继承关系
- 示例
public static void main(String[] args) {
Collection<Integer> list = new ArrayList<>();
list.add(123);
list.add(456);
list.add(789);
getEle(list);
Collection<String> list1 = new ArrayList<>();
list1.add("张三");
list1.add("李四");
list1.add("王五");
getEle(list1);
}
private static void getEle(Collection<?> coll) {
for (Object o : coll) {
System.out.println(o);
}
}
5、通配符高级使用–受限泛型
5.1、泛型的上限
- 格式:
<? extends E>
- 含义:只能接受该类型及其子类
5.2、泛型的下限
- 格式:
<? super E>
- 含义:只能接受该类型及其父类
public static void main(String[] args) {
Collection<Integer> list1 = new ArrayList<>();
Collection<String> list2 = new ArrayList<>();
Collection<Number> list3 = new ArrayList<>();
Collection<Object> list4 = new ArrayList<>();
getEle1(list1);
getEle1(list2); // 编译报错
getEle1(list3);
getEle1(list4); // 编译报错
getEle2(list1); // 编译报错
getEle2(list2); // 编译报错
getEle2(list3);
getEle2(list4);
}
// 泛型的上限:此时的泛型?,必须是Number类型或者Number类型的子类
private static void getEle1(Collection<? extends Number> list1) {
}
// 泛型的下限:此时的泛型?,必须是Number类型或者Number类型的父类
private static void getEle2(Collection<? super Number> list1) {
}