美文网首页
Java泛型基础

Java泛型基础

作者: Tinyspot | 来源:发表于2022-07-19 14:17 被阅读0次

Preface

  • Generic Types
  • type parameter names are single, uppercase letters
  • The most commonly used type parameter names are:
    • E - Element (used extensively by the Java Collections Framework)
    • K - Key
    • N - Number
    • T - Type
    • V - Value
    • S,U,V etc. - 2nd, 3rd, 4th types

1. 基本概念

  • 本质:泛型就是类型参数化,处理的数据类型不是固定的,而是可以作为参数传入
  • 没有指定具体数据类型时,默认操作类型是 Object
  • 只支持类类型,不支持基本类型
  • 同一泛型类,本质上都是相同类型
  • 好处
    • 保证类型安全:泛型约束了变量的类型,保证了类型的安全性(在编译时就可检查类型匹配)
    • 提高代码的重用性
    • 消除强制类型转换:未使用泛型前,需要强制类型转换

2. 泛型基本用法

泛型类,是在实例化类的时候指明泛型的具体类型;
泛型方法,是在调用方法的时候指明泛型的具体类型,更加灵活

2.1 泛型类

泛型类:类名<T>,T 是类型占位符,表示一种引用类型

// T 表示类型参数
public class Result<T> {
    private boolean success;
    private String statusCode;
    private String message;
    // 方式一:作为变量类型
    private T data;

    // 方式二:作为方法参数
    protected void success(T data) {
        setData(data);
        setSuccess(true);
    }
    // 方式三:作为方法返回值
    public T getData() {
        return data;
    }
    // Getter/Setter ...
}
class MultiResult<T, S, U> {
    private T first;
    private S second;
    private U third;
}

使用示例:

public interface BusinessService {
    Result<User> queryUser();
    Result<Order> queryOrder();
}

2.2 泛型方法

  • 泛型方法,就是在声明方法时定义一个或多个类型形参
  • 当方法中的类型与类冲突时,方法中的 T 会覆盖类的 T

语法:[修饰符] [static] <T, R> 返回值类型 method(...) {}
注:<T> 必须存在,并且在方法返回值之前

public <T> T show(T t) {
    return t;
}

Demo demo = new Demo();
String str = demo.show("str");

<T> 声明此方法为泛型方法,指定方法类型,此类型既可以在参数中用,也可以在返回值中用

public static <T> T test(Class<T> clazz) {
    try {
        return clazz.newInstance();
    } catch (Exception e) {
        return null;
    }
}

public static <T> T test(Object obj) {
    return (T) obj;
}

// 方法签名 - 多类型  <T, R>
public <T, R> R count(T t) {
}
public interface Service {
    <T> ResultDTO<T> execute(ServiceCallback<T> callback, String serviceName);
}
public interface ServiceCallback<T> {    
}

2.3 泛型接口

public interface QueryService<T, R> {
    R execute(T obj);
}

泛型类派生子类,见 Java 泛型详解

public class QueryServiceImpl implements QueryService<String, Result> {
    @Override
    public Result execute(String obj) {
        return null;
    }
}

public class QueryServiceImpl2<T, R> implements QueryService<T, R> {
    @Override
    public R execute(T obj) {
        return null;
    }
}
QueryServiceImpl queryService = new QueryServiceImpl();
Result result = queryService.execute("111");

QueryServiceImpl2<String, Result> queryService2 = new QueryServiceImpl2<>();
Result result2 = queryService2.execute("222");

2.4 扩展:泛型接口和泛型方法混合

public interface Stream<T> extends BaseStream<T, Stream<T>> {
    <R> Stream<R> map(Function<? super T, ? extends R> mapper);
    <R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper);
}

3. 泛型通配符

3.1 类型通配符(?)

  • In generic code, the question mark (?), called the wildcard, represents an unknown type
  • List<?> 表示未知类型元素的 List,仅表示它是各种泛型 List 的父类,并不能把元素加入到其中

泛型类型不管继承关系,只管严格的匹配
例如:String 是 Object 的子类,但 List<String> 不是List<Object>类的子类
编译报错:不兼容的类型: java.util.List<java.lang.String>无法转换为java.util.List<java.lang.Object>

可将 List<Object> 改为 List<?>,但还需进行强制类型转换
改进,使用受限制通配符List<? extends Shape>,注意:因无法准确知道这个类型是什么,所以不能把 Shape 对象或其子类的对象加入这个泛型集合中

3.2 受限制通配符(泛型约束)

上界通配符 <? extends Type> : Get First,协变,无法确定子类类型,只读
下界通配符 <? super Type>: Put First,逆变,无法确定父类,只写

上界通配符

public static void main(String[] args) {
    // public interface List<E> extends Collection<E> {}
    List<String> strings = new ArrayList<>();
    List<Object> objects = new ArrayList<>();

    test(strings, objects); // 类型推断失败,编译报错
    test2(strings, objects);
}
public static <T> void test(Collection<T> from, Collection<T> to) {
    for (T ele : from) {
        to.add(ele);
    }
}
/**
 * Collection<? extends T> 类型改为 T 的子类
 *
 * Collection<? extends T>: 类型通配符的表示方式
 * Collection<T> to: 泛型方法的表示方式
 */
public static <T> void test2(Collection<? extends T> from, Collection<T> to) {
    for (T ele : from) {
        to.add(ele);
    }
}
public static void main(String[] args) {
    // public final class Integer extends Number implements Comparable<Integer> {}
    List<Number> numbers = new ArrayList<>();
    List<Integer> integers = new ArrayList<>();

    Number copy = copy(numbers, integers);
    Integer integer = copy2(numbers, integers);
    System.out.println(copy);
}
/**
 * 返回类型只会与 dest 相同
 */
public static <T> T copy(Collection<T> dest, Collection<? extends T> src) {
    T last = null;
    for (T ele : src) {
        last = ele;
        dest.add(ele);
    }
    return last;
}
/**
 * 改进:不管src集合元素的类型是什么,只要dest集合元素的类型与前者相同或是前者的父类即可
 * @return
 */
public static <T> T copy2(Collection<? super T> dest, Collection<T> src) {
    T last = null;
    for (T ele : src) {
        last = ele;
        dest.add(ele);
    }
    return last;
}
// 思考:copy(List<? super T> dest, List<? extends T> src)

3.3 T vs ?

  • ? 和 T 都表示不确定的类型,区别在于我们可以对 T 进行操作,但是对 ?不行
  • T 是一个 确定的 类型,通常用于泛型类和泛型方法的定义
  • ?是一个 不确定 的类型,通常用于泛型方法的调用代码和形参,不能用于定义类和泛型方法。

3.4 类型通配符 vs 泛型方法

  • 类型通配符既可以在方法签名中定义形参的类型,也可以用于定义变量的类型;但泛型方法中的类型形参必须在对应方法中显式声明
  • 如果某个方法中一个形参(a)的类型或返回值的类型依赖于另一个形参(b)的类型,则形参(b)的类型声明不应该使用通配符
  • 扩展:何时使用泛型方法?何时使用类型通配符?

List<T> 中的 T 是一个形参,可以理解为一个占位符(表示一种引用类型),被使用时,会在程序运行的时候替换成具体的类型,比如替换成String,Integer之类的。
List<?> 中的 ? 是一个实参,这是Java定义的一种特殊类型,比Object更特殊,就像一个影子。比如List<Object>和List<String>是没有父子关系的,这是两个类型,List<Object>类型和List<String>类型;但是List<?> 是 List<String>的父类

References

结束语

碎片时间很难用来做系统化学习,所以纯移动端的内容做到最后都会变成以技术的名义养生:知道了各种奇技淫巧,然而并没有什么用。
当然作为知识树的查漏补缺还是不错的,前提是已经完成了系统学习。

相关文章

  • Java 泛型

    导读 移动开发知识体系总章(Java基础、Android、Flutter) 为什么会有泛型? 泛型类 泛型方法 泛...

  • Java泛型教程

    Java泛型教程导航 Java 泛型概述 Java泛型环境设置 Java泛型通用类 Java泛型类型参数命名约定 ...

  • Java基础之泛型

    Java基础之泛型 泛型基本介绍 简单介绍在jdk1.6之前,还没有使用到泛型,Java类型分为原始类型、复杂类型...

  • spring 泛型处理

    java 泛型基础 泛型类型:泛型类型是在类型上参数化的泛型类或接口 泛型使用场景编译时前类型检查。定义为 Col...

  • Java泛型基础

    Java泛型基础 1. 认识泛型 泛型是在JDK1.5之后增加的新功能. 泛型可以解决数据的安全性问题, 主要的原...

  • 一文带你认识Java泛型基础

    Java泛型基础 1. 认识泛型 泛型是在JDK1.5之后增加的新功能. 泛型可以解决数据的安全性问题, 主要的原...

  • 第二十八课:泛型

    泛型出现之前 泛型出现之后 Java深度历险(五)——Java泛型

  • Java基础(一)

    Java要点1 JAVA基础 1.对抽象、继承、多态的理解 2.泛型的作用及使用场景 1.Java泛型是JDK1....

  • 详解Java泛型之3——十分钟理解泛型擦除

    前面我们介绍了泛型以及通配符的基础概念,可以参考文章: 详解Java泛型之1——入门泛型必懂的知识点[https:...

  • Kotlin 泛型

    说起 kotlin 的泛型,就离不开 java 的泛型,首先来看下 java 的泛型,当然比较熟悉 java 泛型...

网友评论

      本文标题:Java泛型基础

      本文链接:https://www.haomeiwen.com/subject/tyvhirtx.html