泛型(java!java!java!)
第十四天
泛型
1.什么是泛型
泛型是一种特殊的数据类型,在这之前,不管我们在定义成员变量时,还是方法的形参时,都要规定他们的具体类型。
2.泛型类的应用
当我们将泛型用在类上时,这个类就叫做泛型类。 泛型定义在类名后。
//在类上定义泛型的类型的变量,T代表的未来将要使用的具体类型 public class Person<T> {//使用类型参数T,来定义变量id。T id;//因为要给id初始化,所以构造器中的形参也应该规定为Tpublic Person(T id) {this.id = id;} }
在实例化时,指定具体类型
public static void main(String[] args) {Person<String> p1 = new Person<>("c1001"); //泛型必须传引用类型,不能是基本数据类型Person<Integer> p2 = new Person<>(1001); }
在继承时,指定具体类型
class Student extends Person<String>{Student(String id){super(id);} }
在继承时,如果不指定具体类型,则默认是Object类型
class Student extends Person{Student(String id){//super(id); 字符串型//super(1001);// Integer类型,也型super(new int[]{});} }
子类也可以使用自己的泛型变量,给父类的泛型变量赋值
class Student<M> extends Person<M>{Student(M id){super(id);} }
3.泛型接口的应用
public interface MyComparator <T,M>{int compare(T t,M m);T calculate(T t,M m); }
实例化时
public static void main(String[] args) {MyComparator comparator = new MyComparator<Integer,Integer>() {public int compare(Integer t1, Integer t2) {return t1.compareTo(t2);}public Integer calculate(Integer t1, Integer t2) {return t1+t2;}}; }
子类实现接口时
//实现子类时,不指定具体泛型,默认就是Object类型了。 class Teacher implements MyComparator{ @Overridepublic int compare(Object o, Object o2) {//两个teacher在比较时,要不要强转,思考一下,会不会很麻烦。return 0;} @Overridepublic Object calculate(Object o, Object o2) {return null;} }
4.泛型方法的应用
public class MyUtil {//泛型方法,泛型定义在返回值类型前面。public static <T> boolean eq(T a, T b) {return a.equals(b);} }public class Employee{String name;public Employee(String name){this.name = name;}@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;Employee employee = (Employee) o;return Objects.equals(name, employee.name);} }public static void main(String[] args) {//调用泛型方法时,不需要传入具体类型名,只需要传入具体类型的值//会主动推导出具体的类型。boolean f = MyUtil.eq("abc","hello");System.out.println("f = " + f);Employee e1 = new Employee("张三");Employee e2 = new Employee("张三");f = MyUtil.eq(e1,e2);System.out.println("f = " + f); }
5.泛型通配符
泛型通配符用 ?,代表不确定的类型,是泛型的一个重要组成。 在调用时,表示我不关心具体类型。
也可以使用通配符规定调用时,传入的类型的范围,即上边界,和下边界。
简单应用:
public class Application {public static void print(List<String> list) {for (int i = 0; i < list.size(); i++) {System.out.println(list.get(i));}}public static void main(String[] args) {// Integer 集合,可以运行List<Integer> intList = Arrays.asList(0, 1, 2);print(intList);// String 集合,可以运行List<String> strList = Arrays.asList("0", "1", "2");print(strList);} }
List<?> list
代表我不确定 List 集合装的是什么类型,有可能是 Integer,有可能是 String,还可能是别的东西。但我不管这些,你只要传一个 List 集合进来,这个方法就能正常运行。
6.上边界
上边界,代表类型变量的范围有限,只能传入某种类型,或者它的子类。
利用 <? extends 类名>
的方式,可以设定泛型通配符的上边界。你看下这个例子就明白了。
public class TopLine {public static void print(List<? extends Number> list) {for (int i = 0; i < list.size(); i++) {System.out.println(list.get(i));}}public static void main(String[] args) {// Integer 是 Number 的子类,可以调用 print 方法print(new ArrayList<Integer>());// String 不是 Number 的子类,没法调用 print 方法print(new ArrayList<String>());}}
7.下边界
下边界,代表类型变量的范围有限,只能传入某种类型,或者它的父类。
利用 <? super 类名>
的方式,可以设定泛型通配符的下边界。你看下这个例子就明白了。
public class LowLine {public static void print(List<? super Integer> list) {for (int i = 0; i < list.size(); i++) {System.out.println(list.get(i));}}public static void main(String[] args) {// Number 是 Integer 的父类,可以调用 print 方法print(new ArrayList<Number>());// Long 不是 Integer 的父类,没法调用 print 方法// print(new ArrayList<String>());} }
总结:
泛型是一种特殊的类型,你可以把泛型用在类、接口、方法上,从而实现一些通用算法。
此外,使用泛型有三个步骤:定义类型变量、使用类型变量、确定类型变量。
在确定类型变量这一步中,你可以用泛型通配符来限制泛型的范围,从而实现一些特殊算法。