5.泛型

目录

5.泛型

5.1.什么是泛型

5.2.使用泛型与否的区别

5.3.泛型在类、方法和接口中使用

5.3.1.泛型在类中使用

5.3.2.泛型在方法中使用

5.3.3.泛型在接口中使用

5.3.4.使用泛型注意事项

5.4.泛型通配符

5.4.1.什么时候使用泛型通配符

5.4.2.泛型通配符的弊端(缺陷)

5.4.3.泛型通配符的使用和注意事项

5.5.泛型通配符高级使用-受限范型


5.泛型


5.1.什么是泛型

1.泛型

     1.1.是一种未知的数据类型,当我们不知道使用什么数据类型的时候,可以使用泛型
     1.2. 泛型也可以看做是一个变量,用来接收数据类型。
     1.3.泛型,用来灵活地将数据类型应用到不同的类、方法、接口中。将数据类型作为参数进行传递。可以在类或方法中预支地使用未知的类型。
      E e:Element元素
      T t:Type类型
2.例如:
       ArrayList集合在定义的时候,不知道集合中都会存储什么类型的数据,所以类型使用泛型。
       集合可以存储所有引用类型数据,包括对象,包装类,字符串等数据。
       创建集合对象时就会确定泛型的数据类型。即ArrayList<String>list=new ArrayList<string>()
       public class ArrayList<E>{   //这是ArrayList集合定义(底层实现)
           public boolean add(E e)()
           public E get(int index)
       }
       
       若创建集合对象ArrayList<String>list=new ArrayList<String>();
       则会把数据类型作为参数传递,把String赋值给泛型E
       public class ArrayList<String>(){
          public boolean add(String e){}
          public String get(int index){}
       }
       
       若创建集合对象ArrayList<Student>list=new ArrayList<Student>();
       则会把数据类型作为参数传递,把Student赋值给泛型E
       public class ArrayList<Student>{
          public boolean add(Student e){}
          public Student get(int index){}
       }
       一般在创建对象时,将未知的类型确定具体的类型。当没有指定泛型时,默认类型为Object类型。

5.2.使用泛型与否的区别

 1.创建集合对象时使用泛型:
     *   1.好处:
     *      1.避免了类型转换的麻烦,存储的是什么类型,取出的就是什么类型
     *      2.把运行期异常(代码运行之后会抛出的异常),提升到了编译期(写代码的时候会报错)。
     *   2.弊端:
     *       泛型是什么类型,只能存储什么类型的数据
     
* 2.创建集合对象时不用泛型:
     *   1.好处:
     *         集合不使用泛型,默认的类型就是Object类型,可以存储任意类型数据。(基本类型转为包装类)
     *   2.弊端:
     *         不安全,会引发异常。

public class GenericDemo2 {
    public static void main(String[] args) {
        show2();
    }

    /**
     * 1.创建集合对象时使用泛型:
     *   1.好处:
     *      1.避免了类型转换的麻烦,存储的是什么类型,取出的就是什么类型
     *      2.把运行期异常(代码运行之后会抛出的异常),
     *        提升到了编译期(写代码的时候会报错)。
     *   2.弊端:
     *       泛型是什么类型,只能存储什么类型的数据
     */
    private static void show1(){
        ArrayList<String>list=new ArrayList<>();
        list.add("abc");
        //list.add(1);集合使用泛型后,这个时候就报错了,运行期异常提升到编译期。
        //使用迭代器遍历list集合
        Iterator<String>it=list.iterator();
        while(it.hasNext()){
            String s = it.next();
            System.out.println("s长度"+s.length());
        }

    }

    /**
     * 2.创建集合对象时不用泛型:
     *   1.好处:
     *         集合不使用泛型,默认的类型就是Object类型,可以存储任意类型数据。
     *   2.弊端:
     *         不安全,会引发异常。
     */

    private static void show2(){
        ArrayList list=new ArrayList();
        list.add("abc");
        list.add(1);
        //使用迭代器遍历list集合
        //获取迭代器(即调用集合中的iterator()方法,并用Iterator接口接收)
        Iterator it=list.iterator();
        //使用迭代器中方法hasNext和next遍历集合
        while(it.hasNext()){
            //取出元素也是Object类型
            //即不使用泛型的集合可存储各种类型的数,当从集合中取出时均以Object类型取出
            Object obj = it.next();
            System.out.println(obj);


           //若想要使用String类特有的方法length获取字符串的长度,是不能使用的,
           //多态 Object obj="abc";
           //需要向下转型
           //会抛出ClassCastException类型转换异常,无法把Iterator类型转换为String类型
           String s=(String)obj;
           System.out.println(s.length());//抛出异常
        }
    }
}

5.3.泛型在类、方法和接口中使用

1.定义含有泛型的类
class ArrayList<E>{
       public boolean add(E e){}
       public E get(int index){}
       .....
}

含有泛型的类什么时候确定泛型的数据类型:创建对象的时候确定泛型的类型,将数据类型作为参数传递给泛型

2.定义含有泛型的方法
 public <M> void method01(M m){
        System.out.println(m);
 }
 public static <S> void method02(S s){
        System.out.println(s); 
 }

 含有泛型的方法什么时候确定泛型数据类型:在调用方法时确定泛型数据类型。传递什么类型参数,泛型就是什么类型
 
3.定义含有泛型的接口
 public interface GenericDemo5Interface<I>{
    public abstract void method(I i);
 }

 
4.含有泛型的接口的两种使用方式
  1.定义接口的实现类,实现接口,指定接口泛型
  2.定义接口的实现类,实现接口,不指定具体接口泛型
    接口使用什么泛型,实现类就使用什么泛型,类跟着接口走。相当于定义了一个含有泛型的类,创建对象的时候确定泛型的类型。
    public class GenericDemo5InterfaceImpl1 implements GenericDemo5Interface<String> {
       public void method(String s){  //定义接口的实现类,要重写接口的抽象方法
           System.out.println(s);
    }
    public class GenericDemo5InterfaceImpl2<I> implements GenericDemo5Interface<I> {
    @Override
       public void method(I i) {
         System.out.println(i);
    }
   }
含有泛型的接口什么时候确定泛型的类型:定义类时确定泛型的类型或创建对象时确定泛型的类型两种。

5.泛型通配符的使用:不能在创建集合对象时使用,只能作为方法的参数使用
 :public static void printArrayList(ArrayList<?> list){}

5.3.1.泛型在类中使用

/**
 * 1.定义一个含有泛型的类
 * 2.泛型是一个未知的数据类型,当我们不确定什么数据类型的时候,可以使用泛型。
 * 3.泛型可以接受任意的数据类型,可以使用Integer,String,Student...
 * 4.创建对象的时候确定泛型的类型。
 */
public class GenericDemo3Class<E> {
    private E name;
    public  E getName(){
        return name;
    }
    public void setName(E name){
        this.name=name;
    }
}


public class GenericDemo3class1 {
    public static void main(String[] args) {
        //不使用泛型则默认获取的数据为Object类型
        GenericDemo3Class gc = new GenericDemo3Class();
        Object obj = gc.getName();

        //创建含泛型的类对象,泛型使用Integer类型(创建对象时确定泛型类型)
        GenericDemo3Class<Integer> gc2 = new GenericDemo3Class<>();
        gc2.setName(1);
        Integer name = gc2.getName();
        System.out.println(name);

        //创建含泛型的类对象,泛型使用String
        GenericDemo3Class<String> gc3 = new GenericDemo3Class<>();
        gc3.setName("小明");
        String name1 = gc3.getName();
        System.out.println(name1);
    }
}

5.3.2.泛型在方法中使用

/**
 * 1.定义含有泛型的方法:泛型定义在方法的修饰符和返回值类型之间。
 * 2.格式;
 *      修饰符<泛型> 返回值类型 方法名(参数列表(使用泛型)){
 *          方法体;
 *      }
 * 3.含有泛型的方法,在调用方法的时候确定泛型的数据类型。
 *   传递什么类型的参数,泛型就是什么类型。
 */

public class GenericDemo4Method {
    /**
     * 定义一个含有泛型的方法
     */
    public <M> void method01(M m){
        System.out.println(m);
    }

    /**
     * 定义一个含有泛型的静态方法
     * 注意:静态方法不建议通过创建对象调用
     *      一般使用类名来调用静态方法。
     */
    public static <S> void method02(S s){
        System.out.println(s);
    }
}


/**
 * 测试含有泛型的方法
 */
public class GenericDemo4Method1 {
    public static void main(String[] args) {
        //创建GenericMethod对象
        GenericDemo4Method gm = new GenericDemo4Method();
        /**
         * 调用含有泛型的方法method01
         * 传递什么类型,泛型就是什么类型,参数可以为任意类型
         */
         gm.method01(10);
         gm.method01("abc");
         gm.method01(8.8);
         gm.method01(true);


         //静态方法,通过类名.方法名(参数)可以直接使用。
         GenericDemo4Method.method02("静态方法");
         GenericDemo4Method.method02(1);
    }
}

5.3.3.泛型在接口中使用

/**
 * 定义含有泛型的接口
 */

public interface GenericDemo5Interface<I>{
    public abstract void method(I i);
}


/**
 * 1.含有泛型的接口:第一种使用方式:定义接口的实现类,实现接口,指定接口泛型
 *      例如:之前学过迭代接口,该接口中定义了next()方法获取下一个元素
 *            public interface Interator<E>{
 *                E next();
 *            }
 *            而Scanner类实现了Iterator接口,并指定接口泛型为String,
 *            所以重写的next()方法泛型默认就是String
 *            public final class Scanner implements Interator<String>{
 *                public String next(){}
 *            }
 * 类名最后是Impl表示该类是接口的实现类
 */

public class GenericDemo5InterfaceImpl1 implements GenericDemo5Interface<String> {
    public void method(String s){  //定义接口的实现类,要重写接口的抽象方法
        System.out.println(s);
    }
}



/**
 * 1.含有泛型的接口第二种使用方式:定义接口的实现类,实现接口,不指定具体接口泛型,
 *     接口使用什么泛型,实现类就使用什么泛型,类跟着接口走。
 *     相当于定义了一个含有泛型的类,创建对象的时候确定泛型的类型。
 * 2.例如List接口的实现类ArrayList:
 *     public interface List<E>{  //List接口定义
 *         boolean add(E e);
 *         E get(int index);
 *     }
 *     public class ArrayList<E> implements List<E>{ //List接口实现类定义
 *         public boolean add(E e){}
 *         public E get(int index){}
 *     }
 *
 */

public class GenericDemo5InterfaceImpl2<I> implements GenericDemo5Interface<I> {
    @Override
    public void method(I i) {
        System.out.println(i);
    }
}

5.3.4.使用泛型注意事项

泛型不存在继承关系 Collection<Object> list = new ArrayList<String>();这种是错误的

5.4.泛型通配符

5.4.1.什么时候使用泛型通配符

当使用泛型类或者泛型接口时,传递的数据中,泛型类型不确定,可以通过通配符<?>表示。比如,定义一个方法能遍历所有类型的ArrayList集合,这个时候我们不知道ArrayList集合使用什么数据类型,因此要用泛型的通配符。

5.4.2.泛型通配符的弊端(缺陷)

一旦使用泛型的通配符后,只能使用Object类中的共性方法集合中元素自身方法无法使用。 此时只能接收数据,不能往该集合中存储数据

5.4.3.泛型通配符的使用和注意事项

1.泛型的通配符 ?:代表任意的数据类型                                                                                                                                                                                             

2.不能在创建集合对象时使用,只能作为方法的参数使用.ArrayList<?> list = new ArrayList<?>();报错

public class GenericDemo6 {
    public static void main(String[] args) {
        //创建集合
        ArrayList<Integer> list01 = new ArrayList<>();
        list01.add(1);
        list01.add(2);

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

        //不能在创建集合对象时使用,只能作为方法的参数使用
        //ArrayList<?> list = new ArrayList<?>();报错
    }

    /**
     * 定义一个方法,能遍历所有类型的ArrayList集合
     *      这时我们不知道ArrayList集合使用什么数据类型,
     *      可以使用泛型的通配符?来接收数据类型。
     * 注意:泛型是没有继承概念的,虽然包装类和字符串都继承Object,
     *      但不能用Object作为泛型来分别接收包装类类型和字符串类型。
     *      只能使用泛型通配符。
     */
    public static void printArrayList(ArrayList<?> list){
        //使用迭代器遍历集合(集合是什么类型,迭代器就是什么类型)
        Iterator<?> it = list.iterator();
        while(it.hasNext()){
            //it.next()方法取出的元素都是Object类型,可以接收任意数据类型
            Object o = it.next();
            System.out.println(o);
        }
    }
}

5.5.泛型通配符高级使用-受限范型

泛型通配符的高级使用--只适用于在方法的参数中使用泛型通配符
1.之前设置泛型时候,实际上是可以任意设置的,只要是类就可以设置。但是在Java泛型中可以指定泛型的上限和下限
2.泛型的上限:
    格式集合类型名称 <? extends 类> 对象名称
    意义:代表使用的泛型?只能是E类型本身或者其子类。
3.泛型的下限:
    格式集合类型名称 <? super 类> 对象名称
    意义:代表使用的泛型?只能是E类型本身或者其父类
比如:现已知Object类,String 类,Number类,Integer类,其中Number是Integer的父类 Integer extends Number extends Object


 * 泛型通配符的高级使用:受限泛型
 * 1.泛型的上限限定: ? extends E  代表使用的泛型?只能是E类型本身或者其子类
 * 2.泛型的下限限定: ?  super E   代表使用的泛型?只能是E类型本身或者其父类。
 
public class GenericDemo7 {
    public static void main(String[] args) {
        //创建Collection集合(因为它是接口,要用接口指向它的实现类来创建对象)
        Collection<Integer>list1=new ArrayList<>();
        Collection<String>list2=new ArrayList<>();
        Collection<Number>list3=new ArrayList<>();
        Collection<Object>list4=new ArrayList<>();
        //通过泛型通配符获取不同数据类型的集合对象
        getElement1(list1);//Integer类是Number类的子类
        getElement1(list2);//报错,String类不是Number的子类
        getElement1(list3);//Number类是Number类本身
        getElement1(list4);//报错,Object类是Number父类而不是子类

        getElement2(list1);//报错,Integer类不是Number类的父类
        getElement2(list2);//报错,String类不是Number类的父类
        getElement2(list3);//Number类是Number类本身
        getElement2(list4);//Object类是Number类父类
        /**
         * 类与类之间的继承关系:
         * Integer extends Number extends Object
         * String extends Object
         */
    }

    /**
     * 在创建含泛型通配符的方法时,只能作为方法的参数使用
     * 方法的参数定义一个集合对象用来接收集合,定义的这个集合使用受限泛型。
     */

    //设置泛型的上限:此时的泛型为?,必须是Number类型或者Number类型的子类
    public static void getElement1(Collection<? extends Number>coll){

    }

    //设置泛型的下限:此时的泛型为?,必须是Number类型或者Number类型的父类
    public static void getElement2(Collection<? super Number>coll){

    }
}

 

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值