如何定义一个入参为泛型的方法_你了解泛型吗?

不点蓝字,我们哪来故事?

泛型概念

泛型,即“参数化类型”。就是将类型由原来具体的类型参数化变成参数形式,然后在使用时传入具体的类型。类似于方法中的变量参数。

字我都认识,咋放在一起就看不懂了呢???

Don't be afraid, I'm here.

‘泛’,意为宽泛的,普遍的,是相对于具体的,独特的而言的。所以泛型是一种广泛的,具有代表性的类型,而如int, float,String等则是具体的类型。

“参数化类型”只是泛型的一个显得很高端的别名,大家不要被吓到。泛型用一个具有代表性的参数来代表各种类型,因此该类型也定义成参数形式将其参数化,故又称为参数化类型。

引入

下面我们举个例子来看,同时也可以帮助大家更好地理解泛型(参数化类型)的概念。

现在有一个需求:对于同一个方法,当A调用时要传入int类型的参数,当B使用时要传入float类型的参数,而当C调用时要传入String类型的参数,请问你要如何编写这个方法?

very good! 给想到重载的同学点个赞,使用重载确实可以解决这个需求,但是当我有更多的类型需求时你是不是还要继续重载呢?一方面这使得我们要经常维护代码,另一方面相同的代码很多,不符合开发规范,也不好。

有没有其他的方法呢?

对的,用Object作为参数类型也可以,但是装入的数据类型都被当作Object类型,从而丢失了实际类型,而且获取数据时往往需要转型,效率低还更容易出现错误,也不合适。

还有没有其他的方法呢?哈哈,忘了我们今天的主题了吗?

泛型嘛,说白了不就是模板嘛,看代码:

定义了一个泛型方法,然后在主方法中多次调用且每次传递不同的参数。

package run.xyzliu.section2.note;

public class GenericParadigm {
    public static void main(String[] args) {
        //传递String类型
        print("hello");

        //传递int类型
        print(100);

        //传递字符类型
        print('H');

        //传递float类型
        print(20.7);
    }

    public static  void print(A a){
        System.out.println(a);
    }
}
399fc2f2da8e38febda07d953bcf0e46.png
向泛型方法中传入各种类型参数

有没有一种拿了同学的报告改了个名字的感觉?

泛型使用

接下来我们就学习一下如何优雅地改同学报告使用泛型

格式

使用<>符号

使用规则
  • 不能使用静态属性和静态方法上

  • 使用的时候需要指定数据类型
    . 编译时会检查数据的类型
    . 获取数据不再需要强制类型转换

  • 泛型使用是不能指定基本数据类型,只能使用起对应的包装类

泛型类

在一个类创建时就声明类中有种类型是我们泛指的类型,在类名后使用声明,其中T可以替换成任意字母。

定义泛型类的格式:

public class className {

 private T data;

 public T getData(){

     return data;

    }

    public void setData(T data){

     this.data = data;

    }

}

泛型类的使用

定义泛型类Person:

package run.xyzliu.section2.note;

//创建类的时声明一个泛型,用参数A表示
public class Person <A>{
    private String name;
    private int age;
    private A data;

    /*name和age的getter()setter()方法*/

    //获取data的方法类型用泛型表示
    public A getData() {
        return data;
    }

    //设置data的方法传入参数也是泛型
    public void setData(A data) {
        this.data = data;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", data=" + data +
                '}';
    }
}

在Test类中使用泛型类Person:

package run.xyzliu.section2.note;

public class Test {
    public static void main(String[] args) {
        //使用泛型类,给声明的泛型传入具体地String类型
        Person p1 = new Person<>();//使用p1调用setData()方法传入的应该时String类型的参数
        p1.setData("小华学IT");
        System.out.println("使用泛型传入String类型:" + p1.getData());//使用泛型,给声明的泛型传入具体的
        Person p2 = new Person<>();//此时使用p2调用setData()方法传入的则应是Integer类型的参数
        p2.setData(1000);
        System.out.println("使用泛型传入Integer类型:" + p2.getData());
    }
}
562b139447ea8a322ec82993d406492d.png
当传入的具体类型为String时,setData()方法也是String类型
418570574c62c892d6ffc0257ae7c17c.png
当传入的具体类型为Integer时,setData()方法也是Integer类型
fa79547081515c838c5bc628dd279457.png
泛型类运行结果
泛型接口

有了使用泛型类的经验,使用泛型接口就容易多了,定义格式如下:

public interface IntercaceName    {
   T getData();
}

实现接口时,可以选择指定泛型类型,也可以选择不指定, 如下:

指定类型:
public class Interface1 implements IntercaceName<String> {
    private String text;

    @Override
    public String getData() {
        return text;
    }
}

不指定类型:
public class Interface1<T> implements IntercaceName<T> {
    private T data;

    @Override
    public T getData() {
        return data;
    }
}

这里不再展示代码,有兴趣的朋友可以自己动手使用一下。

泛型方法

定义泛型方法的格式:

private static T 方法名(T a, T b) {}

此时定义的泛型只在方法内有效,方法外无法使用。代码可参考“引入”种的泛型方法。建议亲自上机写写几遍。

泛型限制类型

在此之前我们设置的泛型使用可以代替任何类型,但是有些特殊的需求,要求泛型的范围必须某范围以内。

在使用泛型时, 可以指定泛型的限定区域。例如:必须是某某类的子类或 某某接口的实现类

格式:   

下面通过一段代码展示:

类中定义了一个Fruit(水果)接口及其实现类Apple(苹果),随后又定义了一个Plate(盘子)类。目前没有对泛型做任何限制,所以可以向泛型类中传入各种具体的类型。

package run.xyzliu.section2.note;

public class Demo {
    public static void main(String[] args) {
        Plate p = new Plate<>();
        p.data = "小华学IT";
        System.out.println(p.data);
        p.data = "1000";
        System.out.println(p.data);
    }
}interface Fruit{}class Apple implements Fruit{}class Plate<T> {
    T data;
}

现在要求这个盘子只能装水果,不能装其他的物品,请问使用泛型如何实现?

其实很简单,只需给泛型添加一个限制即可。使其继承水果及其子类即可,如下:

class Plate < T extends Apple>

此时我们在向泛型传入其他类型便会报错,只能传入水果子类:

7d1061a9a4ff5be213437eb0e4eca177.png
限制泛型只能传入是水果子类
泛型中通配符 "?"

代替方法具体的类型实参。
1  指定了泛型类型的上届
2  指定了泛型类型的下届
3  指定了没有限制的泛型类型

有兴趣的朋友可以按照格式自行上机练习使用。

泛型作用/优点

经过上面的介绍,我们可以得出泛型的作用,如下:

  1. 提高代码复用率

  2. 泛型中的类型在使用时指定,不需要强制类型转换(类型安全,编译器会检查类型)

注意事项

  1. 在编译之后程序会采取去泛型化的措施。

  2. 也就是说Java中的泛型,只在编译阶段有效。

  3. 在编译过程中,正确检验泛型结果后,会将泛型的相关信息擦出,并且在对象进入和离开方法的边界处添加。

  4. 类型检查和类型转换的方法。也就是说,泛型信息不会进入到运行时阶段。 

通过这篇文章,你了解泛型了吗?

  坚持原创

  坚持干货

小华学IT

004aedf8db1b00bbf0086cd26d3ed7cd.png 03b4b8e3e851a0abcf39815eb4c3a916.png b016003eff00cc2b4225f6de8cae5d54.gif

关注小华 一起学习 一起进步

e8274686f1f4f78082c3922989e331bb.gif
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值