泛型
泛型是JDK1.5之后出现的新特性,泛指某一种数据类型,当使用一个类、方法、接口不确定要使用什么数据类型的时候,或者说不确定要用来处理哪种数据类型的时候可以定义为泛型。
使用泛型的好处
1.在谈使用泛型的好处之前,先说一下不使用泛型的情况。
例如,在集合创建时,不使用泛型,那么会默认为Object类型,可以储存任意数据类型
public class Demo08Generic {
public static void main(String[] args) {
//不使用泛型
Collection list = new ArrayList();
list.add("abc");
list.add(12345);
Iterator it = list.iterator();
//可以使用迭代器把不同的数据类型同时打印
while(it.hasNext()){
System.out.println(it.next());
}
}
}
在集合中放入不同的数据类型,程序不会报错,下面是输出结果:
abc
12345
但是不使用反映,弊端也是很明显的,而且编译的时候不会报错,运行的时候才会报错
比如上面的程序中,如果想使用字符串的API接口方法length( )获取字符串的长度时
public class Demo08Generic {
public static void main(String[] args) {
//不使用泛型
Collection list = new ArrayList();
list.add("abc");
list.add(12345);
Iterator it = list.iterator();
//可以使用迭代器把不同的数据类型同时打印
while(it.hasNext()){
System.out.println(it.next());
String str = (String)it.next();
System.out.println(str);
}
}
}
上面的程序在编译时不会报错,但是运行会报错:ClassCastException(类转换异常)
Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
at com.itheima.demo03.Generic.Demo08Generic.main(Demo08Generic.java:21)
2.如果使用泛型,可以避免程序在运行时报错,因为它会把这类错误提前到程序编译时抛出异常,可以提前发现。
当确实集合的类型为String类型时,如果加入整形的数据类型,编译会直接报错。
public class Demo08Generic {
public static void main(String[] args) {
//使用泛型
Collection<String> list = new ArrayList<>();
list.add("abc");
list.add(12345);//编译抛出异常 add(java.lang.String) in Colletion cannot be applied to (int)
Iterator it = list.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
}
}
定义含有泛型的类、方法、接口
1、定义泛型的类
定义一个泛型类,可以把类中的成员变量和成员方法都定义为泛型(成员变量和成员方法也可以定义为具体的数据类型,不过这样就失去了定义为泛型类的意义了)。
格式:
public class GenericClass<E> {
public E name;
public <E> void method(E e){
//方法体
}
}
泛型类在创建对象时,确认泛型的类型
public class Demo01GenericClass {
public static void main(String[] args) {
GenericClass<String> gc = new GenericClass<>();
gc.name="夸父";
System.out.println(gc.name);
}
}
2、定义含有泛型的方法
格式与上面的泛型类中定义的泛型方法一致;
public class GenericClass<E> {
//可以修改为把泛型当做返回值,穿进来什么数据类型,返回的就是什么数据类型
public <E> E method(E e){
return e;
}
}
使用:在调用方法的时候确定泛型的数据类型,传递什么数据类型的参数,泛型就是什么类型
public class Demo01GenericClass {
public static void main(String[] args) {
GenericClass<String> gc = new GenericClass<>();
//传入的是double类型,返回的就是double类型
Double method1 = gc.method(34567.12);
}
}
还可以定义含有泛型的静态方法,格式:
public static <S> void MethodStatic(S s){
System.out.println(s);
}
静态方法用类名直接调用(类名.静态方法名)
public class Demo01GenericClass {
public static void main(String[] args) {
GenericClass.MethodStatic("女娲");
}
}
3、定义含有泛型的接口
格式:
public interface GenericInterface<I> {
public abstract void methodInterface(I i);
}
泛型接口的使用方式有两种,一种是:定义接口的实现类,指定接口的泛型
public class GenericInterfaceImpl implements GenericInterface<String> {
//重写接口的方法也跟着确定了类型
@Override
public void methodInterface(String s){
System.out.println(s);
}
}
第二种使用方式:把接口的实现类也写成含有泛型的格式,创建对象时再确定泛型的类型
public class GenericInterfaceImpl1<E> implements GenericInterface<E> {
@Override
public void methodInterface(E e){
System.out.println(e);
}
}
创建对象,并确定泛型的数据类型
public class Demo01GenericClass {
public static void main(String[] args) {
GenericInterfaceImpl1<String> gc1 = new GenericInterfaceImpl1();
gc1.methodInterface("天天向上");
}
}
泛型的通配符
泛型的通配符:?
表示任意的数据类型
泛型通配符的高级用法:
1、<? extends E>:代表使用的泛型只能是E类型的子类或者本身
2、<? super E> :代表使用的泛型只能是E类型本身或者父类
例如
public static void getElement(Collection<? extends Number> coll){
//此时的泛型?,必须是Number类型或者是Number类型的子类
}
public static void getElement1(Collection<? super Number> coll){
//此时的泛型?,必须是Number类型或者是Number类型的父类
}
注意事项:泛型的通配符不能在创建对象的时候使用,可以作为方法的参数使用
总结
实际开发中,泛型很常见,框架中也很多地方使用,系统的把泛型过一遍,这样在读代码的时候,遇到使用泛型的地方,不会不理解了。