泛型的小结

本文详细介绍了Java泛型的概念、相关术语、语法,包括泛型类、接口、方法以及上界和下界的使用。此外,还提供了泛型在编程中的作用和一些使用建议,旨在提升类型安全和API灵活性。
摘要由CSDN通过智能技术生成

什么是泛型

从JDK1.5开始引入泛型(generic)语法。对类型实现了参数化,编辑器根据上下文推导出实参类型,省略了实参类型的填写。

泛型的相关概念

术语准备

术语范例说明
参数化的类型List<String>表示List中元素的类型为String的容器
实际类型参数String泛型使用时的实参
泛型List<E>声明中具有一个或者多个类型参数的类或接口即泛型
形式类型参数E泛型声明中的形参
原生态类型ListRaw Type。即没有使用泛型,主要是为了兼容之前大量没有使用泛型的代码。
有限制类型参数<E extends Number>只接受 Number 的子类型或者 Number 本身作为 E 的类型实参。 范围上界
递归类型限制<T extends Comparable<T>>只接收实现了Comparable接口的。范围上界
有限制通配符类型List<? extends Number>只接受Number 或其子类类型。范围上界
无限制通配符类型List<?>可以接收任意类型
类型令牌String.class类的字面用在方法传递时的称呼
泛型方法static <E> List<E> aslist(E[] a)

泛型的编译时进行泛型擦除

在这里插入图片描述

程序编写的时候可以指定了泛型的元素类型为String类型,在编译的时候就变成Object。

擦除机制,在编译的过程中,将泛型转换(所有类型)为Object的机制。

泛型的作用

  • 加强类型安全检查:存放元素时,指明容器接收的对象的类型,让编译器进行类型安全检查
  • 无需手动进行类型转换,加快运行效率:取出元素时,无需手动进行类型转换,加快运行效率

在这里插入图片描述

进行类型安全检查之后,会在编译过程中反馈错误,减少运行时的错误。

泛型的使用

泛型常用的形参大写字母

  • E 表示 Element
  • K 表示 Key
  • V 表示 Value
  • N 表示 Number
  • T 表示 Type
  • S, U, V - 第二、第三、第四个类型

泛型类语法

class 类名称 <泛型标识、泛型标识,...> {
    private 泛型标识 变量名;
    ......
}

泛型接口语法

interface 接口名称 <泛型标识,泛型标识,...>{
        泛型标识 方法名();
}      

泛型方法语法

方法限定符 <类型形参列表> 返回值类型 方法名称(形参列表){

}

泛型类的简单示例

// 定义泛型类
public class GenericClass<T, N> {
    private T value1;
    private N value2;

    // 使用泛型类型作为形参类型和返回值
    public T getValue1() {
        return value1;
    }

    public void setValue1(T value1) {
        this.value1 = value1;
    }

    public N getValue2() {
        return value2;
    }

    public void setValue2(N value2) {
        this.value2 = value2;
    }

    public static void main(String[] args) {
        GenericClass<Integer, String> s1 = new GenericClass<>();
        s1.setValue1(1);
        s1.setValue2("XX");
        System.out.println(s1.getValue1() + ":" + s1.getValue2());
        GenericClass<Double, String> s2 = new GenericClass<>();
        s2.setValue1(1.1);
        s2.setValue2("YY");
        System.out.println(s2.getValue1() + ":" + s2.getValue2());
    }
}

泛型接口的简单示例

在接口中定义的类型参数可以在接口中当做类型使用,任何需要类型的地方都可以使用类型参数替代

// 定义泛型接口的类型参数为T
public interface Humans<T> {
    // 使用类型参数T作为方法参数类型
    void say(T t);
	// 使用类型参数T作为返回值类型
    T get();
}

// 实现泛型接口的时候传入类型
public class BlackHuman implements Humans<BlackHuman> {
    public final String name;

    public BlackHuman(String name) {
        this.name = name;
    }

    @Override
    public void say(BlackHuman yellowHuman) {
        System.out.println("我叫" + this.name + ",是黑种人");
    }

    @Override
    public BlackHuman get() {
        return this;
    }
}

public class Demo {

    public static void main(String[] args) {
        BlackHuman blackHuman = new BlackHuman("乔丹");
        blackHuman.say(blackHuman);
        System.out.println(blackHuman.get().name);
    }
}

基于泛型的简单工厂方法

public interface IService {
    String getServiceName();
}
public class MyService1 implements IService {
    @Override
    public String getServiceName() {
        return "My Service1.";
    }
}
public class MyService2 implements IService {
    @Override
    public String getServiceName() {
        return "My Service2.";
    }
}
package com.donny.demo;

/**
 * @author 1792998761@qq.com
 * @description
 * @date 2023/10/8
 */
public class ServiceFactory {

    private ServiceFactory() {
    }

    // 简单写法-通过额外参数表名服务
    public static IService getService(String key) {
        if ("MyService1".equals(key)) {
            return new MyService1();
        } else if ("MyService2".equals(key)) {
            return new MyService2();
        } else {
            return null;
        }
    }

    // 使用泛型方法
    public static <T> T getInstance(Class<T> className) {
        T result = null;
        try {
            result = className.newInstance();
        } catch (IllegalAccessException | InstantiationException e) {
            e.printStackTrace();
        }
        return result;
    }
}
public class Demo {

    public static void main(String[] args) {
        IService service1 = ServiceFactory.getInstance(MyService1.class);
        IService service2 = ServiceFactory.getInstance(MyService2.class);
        System.out.println(service1.getServiceName());
        System.out.println(service2.getServiceName());
    }
}

泛型的上界与下界

由于java中继承的特性

上界语法

class 类名称 <类型标识 extends 类型边界> {
    ......
}

类型边界可以是类,也可以是接口。若类型边界是类,那么泛型中的类型只能接受边界类本身或其子类。若类型边界是接口,那么泛型中的类型必须实现了边界接口

// 传入的类型需要是Number或Number的子类
public interface Price<? extends Number> {
}

// 传入的类型需要实现Comparable接口
public class ApplicableTransition<? extends Comparable<E>> {
}

下界语法

class 类名称 <类型标识 super 类型边界> {
    ......
}

类型边界可以是类,也可以是接口。若类型边界是类,那么泛型中的类型只能接受边界类本身或其父类

泛型的一些使用建议

  1. 不使用原生态类型

  2. 消除非受检警告

    可以在类,方法,对象声明上增加注解来消除非受检个告警

    @SuppressWarnings("unchecked")
    
  3. 使用泛型时,列表优先于数组

  4. 利用有限通配符提升api的灵活性

  5. 优先考虑类型安全的异构容器

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

顧棟

若对你有帮助,望对作者鼓励一下

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值