张小飞的Java之路——第三十六章——泛型方法、接口

文章详细介绍了Java中的泛型概念,包括泛型方法如何提高代码复用,泛型接口的使用,以及通配符在限制类型时的作用。讨论了泛型的上限和下限,解释了它们在处理数据类型时的规则和应用场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

写在前面:

视频是什么东西,有看文档精彩吗?

视频是什么东西,有看文档速度快吗?

视频是什么东西,有看文档效率高吗?


泛型方法

诸小亮:下面来看一下——泛型方法

张小飞:刚才说泛型类的时候,里面不是有泛型方法吗?

诸小亮:其实那个并不能称为泛型方法,真正的泛型方法:

定义方法时,使用:<泛型名>,那么这个方法就是泛型方法,比如:
public <Q> void print(Q q){
    System.out.println("参数q,转换为字符串是:" + q);
}

张小飞:原来如此,这个应该怎么用呢?

诸小亮:来,看下面的代码


public class Demo {
    public static void main(String[] args) throws Exception {
        //1. print方法可以传递任何类型的数据
        new Demo().print(new Hero("yase"));
        new Demo().print(123);
        new Demo().print("456");
    }
	//2. 定义一个可以打印任何类型的方法
    public <Q> void print(Q q){
        System.out.println("参数q,转换为字符串是:" + q);
    }
}

结果:

image.png

张小飞:这么说,静态方法上也可以定义泛型吧

诸小亮:是的,静态方法也可以使用泛型:

image.png

张小飞:泛型方法,在工作中都有什么用呢?

诸小亮:工作中使用还是很多的,定义一个方法,该方法可以从 ArrayList 中取出对应的值
如果不用泛型:

//该方法从 list 中取出指定的字符串
public static String getObj(List<String> list, String arg){
    for(String t : list){
        if(t.equals(arg)){
            return t;
        }
    }
    return null;
}

//该方法从 list 中取出指定的Integer
public static Integer getObj2(List<Integer> list, Integer arg){
    for(Integer t : list){
        if(t.equals(arg)){
            return t;
        }
    }
    return null;
}

public static void main(String[] args) throws IOException {

    ArrayList<String> list = new ArrayList<>();
    list.add("妲己");
    list.add("亚瑟");
    list.add("李白");

    String yase = getObj(list, "亚瑟");


    ArrayList<Integer> list2 = new ArrayList<>();
    list2.add(1);
    list2.add(2);
    list2.add(3);

    Integer num = getObj2(list2, 3);
}


诸小亮:上面的代码中,你能看出什么?

张小飞:getObj、getObj2这两个方法非常相似,只是参数类型不同

诸小亮:没错,这时候就可以使用泛型方法,提高代码复用率

//定义一个泛型方法,从 list 中取出 跟参数 arg 相同的值
public static <T> T getObj(ArrayList<T> list, T arg){
    for(T t : list){
        if(t.equals(arg)){
            return t;
        }
    }
    return null;
}


public static void main(String[] args) throws IOException {

    ArrayList<String> list = new ArrayList<>();
    list.add("妲己");
    list.add("亚瑟");
    list.add("李白");

    String yase = getObj(list, "亚瑟");


    ArrayList<Integer> list2 = new ArrayList<>();
    list2.add(1);
    list2.add(2);
    list2.add(3);

    Integer num = getObj(list2, 3);
}

小结:使用泛型可以提高代码的复用性

泛型接口

诸小亮:在接口上使用:<泛型名>,那么这个接口就是泛型接口,比如:

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

张小飞:嗯嗯,这个我知道,像 List、Set、Comparable 都是泛型接口

诸小亮:那你知道,应该怎么用泛型接口吗?

张小飞:在实现这个接口时候,指定具体的类型就行了,比如:

image.png
张小飞:上图,在实现接口时指定了String类型,那么复写 show 方法时,参数就必须是String类型

诸小亮:嗯嗯,很不错

张小飞:不过我有个疑问,如果实现接口时不想指定具体的类型呢?

诸小亮:如果不想指定具体类型,可以继续使用泛型,比如:
image.png
张小飞:明白了,这时候 MyInterfacedImpl 就是——泛型类

诸小亮:嗯,是这个道理

通配符

张小飞:通配符是什么?

诸小亮:通配符,也属于泛型的一种,用于限制类型

张小飞:限制类型?这是什么意思?

介绍

诸小亮:我们先定义一个通用的方法,打印集合中的元素

张小飞:这个简单,看我的

//打印指定集合中的元素
public static void printCollection(Collection<String> collection){
    for(Iterator<String> it = collection.iterator();it.hasNext();){
        System.out.println(it.next());
    }
}

public static void main(String[] args) throws Exception {
    List<String> list = new ArrayList<>();
    list.add("abc1");
    list.add("abc2");
    list.add("abc3");
    printCollection(list);
}


诸小亮:上面的代码,打印的元素时 String 类型的集合,如果给你一个存储Integer的集合,printCollection 方法就不能用了,比如:

image.png

张小飞:这个简单,可以使用泛型啊

image.png

诸小亮:你说的不错,但是还有另一种方式

张小飞:哪种方式?

诸小亮:通配符,比如:**image.png
张小飞:原来还可以这样,不过这跟 **T Q E **等泛型,有什么不一样吗?

诸小亮:都差不多,只不过 ‘?’ 的使用方式更宽泛一些

张小飞:这是什么意思?

泛型的限定(了解)

诸小亮:那,我们就要聊一聊——泛型的限定

张小飞:限定?

诸小亮:是的,用来限制是哪些类型

泛型上限

诸小亮:首先看——泛型上限,比如:List<? extends Hero> list = new ArrayList<>();

张小飞:这是什么意思?

诸小亮:这表示 list 只能接收 Hero 及其子类型的数据,这就是泛型的上限

张小飞:能具体演示一下吗?

诸小亮:当然可以,先准备一些代码

class Hero{
    String name;

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

class Fashi extends Hero{

    public Fashi(String name){ super(name);}
}

public class Demo {

    public static void main(String[] args) throws IOException {
        List<? extends Hero> list = new ArrayList<>();
    }

张小飞:不对啊,为什么我这里不能给 list 添加数据?

image.png

诸小亮:这是正常的

张小飞:您不是说, list 只能存储 Hero 及其子类型的数据吗?为什么不能添加呢?

诸小亮:这就是泛型限定的缺陷了,虽然不能添加数据,但是可以这样:

List<Hero> heros = new ArrayList<>();
heros.add(new Hero("李白"));
heros.add(new Fashi("嫦娥"));

List<? extends Hero> list = heros;//直接给整个List赋值

张小飞:。。。。,完全不懂,这样的话,为什么要用泛型限定呢?

诸小亮:使用泛型限定,一般是作为方法的参数,限制数据类型,比如:

//该方法只接收List类型的容器,且容器中存储的只能是Hero或Hero的子类型数据
public static void printCollection(List<? extends Hero> collection){
    for(Iterator it = collection.iterator(); it.hasNext();){
        System.out.println(it.next());
    }
}

结果:
image.png

张小飞:原来如此,明白了

泛型下限

诸小亮:刚才说的是泛型上限,接下来我们说说——泛型下限

张小飞:这个是???

诸小亮:不要着急,还是先准备代码

class Person{

}

class Hero extends Person{
    String name;

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

class Fashi extends Hero{

    public Fashi(String name){ super(name);}
}

public class Demo {

    public static void main(String[] args) throws IOException {
        //泛型下限
        List<? super Hero> list = new ArrayList<>()
    }
}

张小飞:这表示** list 只能存储 Hero 及其父类型**吗?

诸小亮:额。。。,是的,不过有些小问题

张小飞:什么意思?

诸小亮:使用 add 方法添加数据时,可以添加 Hero 及其子类型,比如:
image.png
张小飞:还真是,Fashi 是添加了一个 Hero 的子类

诸小亮:但是不能添加 Hero 的父类型,比如:
image.png
张小飞:这是为什么?

诸小亮:一会儿再给你解释,不过虽然不能使用 add 方法添加 Hero 的父类型,但是:

image.png

张小飞:。。。。,完全懵了

诸小亮:这就给你解释,看下面代码

public static void main(String[] args) throws IOException {
     //泛型下限
    //1. 使用 add 方法,只能添加 Hero 及其子类型
    List<? super Hero> list = new ArrayList<>();
    list.add(new Hero("yase"));
    list.add(new Fashi("daji"));

    //2. 使用整体赋值,只能是 Hero 及其父类型
    test(new ArrayList<Hero>());
    test(new ArrayList<Person>());
    test(new ArrayList<Object>());
}

public static void test(List<? super Hero> list){
    Object c = list.get(0);
}

具体解释:

前提:List<? super Hero> list:表示接受 Hero 及其父类型的对象

1. 为什么使用 add 可以添加 Hero 的子类对象
   因为 Hero 子类对象,本质也是 Hero 类型,并且可以向上转型为PersonObject

2. 为什么使用 add 不能添加 Hero 的父类对象
   因为 List<? super Hero> list = new ArrayList<Hero>(); 是合法的
   上面的 test 方法中,参数 list 的值可能是 new ArrayList<Hero>(),
   这样的话,添加 Person 就不合适了,所以。。。。。

张小飞:大概明白了

诸小亮:另外,获取元素时,由于无法确定从 list 中取出来的是什么类型,所以用 Object 接收

image.png

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值