目录
一、泛型的介绍
- 泛型又称参数化类型,是Jdk5.0 出现的新特性,解决数据类型的安全性问题
- 在类声明或实例化时只要指定好需要的具体的类型即可。
- Java泛型可以保证如果程序在编译时没有发出警告,运行时就不会产生ClassCastException异常。同时,代码更加简洁、健壮
- 在类声明时通过一个标识表示类中某个属性的类型或者是某个方法的返回值及参数类型。
二、泛型的语法
2.1 泛型的声明
interface List<T> 和 class GenTest<K,V>
说明:
- 其中,T,K,V不代表值,而是表示类型。这里使
- 用任意字母都可以。常用T表示,是Type的缩写
2.2 泛型的实例化:
要在类名后面指定类型参数的值(类型)。如:
1) List<String> strList = new ArrayList<String>();
- 1. new ArrayList<String> 仍然是运行类型, 表示ArrayList ,并且只能存放String类型
- 2. List<String> 仍然是编译类型, 表示是一个List类型,可以存放String类型
2) Iterator<Customer> iterator = customers.iterator();
- 返回迭代器时,直接指定迭代器指向就是此类型
2.3 泛型使用举例
举例说明,泛型在 HashSet, TreeSet, HashMap 的使用情况, 看老师演示
import java.util.HashMap; import java.util.HashSet; import java.util.Set;
public class GenericDemo03 { public static void main(String[] args) { // TODO Auto-generated method stub // 举例说明,泛型在 HashSet, TreeSet, HashMap 的使用情况, 看老师演示
HashSet<Student> hashSet = new HashSet<Student>(); Student student1 = new Student("jack", 1); Student student2 = new Student("tom", 10); Student student3 = new Student("smith", 4); hashSet.add(student1); hashSet.add(student2); hashSet.add(student3);
//遍历 for (Student student : hashSet) { System.out.println(student); }
// 双列集合 //public class HashMap<K,V>{} //传入几个类型 HashMap<String, Student> hashMap = new HashMap<String, Student>(); hashMap.put("100", student1); hashMap.put("200", student2); hashMap.put("300", student3);
//遍历 Set<String> keySet = hashMap.keySet(); for (String key : keySet) { Student student = hashMap.get(key); System.out.println("s=" + student); } }
}
class Student { public String name; public int age;
public Student(String name, int age) { super(); this.name = name; this.age = age; }
@Override public String toString() { return "Student [name=" + name + ", age=" + age + "]"; }
}
|
2.3 泛型使用的注意事项和细节
1) interface List<T> ,public class HashSet<E>.. 等等
说明:T, E 只能是引用类型
看看下面语句是否正确?:
List<Integer> list = new ArrayList<Integer>();//T
List<int> list2 = new ArrayList<int>();//F, 泛型不能是基本数据类型
2) 泛型使用的形式
List<Integer> list4 = new ArrayList<Integer>();
List<Integer> list4 = new ArrayList<>(); [说明: 会根据前面的编译类型的泛型,来推断<>中是什么类型] , 推荐使用
2.4 泛型课堂练习题
定义Employee类
1) 该类包含:private成员变量name,age,birthday,其中 birthday 为 MyDate 类的对象;
2) 为每一个属性定义 getter, setter 方法;
3) 重写 toString 方法输出 name, age, birthday
4) MyDate类包含: private成员变量month,day,year;并为每一个属性定义 getter, setter 方法;
5) 创建该类的 3 个对象,并把这些对象放入 ArrayList 集合中(ArrayList 需使用泛型来定义),并遍历输出(选择一个即可):
排序方式: 调用ArrayList 的 sort 方法, 传入 Comparator对象,先按照name,排序,如果name相同,则按生日日期的先后排序。【即:定制排序】
代码演示
package com.atguigu.generic;
import java.util.ArrayList; import java.util.Comparator; import java.util.Iterator;
public class GenericExercise01 {
public static void main(String[] args) { // TODO Auto-generated method stub ArrayList<Employee> arrayList = new ArrayList<>(); MyDate myDate1 = new MyDate(2000,11,11); MyDate myDate2 = new MyDate(2000,11,10); MyDate myDate3 = new MyDate(2000,11,1);
Employee employee1 = new Employee("jack", 10, myDate1); Employee employee2 = new Employee("jack", 20, myDate2); Employee employee3 = new Employee("jack", 30, myDate3);
arrayList.add(employee1); arrayList.add(employee2); arrayList.add(employee3);
//迭代器 Iterator<Employee> iterator = arrayList.iterator(); while(iterator.hasNext()) { Employee employee = iterator.next(); System.out.println(employee); }
//定制排序. arrayList.sort(new Comparator<Employee>() {
@Override public int compare(Employee o1, Employee o2) { //先看名字 int compareTo1 = o1.getName().compareTo(o2.getName()); if(compareTo1 !=0) {//比较有结果 return compareTo1; } else { //比较 生日. return o1.getBirthday().compareTo(o2.getBirthday()); } } }); System.out.println("排序=" + arrayList);
}
} /* * 定义Employee类 1) 该类包含:private成员变量name,age,birthday,其中 birthday 为 MyDate 类的对象; 2) 为每一个属性定义 getter, setter 方法; 3) 重写 toString 方法输出 name, age, birthday 4) MyDate类包含: private成员变量month,day,year;并为每一个属性定义 getter, setter 方法; 5) 创建该类的 3 个对象,并把这些对象放入 ArrayList 集合中(ArrayList 需使用泛型来定义),并遍历输出(选择一个即可): 排序方式: 调用ArrayList 的 sort 方法, 传入 Comparator对象, 先按照name,排序,如果name相同,则按生日日期的先后排序。【即:定制排序】
*/ class Employee { private String name; private int age; private MyDate birthday; public Employee(String name, int age, MyDate birthday) { super(); this.name = name; this.age = age; this.birthday = birthday; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public MyDate getBirthday() { return birthday; } public void setBirthday(MyDate birthday) { this.birthday = birthday; } @Override public String toString() { return "Employee [name=" + name + ", age=" + age + ", birthday=" + birthday + "]\n"; }
}
class MyDate implements Comparable<MyDate>{ private int year; private int month; private int day; public MyDate(int year, int month, int day) { super(); this.year = year; this.month = month; this.day = day; } public int getYear() { return year; } public void setYear(int year) { this.year = year; } public int getMonth() { return month; } public void setMonth(int month) { this.month = month; } public int getDay() { return day; } public void setDay(int day) { this.day = day; } @Override public String toString() { return "MyDate [year=" + year + ", month=" + month + ", day=" + day + "]"; } @Override public int compareTo(MyDate o) { //想到... //比较年 int compare1 = year - o.year; if(compare1 != 0) { return compare1; } else { //比较月 int compare2 = month - o.month; if(compare2 != 0) { return compare2; } else { return day - o.day; } } }
} |
2.5 自定义泛型类
- 基本语法
class 类名<T, R...> {
成员
}
注意细节
1) 普通成员可以使用泛型
2) 使用泛型的数组,不能初始化
3) 静态成员中不能使用泛型
4) 泛型类的类型,是在创建对象时确定的(因为创建对象时,需要指定确定类型)
5) 如果在创建对象时,没有指定类型,默认为Object
- 应用案例
下面举例说明自定义泛型的使用, 看老师演示.
package com.atguigu.generic;
public class CustomGeneric {
public static void main(String[] args) {
//使用自定义泛型 //解读 //1. 当创建对象时, T 就是 String // R 就是 Integer // M 就是 Double MyGeneric<String, Integer, Double> myGeneric = new MyGeneric<>("尚硅谷");
//变化 myGeneric.setM(100.3); myGeneric.setR(100); myGeneric.setT("hello");
System.out.println(myGeneric.getT());
// T 就是 Book // R 就是 Float // M 就是 String MyGeneric<Book, Float, String> myGeneric2 = new MyGeneric<>("尚硅谷");
//如果在创建对象时,没有指定类型,默认为Object MyGeneric<Object,Object,Object> myGeneric3 = new MyGeneric("hsp");
}
}
class Book {
}
//自定义的泛型 class MyGeneric<T, R, M> { String name; R r; // 普通成员属性,可以使用泛型
// 普通成员方法,可以使用泛型 public R getR() { return r; }
public void setR(R r) { this.r = r; }
public M getM() { return m; }
public void setM(M m) { this.m = m; }
M m; T t; // 不允许泛型数组开辟长度或初始化, 因为数组在开空间时,大小需要明确,而T 不能明确空间大小 //T[] ts = new T[9];
// 不允许静态成员使用泛型, 因为 静态成员是在加载类的时候,就完成,而我们的T是在创建对象时,才确定 // 因为,不能通过 // static T m; // public static void method(T t){ // // } public static void show() { }
public T getT() { return t; }
public void setT(T t) { this.t = t; }
@Override public String toString() { return "MyGeneric [name=" + name + "]"; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public MyGeneric(String name) { super(); this.name = name; } }
|
2.6 自定义泛型接口
- 基本语法
interface 接口名<T, R...> {
}
- 注意细节
1) 接口中,静态成员也不能使用泛型
2) 泛型接口的类型, 在接口被扩展时(即:被继承或者实现) 会确定
3) 没有指定类型,默认为Object
代码演示
public class InterfaceGeneric { public static void main(String[] args) { // TODO Auto-generated method stub AA aa = new AA(); aa.app(1); aa.consume(12, 20, "hello", "jack"); } }
interface MyInter<T, R> { // 基于接口的泛型 // 普通方法中,可以使用接口泛型 R get(T u); void app(R r); void consume(R r1, R r2, T u1, T u2);
// 在jdk8 中,可以再接口中,使用默认方法 default R method(T u) { return null; } }
// 类与接口是实现, 传入了类型, 使用到泛型 class AA implements MyInter<String, Integer> { @Override public Integer get(String u) { // TODO Auto-generated method stub return null; } @Override public void app(Integer r) { // TODO Auto-generated method stub } @Override public void consume(Integer r1, Integer r2, String u1, String u2) { // TODO Auto-generated method stub } }
// 接口和接口之间是继承, 指定了类型 // 再去继承 MyInter2时,就会体现泛型 interface MyInter2 extends MyInter<Double, Double> {
}
class BB implements MyInter2 { @Override public Double get(Double u) { // TODO Auto-generated method stub return null; } @Override public void app(Double r) { // TODO Auto-generated method stub } @Override public void consume(Double r1, Double r2, Double u1, Double u2) { // TODO Auto-generated method stub } } }
|
2.7 自定义泛型方法
- 基本语法
修饰符 <T,R..>返回类型 方法名(参数列表) {
}
- 注意细节
- 泛型方法,可以定义在普通类中, 也可以定义在泛型类中
- 当泛型方法被调用时,类型会确定.
三、泛型的继承和通配符说明
1) 泛型不具备继承性
2) <?> :支持任意泛型类型
3) <? extends A>:支持A类以及A类的子类,规定了泛型的上限
4) <? super A>: 支持A类以及A类的父类,不限于直接父类,规定了泛型的下限
代码演示
package com.atguigu.generic;
import java.util.ArrayList; import java.util.List;
public class GenericPattern {
public static void main(String[] args) { // TODO Auto-generated method stub ArrayList<Object> al1 = new ArrayList<>(); ArrayList<String> al2 = new ArrayList<>(); ArrayList<AA> al3 = new ArrayList<>(); ArrayList<BB> al4 = new ArrayList<>(); ArrayList<CC> al5 = new ArrayList<>();
// 如果是 List<?> 表示都能接受. printCollection1(al3); printCollection1(al1); printCollection1(al2); printCollection1(al4); printCollection1(al5);
// List<? extends AA> 是可以接受 AA 或者 AA的子类型 // AA 是上限 . // printCollection2(al1); // printCollection2(al2); printCollection2(al3);// ok printCollection2(al4);// ok printCollection2(al5);// ok
// printCollection3(al1);// ok Object 是 AA父类 // printCollection3(al2);//error String 和AA 没有关系 // printCollection3(al3);// ok AA // printCollection3(al4);// error BB 是AA的子类 // printCollection3(al5);// error CC 是 AA 的子类
}
// ? super 子类类名A:支持A类以及A类的父类,不限于直接父类,规定了泛型的下限 public static void printCollection3(List<? super AA> c) { for (Object object : c) { System.out.println(object); } }
// 解读 // List<?> 表示 ? 任意的类型 引用类型 public static void printCollection1(List<?> c) { for (Object object : c) { // 通配符,取出时,就是Object System.out.println(object); } }
// ? extends AA 表示 上限,可以接受 AA或者AA子类型 public static void printCollection2(List<? extends AA> c) { for (Object object : c) { System.out.println(object); } }
}
class AA { // 超类 }
class BB extends AA {// 父类 }
class CC extends BB {// 子类 }
|