Java泛型基础

2022-07-19  本文已影响0人  Tinyspot

Preface

1. 基本概念

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 泛型方法

语法:[修饰符] [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 类型通配符(?)

泛型类型不管继承关系,只管严格的匹配
例如: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 ?

3.4 类型通配符 vs 泛型方法

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

References

结束语

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

上一篇下一篇

猜你喜欢

热点阅读