(java)泛型

1.泛型的简介

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

泛型总结下来就是:类型参数化

定义期间,有些东西不确定是什么类型,在使用期间确定, 这样就可以使用泛型。 给形参赋值具体类型名

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

 2.泛型的定义

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

泛型参数,只能赋值引用类型,不能赋值八大基本数据类型

案例:

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

3.泛型的应用

   (1)泛型类的应用:

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

(1)定义一个泛型类:

public class Person<T> {
    private T idCard;

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

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

小贴士: 实例化过程中,可以只在一边给泛型参数赋值,但是两边的尖括号都不能省略

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

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

(3)在继承过程中,子类也可以有自己的泛型参数,即把子类的泛型参数赋值给父类的泛型参数

 下面例子就是E赋值了T。

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

(4)如果子类在定义期间,没有给泛型父类的泛型参数赋值,那么默认就是Object类型

class President extends Person{
    public President(Object idCard){
        super(idCard);
    }

(2)泛型接口:泛型用在接口上

用法和泛型类,一模一样。

1.定义一个泛型接口

public interface MyComparable<T,M> {
    /**
     * 两种类型进行比较
     * @param o1
     * @param o2
     * @return
     */
    public int mycompare(T o1, M o2);
}

2.子类实现接口: 通常子类要给泛型接口的泛型参数赋值具体类型名(如果不指定具体泛型参数,默认就是Object类型)

下面案例,就是给T和M 都赋值了Employee这个类型,两个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;
    }

}

 测试:

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);

        //使用比较器接口,来重新定义比较规则   :  从泛型的角度来说,在实例化泛型接口时,要给泛型参数传具体类型 ,这里传的是Employee类型
        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));

    }

(3)泛型方法的应用:位置位于返回值类型的前面

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

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

}

定义一个Ca类型:要实现两个对象的比较,必须重写equals和hashCode,

class Cat{
    String name;
    public Cat(String name) {
        this.name = name;
    }
//要实现两个对象的比较,必须重写equals和hashCode,即默认的比较规则不适用了。

    @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);
    }

4.泛型通配符 :?

泛型通配符用 ? 表示,代表不确定的类型,是泛型的一个重要组成。 在调用时,表示我不关心具体类型。

1.简单的应用,设置一个方法实现把集合元素打印到控制台,不确定是什么类型的

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);//1  2  3//打印成功

        List<Long> ns = new ArrayList<Long>();
        ns.add(1L);
        ns.add(2L);
        ns.add(3L);
        MyUtil.print(ns);// 1 2 3//打印成功
    }

也可以使用通配符规定调用时,传入的类型的范围,即上边界,和下边界。

1.上边界

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

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

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

测试:最高只能是Number类型

        //上边界的测试:
        print2(new ArrayList<Long>());
        print2(new ArrayList<Number>());
        //print2(new ArrayList<Object>());  最高到达Number类型

2.下边界

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

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

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

 测试:最低只能是Interger类型

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

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

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值