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 集合。

相关推荐
述雾学java12 分钟前
Spring Boot 整合 Spring Security
java·spring boot·spring security
风象南23 分钟前
SpringBoot解决依赖冲突的5个技巧
java·spring boot·后端
天天摸鱼的java工程师24 分钟前
优秀后端如何定义返回值?
java·后端
都叫我大帅哥24 分钟前
Java的synchronized:从入门到“秃头”的终极指南
java
AI糊涂是福1 小时前
MATLAB语言教程:从入门到精通的全面指南
开发语言·matlab·信息可视化
jz_ddk2 小时前
[学习] C语言多维指针探讨(代码示例)
linux·c语言·开发语言·学习·算法
He_k4 小时前
‘js@https://registry.npmmirror.com/JS/-/JS-0.1.0.tgz‘ is not in this registry
开发语言·javascript·ecmascript
星夜9824 小时前
C++回顾 Day6
开发语言·数据结构·c++·算法
琢磨先生David5 小时前
责任链模式:构建灵活可扩展的请求处理体系(Java 实现详解)
java·设计模式·责任链模式
UpUpUp……6 小时前
C++复习
开发语言·c++·笔记