美文网首页
四 集合 ——第二节 泛型

四 集合 ——第二节 泛型

作者: 杜艳_66c4 | 来源:发表于2022-05-27 23:55 被阅读0次

文章目录

1、 泛型概念
2、 使用泛型的好处
3、 泛型的定义与使用

3、1 定义和使用含有泛型的类
3、2 含有泛型的方法
3、3 含有泛型的接口

4、 泛型通配符

4、1 通配符基本使用
4、2 通配符高级使用----受限泛型

1、概念:

泛型概念

是一种未知的数据类型,当我们不确定使用什么的时候,用泛型。也可以看做一个变量,用来接收数据类型

E—— e Element 元素 e:代表未知的数据类型
T ——t Type 类型
E - Element (在集合中使用,因为集合中存放的是元素)
T - Type(Java 类) T代表在调用时的指定类型
K - Key(键)
V - Value(值)
N - Number(数值类型)
? - 表示不确定的java类型 一般用在通配

ArrayList<E> 集合在定义的时候,不知道集合中都会存储什么类型的数据,所以类型用泛型。
创建集合对象的时候,就会确定泛型的数据类型。
ArrayList<String> list = new ArrayList<>();
会把数据类型作为参数传递,把String赋值给泛型E。
如下代码:

public class GenericDemo {
    public static void main(String[] args) {
        Collection coll = new ArrayList();
        coll.add("abc");
        coll.add("ADC");
        coll.add(5);//由于集合没有做任何限定,任何类型都可以给其中存放
        Iterator it = coll.iterator();
        while(it.hasNext()){
            //需要打印每个字符串的长度,就要把迭代出来的对象转成String类型
            String str = (String) it.next();
            System.out.println(str.length());
        }
    }
}

程序在运行时发生了问题java.lang.ClassCastException。 为什么会发生类型转换异常呢? 我们来分析下:由于集合中什么类型的元素都可以存储。导致取出时强转引发运行时 ClassCastException。 怎么来解决这个问题呢? Collection虽然可以存储各种对象,但实际上通常Collection只存储同一类型对象。例如都是存储字符串对象。因此在JDK5之后,新增了泛型(Generic)语法,让你在设计API时可以指定类或方法支持泛型,这样我们使用API的时候也变得更为简洁,并得到了编译时期的语法检查。

2、使用泛型的好处


import java.util.ArrayList;
import java.util.Iterator;

/**
 * created by apple on 2020/6/17 泛型
 */
public class Demo01Generic {
    public static void main(String[] args) {
        show01();
        show02();
    }
    /*
      创建集合对象,使用泛型
      好处: 避免了类型转换的麻烦,存储的什么类型,取出的什么类型;
           把运行期异常(代码运行后抛出的异常),提升到编译期;
          
      弊端:泛型是什么类型,就只能存储什么类型
       */
    private static void show02() {
        ArrayList<String> li = new ArrayList<>();
        li.add("dfa");
        //好处:在编译期抛异常
       // li.add(12);
     //集合已经明确具体存放的元素类型,那么在使用迭代器的时候,迭代器也同样会知道具体遍历元素类型
        Iterator<String> it1 = li.iterator();
        while (it1.hasNext()){
            String it2 = it1.next();
//当使用Iterator<String>控制元素类型后,就不需要强转了。获取到的元素直接就是String类型
            System.out.println(it2);

        }
    }

    /*
    创建集合对象,不使用泛型
    好处: 默认的类型是Object类型,可以存储任意类型的数据
    弊端:集合不安全,会引发异常
     */
    private static void show01() {
        ArrayList list = new ArrayList();
        list.add("abd");
        list.add(1);
        //迭代器遍历list集合
        Iterator it = list.iterator();
        //使用迭代器中的方法 hasNext  next遍历
        while (it.hasNext()){
//取出元素也是Object 类型
            Object obj = it.next();
            System.out.println(obj); //  

            //想使用String类特有的方法,length 获取字符串长度,现在是多态,Obj obj = “abc”,不能使用子类特有的方法,需要向下转型
          //  String s = (String)obj;  //会抛出异常ClassCastException  不能把Integer转换成String类型
          //  System.out.println(s.length());  // 3 1 

        }   }
}

3、泛型的定义与使用

3、1 定义和使用含有泛型的类

定义格式:

修饰符 class 类名<代表泛型的变量> { }

package collectiondemo;

/**
 * created by apple on 2020/6/17
 * 定义一个含有泛型的类,可以模拟ArrayList集合
 * 泛型是一个未知的数据类型,当不确定使用类型的数据时,用泛型。
 * 泛型可以接受任意的数据类型,可以使用Integer,String,Student
 * 什么时候确定泛型:在创建对象的时候确定泛型的数据类型
 */
public class Demo02Generic<E> {
    public E getName() {
        return name;
    }

    public void setName(E name) {
        this.name = name;
    }

    private E name;
}

测试类
使用泛型: 即什么时候确定泛型。
在创建对象的时候确定泛型

package collectiondemo;

/**
 * created by apple on 2020/6/17
 * 不写泛型 默认是Object类型
 */
public class Demo02Genericclass {
    public static void main(String[] args) {
        Demo02Generic gc = new Demo02Generic();
        gc.setName("只能是字符串");
       // String name = gc.getName();   写成泛型,这个会报错
        Object name = gc.getName();
        System.out.println("没有泛型" + name);

        //创建Demo02Generic对象,泛型用Integer类型
        Demo02Generic<Integer> gc2 = new Demo02Generic();
        gc2.setName(23);
        Integer name1 = gc2.getName();
        System.out.println("Integer:" + name1);

        //创建Demo02Generic对象,泛型用String类型
        Demo02Generic<String> gc3 = new Demo02Generic();
        gc3.setName("fsdj");
        Integer name2 = gc2.getName();
        System.out.println("Strng:" + name2);
    }
}

3、2 定义和使用含有泛型的方法

定义格式:

修饰符 <代表泛型的变量> 返回值类型 方法名(参数){ }

package collectiondemo;

/**
 * created by apple on 2020/6/17
 * 定义含有泛型的方法,泛型定义在方法的修饰符和返回值类型之间
 * 格式:
 * 修饰符<泛型>返回值类型 方法名(参数列表,用泛型){
 *     方法体
 * }
 * 含有泛型的方法,调用方法时 ,确定泛型的数据类型
 * 传递什么类型参数,泛型就是什么类型
 */
public class GenericMethod {

    //定义一个有泛型的方法
    public <M> void method1(M m){
        System.out.println(m);
    }
    // //定义一个有泛型的静态方法
    public static <S> void method2(S s){
        System.out.println(s);
    }
}

调用方法时,确定泛型的类型

package collectiondemo;

/**
 * created by apple on 2020/6/17
 * 测试含有泛型的方法
 */
public class GenericMethodDemo {
    public static void main(String[] args) {
        //创建GenericMethod 对象
        GenericMethod ge  = new GenericMethod();
        //调用方法,传递什么 泛型就是什么类型
        ge.method1(10);
        ge.method1("fd");
        ge.method1(true);

        ge.method2("静态方法 不建议创建对象使用");
        //静态方法通过类名.方法名直接使用
        GenericMethod.method2("静态方法");
        GenericMethod.method2(123);

    }
}

3、3含有泛型的接口

定义格式:

修饰符 interface接口名<代表泛型的变量> { }

public interface MyGenericInterface<E>{
    public abstract void add(E e);
    
    public abstract E getE();  
}

使用格式:

3.31、定义类时确定泛型的类型

含有泛型的接口,第一种使用方式:定义接口的实现类,实现接口,指定接口的泛型
public class MyImpl1 implements MyGenericInterface<String> {
    @Override
    public void add(String e) {
        // 省略...
    }

    @Override
    public String getE() {
        return null;
    }
}

此时,泛型E的值就是String类型。

3.32、始终不确定泛型的类型,直到创建对象时,确定泛型的类型

ublic class MyImp2<E> implements MyGenericInterface<E> {
    @Override
    public void add(E e) {
         // 省略...
    }

    @Override
    public E getE() {
        return null;
    }
}

确定泛型:

/*
 * 使用
 */
public class GenericInterface {
    public static void main(String[] args) {
        MyImp2<String>  my = new MyImp2<String>();  
        my.add("aa");
    }
}

04_泛型通配符

当使用泛型类或者接口时,传递数据中,泛型类型不确定,可通过通配符<?>表示,表示未知通配符,此时只能接受数据,不能往集合中存储数据。一旦使用通配符,只能用Object类中的共性方法,集合中元素自身方法无法使用。

4.1 通配符基本使用

泛型的通配符:不知道使用什么类型来接收的时候,此时可以使用?,?表示未知通配符。

此时只能接受数据,不能往该集合中存储数据

package collectiondemo;

import java.util.ArrayList;
import java.util.Iterator;

/**
 * created by apple on 2020/6/18
 * 泛型的通配符:
 * 代表任意数据类型
 * 使用方式:
 * 不能创建对象使用,只能作为方法的参数使用
 *
 */
public class DemotGeneric {
    public static void main(String[] args) {
        ArrayList<Integer> li = new ArrayList<>();
        li.add(1);
        li.add(3);

        ArrayList<String> li2 = new ArrayList<>();
        li2.add("a");
        li2.add("b");

        printArray(li);
        printArray(li2);
        //定义的时候不能用哦
      //  ArrayList<?> list = new ArrayList<?>();
        /*
        定义一个方法,能遍历所有类型的ArrayList集合
        这时不知道ArrayList集合使用什么数据类型,用泛型的通配符?接收数据类型
         */
    }
    public static  void printArray(ArrayList<?> list){
        //遍历集合
        Iterator<?> it = list.iterator();
        while (it.hasNext()){
            //it.next()取出的元素是Object类型,可以接收任意类型
            Object next = it.next();
            System.out.println(next);
        }
    }
}

4.2 通配符的高级使用

  • 泛型的上限限定: ? extends E 代表使用的泛型只能是E类型的子类/本类 工作中用的不多。看懂源码就行
  • 泛型的下限限定: ? super E 代表使用的泛型只能是E类型的父类/本类

相关文章

  • 四 集合 ——第二节 泛型

    文章目录 1、 泛型概念2、 使用泛型的好处3、 泛型的定义与使用 3、1 定义和使用含有泛型的类3、2 含有泛型...

  • Java一泛型

    目录 一、设计背景 二、什么是泛型?泛型的作用? 三、泛型的原理 四、使用泛型 一、设计背景 Java集合(Col...

  • C#基础提升系列——C#集合

    C#集合 有两种主要的集合类型:泛型集合和非泛型集合。 泛型集合被添加在 .NET Framework 2.0 中...

  • Java—泛型详解和使用

    1 泛型介绍 1.1 泛型的出现   泛型的出现还得从集合说起,没有泛型的时候,我们将一个对象存入集合时,集合不c...

  • 四、Java高级--1、泛型

    泛型定义:数据类型参数化,提前定义好集合中放入什么类型集合框架中没使用泛型和使用泛型的比较 泛型规则和限制1、泛型...

  • JDK5的新特性

    可变参数 格式: 注意 静态导入 泛型 泛型类: 泛型方法: 泛型接口: 增强for 在 集合_List 中有...

  • 泛型——Dart(五)

    泛型 从字面意思理解,就是广泛的类型,我们可以在集合中看到泛型的影子: 为什么要有泛型? 以集合为例,假如没有泛型...

  • 泛型集合与非泛型集合,泛型

    ArrayList//非泛型集合 非泛型集合添加元素演示 public void Test1(){ ArrayLi...

  • 泛型

    泛型的使用 jdk 5.0新增的特性 在集合中使用泛型 ① 集合接口或集合类在jdk5.0时都修改为带泛型的结构。...

  • 《Kotlin入门实战》CH8 | 泛型

    泛型 泛型是在Java5中引入的,泛型让集合框架可以重用代码,在没有泛型时候,集合框架中存储数据的类型都是Obje...

网友评论

      本文标题:四 集合 ——第二节 泛型

      本文链接:https://www.haomeiwen.com/subject/ecoexktx.html