java之泛型

一、泛型的简介

1.1 什么是泛型

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

在之前,不管我们在定义成员变量时,还是方法的形参时,都要规定他们的具体类型。

int n1;

String n2;

确定了n1为int类型,n2为String类型。这样参数类型一旦确定就传不了其他类型的值了

这样很不灵活,那么就产生了泛型。

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

一句话:就是类型参数化。

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

1.2 泛型的定义

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

public class Person<T>{}

public class Person<T,M>{}

public interface Calculate<T> {

public T calculate(T n1, T n2);

}

二、泛型的应用

2.1 泛型类的应用

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

复制代码
public class Person <T,M>{//在类上定义泛型的类型的变量,T,M代表未来将要使用的具体类型
    T name;
    M age;
    public Person(){}
    public Person(T name ,M age){//初始化
        this.name =name;
        this.age =age;
    }
}

在实例化时,指定具体类型

复制代码
public static void main(String[] args) {
        Person<String,Integer> b=new Person<>("lily",10);
    }
}

在继承时,指定具体类型

复制代码
public class Student extends Person<String,Short>{
    Student (String name,Short age){
        super(name,age);
}

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

2.2 泛型接口的应用

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

public interface MyComparator <T,M>{

int compare(T t,M m);

T calculate(T t,M m);

}

实例化时

复制代码
public static void main(String[] args) {
   MyComparator comparator = new MyComparator<Integer,Integer>() {
      public int compare(Integer t1, Integer t2) {
         return t1.compareTo(t2);
      }
      public Integer calculate(Integer t1, Integer t2) {
         return t1+t2;
      }
   };
}

子类实现接口时

复制代码
//实现子类时,不指定具体泛型,默认就是Object类型了。
class Teacher implements MyComparator{
​
    @Override
    public int compare(Object o, Object o2) {
        //两个teacher在比较时,要不要强转,思考一下,会不会很麻烦。
        return 0;
    }
​
    @Override
    public Object calculate(Object o, Object o2) {
        return null;
    }
}

2.3 泛型方法的应用

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

public class MyUtil {

//泛型方法,泛型定义在返回值类型前面。

public static <T> boolean eq(T a, T b) {

return a.equals(b);

}

}

public class Employee{

String name;

public Employee(String name){

this.name = name;

}

@Override

public boolean equals(Object o) {

if (this == o) return true;

if (o == null || getClass() != o.getClass()) return false;

Employee employee = (Employee) o;

return Objects.equals(name, employee.name);

}

}

测试:

public static void main(String[] args) {

//调用泛型方法时,不需要传入具体类型名,只需要传入具体类型的值

//会主动推导出具体的类型。

boolean f = MyUtil.eq("abc","hello");

System.out.println("f = " + f);

Employee e1 = new Employee("张三");

Employee e2 = new Employee("张三");

f = MyUtil.eq(e1,e2);

System.out.println("f = " + f);

}

三、泛型通配符

3.1 简介

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

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

3.2 简单应用

比如,你要写一个通用方法,把传入的 List 集合输出到控制台,那么就可以这样做。

public class Application {

public static void print(List<?> list) {

for (int i = 0; i < list.size(); i++) {

System.out.println(list.get(i));

}

}

public static void main(String[] args) {

// Integer 集合,可以运行

List<Integer> intList = Arrays.asList(0, 1, 2);

print(intList);

// String 集合,可以运行

List<String> strList = Arrays.asList("0", "1", "2");

print(strList);

}

}

List<?> list 代表我不确定 List 集合装的是什么类型,有可能是 Integer,有可能是 String,还可能是别的东西。但我不管这些,你只要传一个 List 集合进来,这个方法就能正常运行。

3.3 上边界

上边界,代表类型变量的范围有限,只能传入某种类型,或者它的子类。

利用 <? extends 类名> 的方式,可以设定泛型通配符的上边界。

public class TopLine {

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

for (int i = 0; i < list.size(); i++) {

System.out.println(list.get(i));

}

}

public static void main(String[] args) {

// Integer 是 Number 的子类,可以调用 print 方法

print(new ArrayList<Integer>());

// String 不是 Number 的子类,没法调用 print 方法

print(new ArrayList<String>());

}

}

你想调用 print() 方法中,那么你可以传入 Integer 集合,因为 Integer 是 Number 的子类。但 String 不是 Number 的子类,所以你没法传入 String 集合。

3.4 下边界

下边界,代表类型变量的范围有限,只能传入某种类型,或者它的父类。

利用 <? super 类名> 的方式,可以设定泛型通配符的下边界

public class LowLine {

public static void print(List<? super Integer> list) {

for (int i = 0; i < list.size(); i++) {

System.out.println(list.get(i));

}

}

public static void main(String[] args) {

// Number 是 Integer 的父类,可以调用 print 方法

print(new ArrayList<Number>());

// Long 不是 Integer 的父类,没法调用 print 方法

// print(new ArrayList<String>());

}

}

你想调用 print() 方法中,那么可以传入 Number 集合,因为 Number 是 Integer 的父类。但 Long 不是 Integer 的父类,所以你没法传入 Long 集合。

相关推荐
向宇it3 分钟前
【零基础入门unity游戏开发——2D篇】2D 游戏场景地形编辑器——TileMap的使用介绍
开发语言·游戏·unity·c#·编辑器·游戏引擎
DARLING Zero two♡7 分钟前
C++类间的 “接力棒“ 传递:继承(上)
开发语言·c++·继承·里氏替换原则
会讲英语的码农9 分钟前
如何学习C++以及C++的宏观认知
开发语言·c++·学习
martian66513 分钟前
Spring Boot后端开发全攻略:核心概念与实战指南
java·开发语言·spring boot
跟着珅聪学java2 小时前
spring boot +Elment UI 上传文件教程
java·spring boot·后端·ui·elementui·vue
我命由我123452 小时前
Spring Boot 自定义日志打印(日志级别、logback-spring.xml 文件、自定义日志打印解读)
java·开发语言·jvm·spring boot·spring·java-ee·logback
lilye662 小时前
程序化广告行业(55/89):DMP与DSP对接及数据统计原理剖析
java·服务器·前端
徐小黑ACG3 小时前
GO语言 使用protobuf
开发语言·后端·golang·protobuf
0白露4 小时前
Apifox Helper 与 Swagger3 区别
开发语言
Tanecious.5 小时前
机器视觉--python基础语法
开发语言·python