Java进阶篇之泛型

🔥 本文由 程序喵正在路上 原创,CSDN首发!
💖 系列专栏:Java入门
🌠 首发时间:2022年9月13日
🦋 欢迎关注🖱点赞👍收藏🌟留言🐾
🌟 一以贯之的努力 不得懈怠的人生

泛型简介

泛型是 JDK5 中引入的特性,它提供了编译时类型安全检测机制,该机制允许在编译时检测到非法的类型,它的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数

一提到参数,最熟悉的就是定义方法时如果有形参,调用此方法时就要传递实参,那么参数化类型该怎么来理解呢?

顾名思义,参数化类型就是将类型由原来的具体的类型参数化,然后在使用/调用时传入具体的类型

这种参数类型可以用在类、方法和接口中,分别被称为泛型类泛型方法泛型接口

泛型的定义格式:

  • <类型>:指定一种类型的格式,这里的类型可以看成是形参
  • <类型1,类型2…>:指定多种类型的格式,多种类型之间用逗号隔开,这里的类型可以看成是形参
  • 将来具体调用的时候给定的类型可以看成是实参,并且实参的类型只能是引用数据类型

以前的写法

import java.util.*;

public class GenericDemo {
    public static void main(String[] args) {
        //创建集合对象
        Collection c = new ArrayList();

        //添加元素
        c.add("hello");
        c.add("world");
        c.add("java");

        //遍历集合
        Iterator it = c.iterator();
        while (it.hasNext()) {
            String s = (String) it.next();
            System.out.println(s);
        }
    }
}

学了泛型以后的写法

import java.util.*;

public class GenericDemo {
    public static void main(String[] args) {
        //创建集合对象
        Collection<String> c = new ArrayList<>();

        //添加元素
        c.add("hello");
        c.add("world");
        c.add("java");

        //遍历集合
        Iterator<String> it = c.iterator();
        while (it.hasNext()) {
            String s = it.next();
            System.out.println(s);
        }
    }
}

泛型的好处:

  • 把运行时期的问题提前到了编译期间
  • 避免了强制类型转换

泛型类

泛型类的定义格式:

  • 格式:修饰符 class 类名<类型> { }
  • 例子:public class Generic<T> { }
    此处 T 可以随便写为任意标识,常见的如 T、E、K、V 等形式的参数用于表示泛型

我们来定义一个泛型类,如下

public class Generic<T> {
    private T t;

    public T getT() {
        return t;
    }

    public void setT(T t) {
        this.t = t;
    }
}

接着测试一波

public class GenericDemo {
    public static void main(String[] args) {
        Generic<String> g1 = new Generic<>();
        g1.setT("小明");
        System.out.println(g1.getT());

        Generic<Integer> g2 = new Generic<>();
        g2.setT(30);
        System.out.println(g2.getT());

        Generic<Boolean> g3 = new Generic<>();
        g3.setT(true);
        System.out.println(g3.getT());
    }
}

结果如下:
在这里插入图片描述

泛型方法

泛型方法的定义格式:

  • 格式:修饰符<类型> 返回值类型 方法名(类型 变量名) { }
  • 例子:public<T> void show(T t) { }

定义一个泛型方法,如下

public class Generic {
    public <T> void show(T t) {
        System.out.println(t);
    }
}

测试一下

public class GenericDemo {
    public static void main(String[] args) {
        Generic g = new Generic();
        g.show("小明");
        g.show(30);
        g.show(true);
        g.show(12.34);
    }
}

没毛病

在这里插入图片描述

泛型接口

泛型接口的定义格式:

  • 格式:修饰符 interface 接口名<类型> { }
  • 例子:public interface Generic<T> { }

我们来写一个泛型接口

public interface Generic<T> {
    void show(T t);
}

写一个类实现这个接口

public class GenericImpl<T> implements Generic<T> {
    @Override
    public void show(T t) {
        System.out.println(t);
    }
}

最后测试这个类

public class GenericDemo {
    public static void main(String[] args) {
        Generic<String> g1 = new GenericImpl<>();
        g1.show("小明");

        Generic<Integer> g2 = new GenericImpl<>();
        g2.show(20);
    }
}

测试成功

在这里插入图片描述

类型通配符

为了表示各种泛型 List 的父类,可以使用类型通配符

  • 类型通配符:<?>
  • List<?>:表示元素类型未知的 List,它的元素可以匹配任何的类型
  • 这种带通配符的 List 仅表示它是各种泛型 List 的父类,并不能把元素添加到其中

如果说我们不希望 List<?> 是任何泛型 List 的父类,只希望它代表某一类泛型 List 的父类,可以使用类型通配符的上限

  • 类型通配符上限:<?extends 类型>
  • List<?extends Number>:表示的类型是 Number 或者其子类型

除了可以指定类型通配符的上限,我们也可以指定类型通配符的下限

  • 类型通配符下限:<?super 类型>
  • List<?super Number>:表示的类型是 Number 或者其父类型

如果你不认识 Number 类,那我们这里就简单说一下,Number 是一个抽象类,也是一个超类(即父类)。Number 类属于 java.lang 包,所有的包装类(如 DoubleFloatByteShortInteger 以及 Long)都是抽象类 Number 的子类

import java.util.*;

public class GenericDemo {
    public static void main(String[] args) {
        //类型通配符:<?>
        List<?> l1 = new ArrayList<Object>();
        List<?> l2 = new ArrayList<Number>();
        List<?> l3 = new ArrayList<Integer>();
        System.out.println("---------------------");

        //类型通配符上限:<? extends 类型>
//        List<? extends Number> l4 = new ArrayList<Object>();   //不可以
        List<? extends Number> l5 = new ArrayList<Number>();
        List<? extends Number> l6 = new ArrayList<Integer>();
        System.out.println("---------------------");
        
        //类型通配符下限:<? super 类型>
        List<? super Number> l7 = new ArrayList<Object>();
        List<? super Number> l8 = new ArrayList<Number>();
//        List<? super Number> l9 = new ArrayList<Integer>();   //不可以
    }
}

可变参数

可变参数又称为参数个数可变,用作方法的形参出现,那么方法参数个数就是可变的了

  • 格式:修饰符 返回值类型 方法名(数据类型... 变量名) { }
  • 例子:public static int sum(int... a) { }

可变参数的注意事项

  • 这里的变量 a 其实是一个数组
  • 如果一个方法有多个参数,包含可变参数,那么可变参数要放在最后
public class ArgsDemo {
    public static void main(String[] args) {
        System.out.println(sum(1, 2, 3));
        System.out.println(sum(1, 2, 3, 4, 5, 6));
        System.out.println(sum(1, 2, 3, 4, 5, 6, 7, 8, 9));
    }

    public static int sum(int... a) {
        int sum = 0;

        for (int i : a) {
            sum += i;
        }

        return sum;
    }
}

在这里插入图片描述

可变参数的使用

Arrays 工具类中有一个静态方法:

  • public static <T> List<T> asList(T... a):返回由指定数组支持的固定大小的列表
  • 返回的列表不能做增删操作,可以做修改操作

List 接口中有一个静态方法:

  • public static <E> List<E> of(E... elements):返回一个包含任意数量元素的不可变列表
  • 返回的列表不能做增删改操作

Set 接口中有一个静态方法:

  • public static <E> Set<E> of(E... elements):返回一个包含任意数量元素的不可变集合
  • 返回的集合不能做增删操作,集合没有修改的操作
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

程序喵正在路上

你的鼓励是我创作最大的动力

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

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

打赏作者

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

抵扣说明:

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

余额充值