本次博客带领大家了解泛型的介绍。
泛型说明
- 泛型又称参数化类型,是jdk5.0出现的新特性,解决数据类型的安全性问题。
- 在类声明或实例化时只要指定好需要的具体的类型即可。
- Java泛型可以保证如果程序在编译时没有发出警告,运行时就不会产生ClassCastException异常,同时,代码更加简洁、健壮。
- 泛型的作用是:可以在类声明时通过一个标识表示类中某个属性的类型,或者是某个方法的返回值的类型,或者是参数类型。
public class Generic03 {
public static void main(String[] args) {
Person<String> stringPerson = new Person<String>("加油!");
stringPerson.t();
/*
你可以这样理解,上面的Person类
class Person{
String s;//E表示 s的数据类型,该数据类型在定义Person对象的时候指定,即在编译期间,就确定E是什么类型
public Person(String s) { //E也可以是参数类型
this.s = s;
}
public String f(){ //返回类型使用E
return s;
}
}
*/
}
}
class Person<E>{
E s;//E表示 s的数据类型,该数据类型在定义Person对象的时候指定,即在编译期间,就确定E是什么类型
public Person(E s) { //E也可以是参数类型
this.s = s;
}
public E f(){ //返回类型使用E
return s;
}
public void t(){
System.out.println(s.getClass());
}
}
泛型的语法
- 泛型的声明
interface 接口{} 和 class 类<K,V>{}
//比如:List,ArrayList
说明:
- 其中,T,K,V不代表值,而是表示类型。
- 任意字母都可以。常用T表示,是Type的缩写。
- 泛型的实例化:
要在类名后面指定类型参数的值(类型)。如:
- List strList = new ArrayList();
- Iterator iterator = customers.iterator();
- 泛型的使用举例
- 创建3个学生对象
- 放入到HashSet中学生对象使用
- 放入到HashMap中,要求Key是String name,Value 就是学生对象
- 使用两种方式遍历
public class GenericExercise {
public static void main(String[] args) {
//使用泛型方式给HashSet 放入3个学生对象
HashSet<Student> set = new HashSet<Student>();
set.add(new Student("jack",20));
set.add(new Student("tom",19));
set.add(new Student("smith",21));
//遍历
System.out.println("========增强for遍历======");
for (Student student : set) {
System.out.println("set="+student);
}
System.out.println("========迭代器遍历=======");
Iterator<Student> iterator = set.iterator();
while (iterator.hasNext()) {
Student student = iterator.next();
System.out.println("set="+student);
}
HashMap<String, Student> hm = new HashMap<>();
hm.put("milan",new Student("milan",20) );
hm.put("marry",new Student("marry",19) );
hm.put("ld",new Student("ld",21) );
//迭代器
System.out.println("=====HashMap的迭代器遍历");
Set<Map.Entry<String, Student>> entries = hm.entrySet();
Iterator<Map.Entry<String, Student>> iterator1 = entries.iterator();
while (iterator1.hasNext()) {
Map.Entry<String, Student> student = iterator1.next();
System.out.println(student.getKey()+"--"+student.getValue());
}
}
}
class Student{
public String name;
public int age;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
泛型使用的注意事项和细节
- interface List{},public class HashSet{}…等等
说明:T,E只能是引用类型
给泛型指向数据类型时,要求是引用类型,不能是基本数据类型。
List<Integer> list = new ArrayList<Integer>();//ok
ArrayList<int> ints = new ArrayList<int>();//错误
- 在给泛型指定具体类型后,可以传入该类型或者其子类类型。
Pig<A> aPig = new Pig<A>(new A());
Pig<A> aPig2 = new Pig<A>(new B());
class A{}
class B extends A{}
class Pig<E> {
E e;
public Pig(E e) {
this.e = e;
}
}
- 泛型的使用形式:
ArrayList<Integer> integers = new ArrayList<Integer>();
//在实际开发中,我们往往简写
//编译器会进行类型判断,老师推荐使用下面写法
ArrayList<Integer> integers1 = new ArrayList<>();
- 如果是这样写 泛型默认是 Object
ArrayList arrayList = new ArrayList();//等价于ArrayList<Object> arrayList = new ArrayList<>();
泛型练习题
定义Employee类
- 该类包含:private成员变量name,sal,birthday,其中 birthday 为 MyDate 类的对象;
- 为每一个属性定义 getter,setter方法;
- 重写toString 方法输出 name,sal,birthday;
- MyDate类包含:private成员变量month,day,year;并为每一个属性定义getter,setter方法;
- 创建该类的三个对象,并把这些对象放入ArrayList集合中(ArrayList需使用泛型来定义),对集合中的元素进行排序,并遍历输出。
排序方式:调用ArrayList的sort方法,传入Comparator对象[使用泛型],先按照name排序,如果name相同,则按生日日期的先后排序。
public class GenericExercise02 {
public static void main(String[] args) {
ArrayList<Employee> employees = new ArrayList<>();
employees.add(new Employee("tom",20000,new MyDate(1990,1,9)));
employees.add(new Employee("jack",12000,new MyDate(2001,12,12)));
employees.add(new Employee("tom",50000,new MyDate(1980,10,10)));
System.out.println("employees="+employees);
System.out.println("====对雇员进行排序====");
employees.sort(new Comparator<Employee>() {
@Override
public int compare(Employee emp1, Employee emp2) {
//先对传入的参数进行验证
if(!(emp1 instanceof Employee && emp2 instanceof Employee)){
System.out.println("类型不正确...");
return 0;
}
//比较name
int i = emp1.getName().compareTo(emp2.getName());
if(i != 0){
return i;
}
//下面是对birthday 的比较,因此,我们最好把这个比较,放在MyDate类完成
//封装后,将来可维护性和复用性,就大大增强。
return emp1.getBirthday().compareTo(emp2.getBirthday());
}
});
System.out.println("employees="+employees);
}
}
class Employee{
private String name;
private double sal;
private MyDate birthday;
public Employee(String name, double sal, MyDate birthday) {
this.name = name;
this.sal = sal;
this.birthday = birthday;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getSal() {
return sal;
}
public void setSal(double sal) {
this.sal = sal;
}
public MyDate getBirthday() {
return birthday;
}
public void setBirthday(MyDate birthday) {
this.birthday = birthday;
}
@Override
public String toString() {
return "\nEmployee{" +
"name='" + name + '\'' +
", sal=" + sal +
", birthday=" + birthday +
'}';
}
}
class MyDate implements Comparable<MyDate>{
private int year;
private int month;
private int day;
public MyDate(int year, int month, int day) {
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) {
//如果name 相同,就比较 birthday- year
int yearMinus = year - o.getYear();
if (yearMinus !=0){
return yearMinus;
}
//如果year 相同,就比较month
int monthMinus = month - o.getMonth();
if (monthMinus != 0){
return monthMinus;
}
//如果 year和 month
return day - o.getDay();
}
}