1、概念:
泛型就是用来定义可以传入什么数据类型,限制传入的数据类型。
指定泛型的具体类型之后,可以传入该类型或者该类的子类型。
2、意义:
1、泛型的好处,可以在编译时进行数据类型检查。
例如:
//约束collection集合中只能存储String类型的数据
Collection<String> collection = new ArrayList<>();
推荐写法:
3、使用:
类和接口中使用:
package com.hsf.First;/*
* @author HSF
* @version 8.0
*/
public class Generic02 {
public static void main(String[] args) {
Person<String,Integer> stringPerson = new Person<String,Integer>("liLei");
}
}
class Person<E,K> {
E name;
public Person(E name) {
this.name = name;
}
public E fn() {
return name;
}
}
集合使用:
package com.hsf.First;/*
* @author HSF
* @version 8.0
*/
import java.util.ArrayList;
public class First_ {
public static void main(String[] args) {
ArrayList<Dog> dogs = new ArrayList<>();
dogs.add(new Dog("旺财", 10));
dogs.add(new Dog("大黄", 8));
dogs.add(new Dog("小黄", 12));
// dogs.add(new Cat()); // 不是Dog类型:报错
/*
没有使用泛型之前:只能接收一个Object对象,并且要进行向下转型,才可以使用dog的get和set方法。
for (Object o : dogs) {
Dog dog = (Dog)o;
System.out.println(dog.getName());
}
*/
// 使用泛型之后:可以直接使用dog对象来接收
for (Dog dog : dogs) {
System.out.println(dog.getName() + dog.getAge());
}
}
}
class Dog {
private String name;
private int age;
public Dog(String name, int age) {
this.name = name;
this.age = age;
}
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;
}
}
class Cat {
}
package com.hsf.First;/*
* @author HSF
* @version 8.0
*/
import com.sun.org.apache.xml.internal.serializer.ToStream;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
public class Test {
public static void main(String[] args) {
Map<String, Student> map = new HashMap<String, Student>();
Student liLei = new Student("liLei", 20);
Student mary = new Student("mary", 18);
Student jack = new Student("jack", 25);
map.put("liLei", liLei);
map.put("mary", mary);
map.put("jack", jack);
// entry遍历
Set<Map.Entry<String, Student>> entries = map.entrySet();
Iterator<Map.Entry<String, Student>> iterator = entries.iterator();
while (iterator.hasNext()) {
Map.Entry<String, Student> next = iterator.next();
System.out.println(next.getKey());
System.out.println(next.getValue());
}
}
}
class Student {
public String name;
public int age;
public Student(String name) {
this.name = name;
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return name + " " + age;
}
}
作业:定制排序:
package com.hsf.First;/*
* @author HSF
* @version 8.0
*/
import java.util.ArrayList;
import java.util.Comparator;
public class HomeWork {
public static void main(String[] args) {
Employee liLei = new Employee("liLei", 3000, new MyDate(2020, 1, 1));
Employee Mary = new Employee("Mary", 9000, new MyDate(2022, 3, 1));
Employee Jack = new Employee("liLei", 6000, new MyDate(2020, 1, 2));
ArrayList<Employee> employees = new ArrayList<>();
employees.add(liLei);
employees.add(Mary);
employees.add(Jack);
// 作业要求:定制排序
// 调用ArrayList的sort方法,传入comparator对象,先按照name进行排序,如果name相同,则按生日日期进行排序。
employees.sort(new Comparator<Employee>() {
@Override
public int compare(Employee o1, Employee o2) {
// 先比较name
int i = o1.getName().compareTo(o2.getName());
if (i != 0) {
return i;
}
// 再比较生日
return o1.getBirthday().compareTo(o2.getBirthday());
}
});
System.out.println(employees);
}
}
class Employee {
private String name;
private double dal;
private MyDate birthday;
public Employee(String name, double dal, MyDate birthday) {
this.name = name;
this.dal = dal;
this.birthday = birthday;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getDal() {
return dal;
}
public void setDal(double dal) {
this.dal = dal;
}
public MyDate getBirthday() {
return birthday;
}
public void setBirthday(MyDate birthday) {
this.birthday = birthday;
}
@Override
public String toString() {
return "Employee{" +
"name='" + name + '\'' +
", dal=" + dal +
", 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 int compareTo(MyDate o) {
int yearMinus = year - o.getYear();
if (yearMinus != 0) {
return yearMinus;
}
int MonthMinus = month - o.getMonth();
if (MonthMinus != 0) {
return MonthMinus;
}
return day - o.getDay();
}
@Override
public String toString() {
return "MyDate{" +
"year=" + year +
", month=" + month +
", day=" + day +
'}';
}
}
1、自定义泛型类:
class Tiger<T,R,E> {
T name;
R age;
E gender;
public Tiger(T name, R age, E gender) {
this.name = name;
this.age = age;
this.gender = gender;
}
// 不能初始化:因为数组在new的时候,不能确定T的类型,就无法开辟空间。
T[] ts = new T[8];
T[] ts1; // 可以定义
}
注意点:
1、类后面有泛型,我们称为自定义泛型。
2、T,R,E 泛型标识符,可以写多个。
3、普通成员也可以使用泛型。
4、使用泛型的数组不能初始化。
5、静态方法和静态属性不能使用泛型:
a、因为静态成员是在类加载的时候执行,而泛型是在类创建的时候指定,而类加载 又先于对象创建,因此在类加载的时候无法知道成员类型,无法进行初始化。
6、如果创建对象时没有指定泛型,默认为Object。
2、自定义泛型接口:
如果没有指定类型,默认是Objectl类型:
class IComputer implements IUsb<Object, Object>
// 实现泛型接口后,String--E;Integer -- T;
class IComputer implements IUsb<String, Integer> {
@Override
public String get(Integer integer) {
return null;
}
@Override
public void hi(Integer integer) {
}
@Override
public void run(String e1, String e2, Integer t1, Integer t2) {
}
}
interface IUsb<E,T> {
// E name; 普通属性不能使用泛型,以为接口中属性默认是静态的
// 抽象方法
E get(T t);
void hi(T t);
void run(E e1, E e2, T t1, T t2);
// 默认方法
default E method(T t) {
return null;
}
}
3、自定义泛型方法:
package com.hsf.First;/*
* @author HSF
* @version 8.0
*/
public class Method_ {
public static void main(String[] args) {
Animal<String> animal = new Animal<>();
animal.eat("jack", 12);
}
}
class Animal<E> {
public void run() {}; // 普通方法
// 泛型方法:使用了一个泛型类声明的泛型E,也是用了一个自己声明的泛型T
public<E, T> void eat(E e, T t) {
System.out.println(e.getClass()); // string
System.out.println(t.getClass()); // integer
}
// 泛型方法:两个都是自己声明的泛型K,T
public<K, T> void hi(K k, T t) {}
// 使用了泛型,不叫泛型方法,只能在泛型类中使用,因为只能用泛型类声明的泛型。
public void say(E e) {}
}
class People<E,K> {
}
4、泛型的继承和通配符:
1、泛型不具备继承性,不可被继承。
List<Object> lsit= new ArrayList<String>(); // 错误string虽然是object子类,但是不可被继承
2、通配符:
a、<?>:表示支持任意泛型类型。
b、<? extends A>:支持A类以及A类的子类,规定了泛型的上限:即最上面只能到A类。
c、<? super A>:支持A类及A类的父类,规定了泛型的下限:即最底下只能到A类。