泛型的知识点

一、简介

1.1 什么是泛型

泛型是一种特殊的数据类型。 它是Java 的一个高级特性。在 Mybatis、Hibernate 这种持久化框架,泛型更是无处不在。

我们在定义一个语法结构时,有些东西不确定是什么类型,而是在使用期间确定,那么就不用指明具体类型,这样就可以使用泛型。 给形参赋值具体类型名。

一句话来说就是类型参数化,使用形参接收具体类型。

1.2 泛型的定义

泛型,定义在一对尖括号中,也是一个标识符,遵循大驼峰命名法。通常都是用一个大写字母。

public class Person<T>{}
public class Person<T,M>{}
public interface Calculate<T> {
 	public T calculate(T n1, T n2);
}

二、泛型的应用

2.1 泛型类的应用

泛型类:就是泛型应用在类上。一般在类名后,使用尖括号括起来。用大写字母作为泛型参数。

1)在类中使用泛型参数,来定义变量,因为要给变量初始化,所以构造器中的形参也应该规定为泛型类型。

public class Person<T>{
    private T idCard;
    public Person(T idCard){
    this.idCard = idCard;
    }
}

2)在实例化时,指定具体类型,泛型必须传引用类型,不能是八大基本数据类型。

public static void main(String[] args) {
    //创建一个Person对象,需要给泛型参数赋值具体类型。
    Person<String> p1 = new Person<String>("c1001");
    Person<String> p2 = new Person<>("c1002");
    //泛型参数只能赋值引用类型,不能赋值八大基本数据类型
    Person<Long> p3 = new Person<>(10001L);
    Date date = new Date();
    Person<Date> p4 = new Person<>(date);
}

3)当一个子类继承带有泛型的父类时,一般情况下要给泛型参数赋值具体类型。

class Student extends Person<Integer>{
    public Student(Integer idCard){
        super(idCard);
    }
}

4)子类的泛型参数可以赋值给父类的泛型参数。

下面就是将子类的E赋值给了父类的T:

class Teacher<E> extends Person<E>{
    public Teacher(E idCard){
        super(idCard);
    }
}

5)在继承时,如果不指定具体类型,则默认是Object类型。

class  President extends Person{
    public President(Object idCard){
        super(idCard);
    }
}
小贴士:实例化过程中,可以只在一边给泛型参数赋值,但是两边的尖括号都不能省略。

2.2 泛型接口的应用

泛型接口,就是泛型应用在接口上,泛型定义在接口名后面,用<>括起来,用法与泛型类一致。

public interface MyComparable<T,M> {
    public int mycompare(T o1, M o2);
    public static void main(String[] args) {
        Employee[] employees = new Employee[3];
        employees[0] = new Employee("小张",18);
        employees[1] = new Employee("小王",17);
        employees[2] = new Employee("小李",19);
        //使用比较器接口来重新定义比较规则  : 从泛型的角度来说,在实例化泛型接口时,要给泛型接口传                    具体类型。
        Comparator c = new Comparator<Employee>() {
            //重写比较器里的compare方法
            public int compare(Employee o1, Employee o2) {
                //调用了自定义的员工类里的比较方法
                return o1.mycompare(o1, o2);
            }
        };
        Arrays.sort(employees,c);
        System.out.println(Arrays.toString(employees));
    }
}
子类实现接口:通常子类要给泛型接口的泛型参数赋值具体类型名。
下面案例,就是给T和M都赋值了Employee这个了类型:
class Employee implements MyComparable<Employee,Employee>{
    String name;
    int age;
    public Employee(String name, int age) {
        this.name = name;
        this.age = age;
    }
    public String toString() {
        return "["+name+","+age+"]";
    }
    //在我们自己定义的方法中来实现比较规则
    public int mycompare(Employee o1, Employee o2) {
        return o1.age - o2.age;
    }
}

2.3 泛型方法的应用

泛型方法,就是泛型应用在方法上。需要把泛型定义在返回值类型前面。

泛型方法在调用期间,不需要指定具体类型,只需要传入具体对象,编译器会自动推断对象的类型。

案例演示:定义一个工具类,用于比较两个对象长得是否一样。

public class MyUtil {
    //泛型方法,泛型定义在返回值类型前面。
    public static <T> boolean equals(T t1,T t2){
        return t1.equals(t2);
    }
}
class Cat {
    String name;
    public Cat(String name) {
        this.name = name;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Cat cat = (Cat) o;
        return Objects.equals(name, cat.name);
    }

    @Override
    public int hashCode() {
        return Objects.hashCode(name);
    }
}

测试:

public static void main(String[] args) {
    Cat c1 = new Cat("小黄");
    Cat c2 = new Cat("小黄");
    //泛型方法在调用期间,不需要指定具体类型,只需要传入具体对象,编译器会自动推断对象的类型
    //泛型方法调用期间,并没有给泛型参数赋值。下面的案例是c1给t1,c2给t2赋值,没有给T赋值。
    boolean equals = MyUtil.equals(c1, c2);
    System.out.println("equals: " + equals);
}

2.4 泛型通配符

2.4.1 简介

泛型通配符用?表示,代表不确定的类型,是泛型的一个重要组成。在调用时,表示我不关心具体类型。也可以使用通配符规定调用时,传入的类型的范围,即上边界,和下边界。

//不管List集合里面装的是什么类型,只要传进来的是List集合就可以正常运行。
public static void print(List<?> lists){
    for(int i = 0;i < lists.size();i++){
        System.out.println(lists.get(i));
    }
}

测试:

public static void main(String[] args) {
    List<Integer> nums = new ArrayList<Integer>();
    nums.add(1);
    nums.add(2);
    nums.add(3);
    MyUtil.print(nums);
    List<Long> ns = new ArrayList<Long>();
    ns.add(1L);
    ns.add(2L);
    ns.add(3L);
    MyUtil.print(ns);
}
运行结果:
1
2
3
1
2
3

2.4.2 上边界

上边界的定义: <? extends 具体类名> 

具体调用的时候,可以是上边界的任何子类或者是上边界本身类型。

public static void print2(List<? extends Number> lists) {
    for(int i = 0;i < lists.size();i++){
        System.out.println(lists.get(i));
    }
}

上边界的测试:

print2(new ArrayList<Long>());//Number的子类型,可以。
print2(new ArrayList<Number>());//本类型,可以。
print2(new ArrayList<Object>());//不可以,最高只能到达Number类型,而Object是Number的父类型。

2.4.3 下边界

下边界的定义: <? super 具体类名>

具体调用的时候,可以是下边界的任何父类或者是本类型。

public static void print3(List<? super Integer> lists) {
    for(int i = 0;i < lists.size();i++){
        System.out.println(lists.get(i));
    }
}

下边界的测试:

print3(new ArrayList<Number>());//Number是Integer的父类,可以。
print3(new ArrayList<Long>());//Long和Integer没关系,因此不可以。
print3(new ArrayList<Object>());//Object是Integer的父类,可以。

2.5 总结

泛型是一种特殊类型,你可以把它用在类、接口、方法上,从而实现一些通用算法。

此外,使用泛型有三个步骤:定义类型变量、使用类型变量、确定类型变量。

在确定类型变量时,你可以用泛型通配符来限制泛型的范围,从而实现一些特殊算法。

  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值