(1)泛型
泛型是JDK 1.5中新增的特性,在集合框架中使用,某种程度上是为了让集合记住其保存的元素的类型。
在泛型产生之前,集合中存入一个元素,集合并不知道存入元素的数据类型,集合会把所有对象全部当做Object类型处理。
但是当作Object类型处理之后,会出现以下的问题:
泛型是JDK 1.5中新增的特性,在集合框架中使用,某种程度上是为了让集合记住其保存的元素的类型。
在泛型产生之前,集合中存入一个元素,集合并不知道存入元素的数据类型,集合会把所有对象全部当做Object类型处理。
为解决以上的问题,JDK5以后,Java引入了泛型,即“参数化类型”。允许程序在创建集合时指定集合元素的类型(允许程序在创建对象或者调用方法时动态的指定),所谓泛型,就是允许在定义类、接口、方法时使用类型形参,这个类型形参将在声明变量、创建对象、调用方法时动态地指定(即传入实际的类型参数,也可称为类型实参)。
/**
* 泛型练习
*/
public class GnericityDemo {
public static void main(String[] args) {
//定义一个只能存放String类型的List集合
List<String> list = new ArrayList<>();
//添加元素到集合中
list.add("白嘉轩");
list.add("鹿子霖");
list.add("朱先生");
//编译出错 List泛型规定list中只能添加Stirng类型的元素 不能添加其他类型的元素
//list.add(123)
}
}
/**
* 菱形语法
*/
public class GnericityDemo1 {
public static void main(String[] args) {
//在Java1.5中要求泛型在类名和构造器名后写在<>内
List<String> list = new ArrayList<String>();
//在Java1.7中则可以省略构造器名称后的<>内的泛型。
List<String> list2 = new ArrayList<>();
}
}
允许在定义类、接口、方法时使用类型形参,这个类型形参将在声明变量、创建对象、调用方法时动态地指定(即传入实际的类型参数,也可称为类型实参)。Java 5 改写了集合框架中的全部接口和类,为这些接口、类增加了泛型支持,从而可以在声明集合变量、创建集合对象时传入类型实参,
泛型接口:
/**
* 泛型接口
* 允许在定义接口、类时声明类型形参、类型形参在整个接口、类中当成类型使用
* @param <E>
*/
public interface Ilist<E> extends Collection<E> {
boolean add(E e);
E get(int index);
}
泛型类:
/**
* 泛型类
*/
public class Student<T>{
//定义泛型类型的成员变量 具体类型在创建对象时指定
private T t;
public Student(T t){
this.t = t;
}
public T getT() {
return t;
}
public void setT(T t) {
this.t = t;
}
public T getInfo(){
return this.t;
}
}
/**
* 测试类
* 定义了一个带泛型声明的Student<T>类,使用Student<T>类是就可以为T类型传入实际类型
*/
public class GenericityDemo2 {
public static void main(String[] args) {
//创建对象时指定为String类型
Student<String> s1 = new Student<>("白鹿原");
System.out.println(s1.getInfo());
//传给T形参的是Integer类型 所以构造器中只能是Integer类型
Student<Integer> s2 = new Student<>(123);
System.out.println(s2.getInfo());
}
}
泛型通配符:
Java中可以使用类型通配符,类型通配符是一个问号(?),将一个问号做为实际类型传给List集合,写作:List<?>,意思是元素类型未知的List。它的元素类型可以匹配任何类型。
/**
* 新闻类 其泛型继承自Number 创建对象时,指定泛型必须是Number或者Number的子类
* @param <T>
*/
public class News <T extends Number>{
}
public class GenericityDemo3 {
public static void main(String[] args) {
List<?> list = new ArrayList();
//编译错误 add()方法有参数类型E作为集合的元素类型,所以传给add的参数必须是E类对象或者其子类的对象,但是在上例中不知道E是什么类型,所以无法将任何对象添加进集合
//list.add(1);
//如果想让上例中的代码正常工作,就需要学习通配符的上下限
//设置了泛型的上限Number,也就是说,当创建Teacher对象指定泛型类型时,只能传入Number类型或者Number类型的子类
News<Number> t1 = new News<>();
//编译通过,Integer是Number的子类
News<Integer> t3 =new News<>();
//编译错误,Integer是Number的父类
//News<Objects> t2 =new News<Objects>();
//编译错误,因为String和Number不存在继承关系
//News<String> t4 = new News<>();
}
}
泛型方法:
前面介绍了在定义类、接口时可以使用类型形参,在该类的方法定义和成员变量定义、接口的方法定义中,这些类型形参可被当成普通类型来用。在另外一些情况下,定义类、接口时没有使用类型形参,但定义方法时可以定义类型形参。
修饰符 <T> 返回值类型 方法名(形参列表){
//方法体
}
public class GnericityDemo4{
//定义泛型方法
public <T> T test(T t){
return t;
}
//注意:此方法只使用了泛型,不是泛型方法
// public void test(T t){
//
// }
public static void main(String[] args) {
GnericityDemo4 gd = new GnericityDemo4();
StringBuilder s = gd.test(new StringBuilder("白鹿原"));
System.out.println(s);
}
}
通配符下限:
public class GnericityDemo5 {
public static void main(String[] args) {
//通配符的下限
TreeSet<String> set = new TreeSet<>(new Comparator<Object>() {
@Override
public int compare(Object o1, Object o2) {
return 0;
}
});
}
}
泛型擦除:
public class GnericityDemo6 {
public static void main(String[] args) {
List<String> list1 = new ArrayList<>();
list1.add("张三");
//泛型擦除
List list2 = list1;
}
}