1. 泛型
泛型是JDK1.5的新特性,泛型的本质是参数化类型,也就是给所操作的数据类型指定一个参数,使代码可以用于多种类型。
2. 泛型的好处
Java语言引入泛型的好处有以下几点:
- 安全简单:在编译的时候就检查类型安全,并且所有的强制转换都是自动和隐式进行的,提高了代码的重用率。
- 消除了强制类型转换:泛型消除了代码中的很多强制类型转换,使得代码更加可读,减少了出错机会。
不使用泛型的例子:
List list = new ArrayList();
list.add("sdsggegeerger");
list.add(52);
String a1 = (String)list.get(0);//需要强制转型,否则编译不通过
int a2 = (int)list.get(1); //需要强制转型,否则编译不通过
int a3 = (int)list.get(0); //运行时抛出异常java.lang.ClassCastException
System.out.println(a1);
System.out.println(a2);
System.out.println(a3);
System.out.println(list);
使用泛型的例子:
List<String> list = new ArrayList();
list.add("sdsggegeerger");
list.add(52);//编译期就报错,减少出错机会
String s = list.get(0);//不需要强制类型转换,简单高效
3. 自定义泛型类、泛型接口、泛型方法
3.1 泛型类
泛型类简单说就是具有一个或多个类型参数的类。
- 定义泛型类的语法格式如下:
访问控制符 class className< TypeList > {…}
例如:public class Student<T,V>{…} - 创建泛型类实例的语法格式如下:
new className< TypeList >(argList)
例如:new Student<String,Integer>(“xingze”,18);
注: TypeList表示定义的类型参数列表,每个类型变量之间以逗号分隔
ArgList表示实际传递的类型参数列表,每个类型变量之间以逗号分隔
代码如下:
public class test1<E,T> {
private E e;
private T t;
public test1(E e,T t)
{
this.e=e;
this.t=t;
}
public void showType()
{
System.out.println("E的类型为:"+e.getClass().getName());
System.out.println("T的类型为:"+t.getClass().getName());
}
public static void main(String[] args)
{
test1<String, Integer> tt=new test1<String,Integer>("xingze",21);
tt.showType();
//输出: E的类型为:java.lang.String
// T的类型为:java.lang.Integer
}
}
3.2 泛型接口
泛型接口就是拥有一个或多个类型参数的接口。泛型接口的定义方式与定义泛型类类似。
- 定义泛型接口的语法格式如下:
访问修饰符 interface interfaceName< TypeList > {…}
例如:public interface Student<T,V>{ public T print(T t); } - 泛型类实现泛型接口的语法格式如下:
访问修饰符 class className< TypeList> implements interfaceName< TypeList>
代码如下:
public interface test2<T,V> {
public void print(T t,V v);
public void showType(T t,V v);
}
3.3 泛型方法
泛型方法实际上就是带有类型参数的方法。定义泛型方法与方法所在的类或接口是否是泛型类或接口没有直接的联系,也就是说,无论是非泛型类还是泛型类,都可以定义泛型方法。
- 定义泛型方法的语法格式如下:
访问修饰符<类型参数> 返回值 方法名 (类型参数列表)
例如: public< String> void showName(String s){…}
代码如下:
public void showType(T t, V v) {
System.out.println("T的类型为:"+t.getClass().getName());
System.out.println("V的类型为:"+v.getClass().getName());
}
3.4 从泛型类派生子类
面向对象的特性同样适用于泛型类,所以泛型类也可以被继承。不过,继承了泛型类的子类,必须也是泛型类。
继承泛型类的语法格式:class 子类 < T > extends 父类 < T >{…}
4. 泛型擦除
Java的泛型是伪泛型,这是因为Java程序在编译期间,所有的泛型信息都会被擦除,集合元素的类型都是Object。例如在代码中定义的List< object>和List< String>等类型,在编译后都会编程List。JVM看到的只是List,而由泛型附加的类型信息对JVM来说是不可见的。
List<String> list1=new ArrayList<>();
list1.add("xing");
list1.add("ze");
//编译器会丢失list1的类型信息,是典型的擦除
List list2=list1;
Java允许将一个List类型的对象赋给一个List< Type >(Type可以是任何类型)类型的变量。如下代码可以编译通过。
List<String> list1=new ArrayList<>();
list1.add("xing");
list1.add("ze");
//编译器会丢失list1的类型信息,是典型的擦除
List list2=list1;
List<Integer> list3=list2;
5. 泛型通配符
通配符用于表示某种未知的类型,例如 List<?> 表示一个可以存储任何类型对象的 List,但是不能对其中的元素进行添加操作。通配符可以用来解决类型不确定的情况,例如在方法参数或返回值中使用。