泛型用法

泛型用法

这次写项目写了很多工具类,泛型用的比较多,之前没怎么用过,现在才发现是真的好用,总结一波

注:文章借鉴: https://segmentfault.com/a/1190000014120746 作者:java3y

1.在哪里我们见过泛型?

ArrayList<String> list = new ArrayList<String> ();
  • 这是一个常见的array集合 <String>表示这个集合中只能存入String类型的元素,我们通过泛型规定了list集合中元素的类型。
  • ArrayList<E>中的E称为类型参数变量
  • 我们把 ArrayList<String> 中的String称为实际类型参数
  • 整个称为ArrayList<E>泛型类型
  • 整个ArrayList<String>称为参数化的类型ParameterizedType
  • 而泛型在定义上解释为:把类型明确的工作推迟到创建对象或调用方法的时候才去明确的特殊的类型
    在ArrayList这个类被设计的时候并不知道他应该存什么元素,而ArrayList本身只能存储一种类型的元素,所以我们可以用泛型让ArrayList在被创建的时候再去规定他储存的元素。这就是泛型常见的一种用法。

二、为什么需要泛型

早期Java是使用Object来代表任意类型的,但是向下转型有强转的问题,这样程序就不太安全

首先,我们来试想一下:没有泛型,集合会怎么样

  • Collection、Map集合对元素的类型是没有任何限制的。本来我的Collection集合装载的是全部的Dog对象,但是外边把Cat对象存储到集合中,是没有任何语法错误的。
  • 把对象扔进集合中,集合是不知道元素的类型是什么的,仅仅知道是Object。因此在get()的时候,返回的是Object。外边获取该对象,还需要强制转换

有了泛型以后:

  • 代码更加简洁【不用强制转换】
  • 程序更加健壮【只要编译时期没有警告,那么运行时期就不会出现ClassCastException异常】
  • 可读性和稳定性【在编写集合的时候,就限定了类型】

2.1有了泛型后使用增强for遍历集合

在创建集合的时候,我们明确了集合的类型了,所以我们可以使用增强for来遍历集合!

   //创建集合对象
        ArrayList<String> list = new ArrayList<>();

        list.add("hello");
        list.add("world");
        list.add("java");

        //遍历,由于明确了类型.我们可以增强for
        for (String s : list) {
            System.out.println(s);
        }

三、 泛型基础

3.1泛型类

泛型类就是把泛型定义在类上,用户使用该类的时候,才把类型明确下来… 这样的话,用户明确了什么类型,该类就代表着什么类型…用户在使用的时候就不用担心强转的问题,运行时转换异常的问题了。

  • 在类上定义的泛型,在类的方法中也可以使用!
/*
    1:把泛型定义在类上
    2:类型变量定义在类上,方法中也可以使用
 */
public class ObjectTool<T> {
    private T obj;

    public T getObj() {
        return obj;
    }

    public void setObj(T obj) {
        this.obj = obj;
    }
}

用户想要使用哪种类型,就在创建的时候指定类型。使用的时候,该类就会自动转换成用户想要使用的类型了。

  public static void main(String[] args) {
        //创建对象并指定元素类型
        ObjectTool<String> tool = new ObjectTool<>();

        tool.setObj(new String("钟福成"));
        String s = tool.getObj();
        System.out.println(s);


        //创建对象并指定元素类型
        ObjectTool<Integer> objectTool = new ObjectTool<>();
        /**
         * 如果我在这个对象里传入的是String类型的,它在编译时期就通过不了了.
         */
        objectTool.setObj(10);
        int i = objectTool.getObj();
        System.out.println(i);
    }

3.2泛型方法

前面已经介绍了泛型类了,在类上定义的泛型,在方法中也可以使用

现在呢,我们可能就仅仅在某一个方法上需要使用泛型…外界仅仅是关心该方法,不关心类其他的属性…这样的话,我们在整个类上定义泛型,未免就有些大题小作了。

  • 定义泛型方法…泛型是先定义后使用的
    //定义泛型方法..
    public <T> void show(T t) {
        System.out.println(t);

    }
  • 使用
  //定义泛型方法..
    public static void main(String[] args) {
        //创建对象
        ObjectTool tool = new ObjectTool();

        //调用方法,传入的参数是什么类型,返回值就是什么类型
        tool.show("hello");
        tool.show(12);
        tool.show(12.5);
    }

3.3泛型类派生出的子类

前面我们已经定义了泛型类,泛型类是拥有泛型这个特性的类,它本质上还是一个Java类,那么它就可以被继承

那它是怎么被继承的呢??这里分两种情况

  • 子类明确泛型类的类型参数变量
  • 子类不明确泛型类的类型参数变量
3.3.1子类明确泛型类的类型参数变量

泛型接口

/*
    把泛型定义在接口上
 */
public interface Inter<T> {
    public abstract void show(T t);

}

实现泛型接口的类…

/**
 * 子类明确泛型类的类型参数变量:
 */

public class InterImpl implements Inter<String> {
    @Override
    public void show(String s) {
        System.out.println(s);
    }
}
3.3.2子类不明确泛型类的类型参数变量

当子类不明确泛型类的类型参数变量时,外界使用子类的时候,也需要传递类型参数变量进来,在实现类上需要定义出类型参数变量

/**
 * 子类不明确泛型类的类型参数变量:
 *      实现类也要定义出<T>类型的
 *
 */
public class InterImpl<T> implements Inter<T> {

    @Override
    public void show(T t) {
        System.out.println(t);

    }
}

测试代码

 public static void main(String[] args) {
        //测试第一种情况
        //Inter<String> i = new InterImpl();
        //i.show("hello");

        //第二种情况测试
        Inter<String> ii = new InterImpl<>();
        ii.show("100");

    }

值得注意的是:

  • 实现类的要是重写父类的方法,返回值的类型是要和父类一样的!
  • 类上声明的泛形只对非静态成员有效

3.4类型通配符

为什么需要类型通配符????我们来看一个需求…

现在有个需求:方法接收一个集合参数,遍历集合并把集合元素打印出来,怎么办?

按照我们没有学习泛型之前,我们可能会这样做:


public void test(List list){

    for(int i=0;i<list.size();i++){
        
        System.out.println(list.get(i));
    
    }
}

上面的代码是正确的,只不过在编译的时候会出现警告,说没有确定集合元素的类型…这样是不优雅的…

  • 那我们学习了泛型了,现在要怎么做呢??有的人可能会这样做:

public void test(List<Object> list){

    for(int i=0;i<list.size();i++){
        
        System.out.println(list.get(i));
    
    }
}

这样做语法是没毛病的,但是这里十分值得注意的是:该test()方法只能遍历装载着Object的集合!!!

强调:泛型中的并不是像以前那样有继承关系的,也就是说List和List是毫无关系的!!!!

那现在咋办???我们是不清楚List集合装载的元素是什么类型的,List这样是行不通的…于是Java泛型提供了类型通配符 ?


public void test(List<?> list){


    for(int i=0;i<list.size();i++){
        
        System.out.println(list.get(i));
    
    }
}

?号通配符表示可以匹配任意类型,任意的Java类都可以匹配…

?号通配符表示可以匹配任意类型,任意的Java类都可以匹配…就只能调对象与类型无关的方法,不能调用对象与类型有关的方法。

记住,只能调用与对象无关的方法,不能调用对象与类型有关的方法。 因为直到外界使用才知道具体的类型是什么。也就是说,在上面的List集合,我是不能使用add()方法的。因为add()方法是把对象丢进集合中,而现在我是不知道对象的类型是什么。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值