java9-泛型

1.泛型的简介

1.1 什么是泛型

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

在这之前,不管我们在定义成员变量时,还是方法的形参时,都要规定他们的具体类型。所以提出猜想,有没有一种可能,一次声明,就可以给各种各样的值呢?所以,泛型这个概念就出来了。

泛型的定义:        

        我们在定义一个语法结构时,不用指明具体类型,而是先定义一个类型变量,在真正使用的时候再确定该变量的具体类型。

总结: 类型参数化

两个参数化:

        数据参数化:  就是使用形参接收具体数据(实际参数)
        类型参数化:  就是使用形参接收具体类型。

1.2 泛型的定义

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

public class Test1<T> {
}
class Person<T,M>{
}
class Calculate<T>{
    public T calculate(T a, T b){
        return a;
    }
}

2.泛型的应用 

2.1 泛型类的应用

        当我们将泛型用在类上时,这个类就叫做泛型类。

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

演示代码:

import java.util.Date;

public class Person<T> {
    private T idCard;
    public Person(){

    }

    public Person(T idCard){
        this.idCard = idCard;
    }

    public static void main(String[] args) {
        //创建一个Person对象。需要给泛型参数赋值具体类型
        Person p = new Person<String>("cds123");
        Person<String> p2 = new Person<>("cds122");
        // 泛型参数,只能赋值引用类型,不能赋值八大基本数据类型
        Person<Long> p3 = new Person<>(3215466L);
        Date date = new Date();
        //小贴士:    实例化过程中,泛型只在一边给泛型参数赋值,但是两遍的尖括号都不能省略。
        Person<Date> p4 = new Person<>(date);
    }
}

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

class Student extends Person<Integer>{
    public Student(Integer idCard){
        super(idCard);
    }
}
/*
子类的泛型参数可以给父类的泛型参数赋值。
下面的例子就是E赋值给了T。
 */

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

/*
如果子类在定义期间,没有给泛型父类的泛型参数赋值,那么默认就是Object类型
 */
class Persident extends Person{
    public Persident(Object idCard){
        super(idCard);
    }

}

总结:

在实例化时,要给泛型参数赋具体值。实例化时两边的类名都可以赋值,也可以一边赋值,但是两边的尖括号不能去掉。在继承时也要赋值,如果没有赋值,那就默认object类型。也可以将子类的泛型赋值给父类。

2.2 泛型接口的应用

         将泛型用在接口上时,这个接口就叫做泛型接口。 泛型定义在接口名后。 用法和泛型类,一模一样。

测试代码:

import java.util.Arrays;
import java.util.Comparator;

/**
 * 泛型接口,泛型用在接口上,就叫泛型接口。
 * @param <T>
 */
public interface MyComparable<T,M> {
    /**
     * 两种类型进行比较
     * @param o1
     * @param o2
     * @return
     */


    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("建模",19);
        employees[2] = new Employee("ez",17);

        //使用比较器接口,来重新定义比较规则:  从泛型的角度来说,在实例化接口时,要给泛型参数传具体类型。
        Comparator c = new Comparator<Employee>(){
            //重写比较器里面的compare方法
            public int compare(Employee o1, Employee o2) {
                //调用了自定义的员工类里的比较方法。
                return o1.name.compareTo(o2.name);
            }
        };


        Arrays.sort(employees);
        System.out.println(Arrays.toString(employees));
    }


}
//子类实现接口 : 通常子类要给泛型接口的泛型参数赋值具体类型名。
//下面案例,就是给T和M都赋值了Employee这个类型。
class Employee implements MyComparable<Employee,Employee>, Comparator<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;
    }

    @Override
    public int compare(Employee o1, Employee o2) {
        return mycompare(o1,o2);
    }

}

2.3 泛型方法的应用

        泛型不仅能用在类和接口上,还可以用在方法上。 需要把泛型定义在返回值类型前面。

测试代码:

import java.util.Objects;

public class MyUtil {

    public static <T> boolean equals(T t1,T t2){
        return t1.equals(t2);
    }

    public static void main(String[] args) {
        Cat cat = new Cat("咪咪");
        Cat cat1 = new Cat("咪咪");

        //泛型方法在调用期间,不需要指定具体类型,只需要传入具体对象
        //泛型方法调用期间,并没有给泛型参数赋值。下面的案例是c1给t1,c2给t2赋值,没有给T赋值。
        boolean a = MyUtil.equals(cat, cat1);
        System.out.println("equals"+a);
    }
}

class Cat{
    String name;
    public Cat(){
    }
    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);
    }
}

注意:

在方法调用期间,不需要给泛型具体赋值,只需要传入变量即可。

3.泛型通配符

3.1 简介

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

3.2 简单应用 

import java.util.ArrayList;
import java.util.List;

/*
    泛型通配符: ?  用于表明不关心调用时的具体类型。
 */

public class MyUtil {
    /**
     * 将集合元素打印到控制台上
     */
    public static void print(List<?> lists){
        for(int i = 0; i<lists.size();i++){
            System.out.println(lists.get(i));
        }
    }

    /**
     * 上边界的定义: <? extends Number>
     *              具体使用的时候,可以是上边界的任何子类型或者是本类型。
     * @param list
     */

    public static void print2(List<? extends Number> list){

    }

    /**
     * 下边界的定义: <? super 具体类名>
     *              具体使用的时候,可以是下边界的任何父类型或者本类型。
     * @param list
     */
    public static void print3(List<? super Integer> list){
        for(int i = 0; i<list.size();i++){
            System.out.println(list.get(i));
        }
    }

    public static void main(String[] args) {
        List<Long> ns = new ArrayList<Long>();
        ns.add(1L);
        ns.add(2L);//注意 L 是Long类型不是long。
        ns.add(3L);
        MyUtil.print(ns);

        print2(new ArrayList<Long>());
        print2(new ArrayList<Number>());
//        print2(new ArrayList<Object>());最高到达Number类型

        //下边界的测试
        print3(new ArrayList<Number>());
        print3(new ArrayList<Object>());
        print3(new ArrayList<Integer>());
//        print3(new ArrayList<Long>());//Long和Integer没有关系。


    }

}

3.3 总结

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

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

确定类型变量这一步中,你可以用泛型通配符来限制泛型的范围,从而实现一些特殊算法。(方法 <? extends 类名>上边界、 <? super 类名>下边界(都包括类名))。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值