关于泛型的那些事之为什么要有泛型与泛型方法等

一、背景

今天是学习JAVASE的第20天,和大家汇报一下前几天在学习LIst集合(主要是ArrayLIst),我写了一个计算集合内数据的和的工具方法,然后封装好丢给了好朋友,他接受到之后就跟我说程序运行不了我就纳了个闷,怎么会运行不了呢?经过询问才知道,他输入了“一”和“三”........这字符串怎么用来计算嘛。我就抛出了这个问题,有啥方法可以根据我输入的参数的类型来处理集合吗?经过我的研究,这种技术就叫——泛型。

二、为什么要有泛型 

众所周知,集合里面的元素都是被上升为Object类型的,存的时候你是心高气傲,取出来用的时候就生死难料了(doge),如下 

public static void main(String[] args) {
        //往集合里存点东西
        ArrayList list = new ArrayList();
        list.add("一亩三分地er");
        list.add("求免费的赞和评论给予我鼓励呀");
        list.add(123);
        list.add(new Student());
        //使用集合里的元素
        String str = new String();
        for (int i = 0; i < list.size(); i++) {
            str+=list.get(i);
        }
    }

这铁定报错啊,怎么可能把一个类给拼接到字符串上呢?所以,要保证不报错,我就只能对集合里的元素使用Object类的方法,满足了通用性。可是这样就 牺牲了独特性,因为我的元素的特别方法就用不了了。所以才出现了——泛型这一技术。

通过泛型,我们就可以实现我要用String类,这个集合就是String类型的集合;我用Integer类,他就是Integer类型的集合,实现了通用性和独特性的结合。

三、泛型类、泛型方法、泛型接口

1、泛型类

要想使用泛型类,只需要在类名的后面加“<>”符号,<>里面可以添加一个或多个符号。这个符号可以是A、B、C等等符合命名规范的字符,但一般使用约定俗成的字符,如:T(type)、E(element)、Key(键)等等。这样在类中就可以替掉具体的类型了。这个符号可以看作一个参数。使用时,调用者传入什么类型参数,这个符号就会变成什么类型。

public class ArrayList1<E> {
    transient Object[] elementData;

    public E get(int index) {
        return (E) elementData[index];
    }
    public boolean add (E e) {
        //省略向elementData添加E元素的代码
        return true;
    }
}

 比如,上面的ArrayList1类就需要一个E类型作为参数用于类中的方法和属性。

2、泛型方法

首先说好,泛型方法不需要所在的类是泛型类,泛型方法和泛型类没有必反联系,泛型方法一般用于参数E只在这个方法会被用到,如果在整个类中被用到那就可以把泛型定义在类名后面啦!

public class GenericTest {
    public <E> E genericMethod(E e){
        //第一个E表示这是一个泛型方法,第二个E表示返回值类型为E,小括号里的E表示形参为E类型
        //省略逻辑处理
        return e;
    }
}

上面的方法是成员方法,当然泛型也可以被用在静态方法。但是静态属性和静态方法有个缺陷,就是他们无法访问类上定义的泛型参数:

public class GenericTest<E> {
    
    private static  void generiMethond(E e) {
    }//编译错误
}

 这很好理解嘛,因为泛型参数是我们在创建实例对象的时候指定的,而静态方法是class加载时就被创建的,没有给他指定泛型参数的类型,他是不可能让你编译成功的。

所以,静态方法要调用泛型参数,那么他本身就要被声明为一个泛型、静态方法。即:

public class GenericTest<E> {

    private static <E> void back(E e) {
    }//编译错误
}

3、泛型接口

泛型接口的使用有两种方法:

1、实现类给出具体的类型

2、实现类延续泛型,在创建对象时给出具体的泛型类型。

我们来看第一种:

public interface Generic3<E> {
    void consum(E e);
}
class Test implements  Generic3<String>{

    @Override
    public void consum(String s) {

    }
}

可以看到,当我们Test实现类给出具体的类型后(String),我们以后传递的参数就只能是String了,包括后面实现Testt时,传递的参数也只能是String。

第二种:

public interface Generic3<E> {
    void consum(E e);
}
class Test<E> implements  Generic3<E>{

    @Override
    public void consum(E e) {

    }
}
public class Generic {
    public static void main(String[] args) {
        Test<String> t = new Test<>();
        t.consum("aaa");
    }
}

在实现接口时,我们并没有给出E的具体类型,而是在实现类实例化的时候给出的(为String),此时我们调用consume方法就只能传递String类型的变量。

四、结语

这篇文章可能不如某些行内大佬做的好,大家多多包容,有问题欢迎在评论区批评指正!祝生活愉快!

  • 10
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值