Java 泛型的作用以及类、方法、接口的使用和通配符

一、泛型的作用

        1.集合如果不使用泛型:

        存的时候什么类型都可以,但是要取的时候会懵,因为取出来啥也不是,或者不知道取的是什么类型的数据。像这样:

        // 创建ArrayList集合,不使用泛型
        ArrayList arrayList = new ArrayList();

        // 往集合中添加元素
        arrayList.add("老二");
        arrayList.add("张三");
        arrayList.add(10);
        arrayList.add(1.1);
        System.out.println(arrayList);

        // 遍历集合中的元素
        for(Object o : arrayList){
            String str = (String) o;
            System.out.println(str);
        }

        输出结果:

        Java 泛型的作用以及类、方法、接口的使用和通配符_第1张图片

         2.集合中使用泛型:

        使用泛型在编译器里直接对类做了控制,只能存储泛型定义的数据

                像这样:

                Java 泛型的作用以及类、方法、接口的使用和通配符_第2张图片

                 结果:存储泛型指定以外的数据类型,编译都不会通过的

        总结:

                泛型:定义的时候表示一种未知的数据类型,在使用的时候确定其具体的数据类型

        重点:

                泛型的作用是在创建对象时,将未知的类型确定为具体的类型。

                当没有指定泛型时,默认类型为Object类型

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

        1. 定义含有翻新的类:

                public class 类名称<泛型变量>{}

        2.泛型变量的:

                任意字母。一般都会写 E ,方便识别。

    public class MyArrayList {
        E e;
        public E method(E e){
            return e;
        }
    }

        3.什么时候定义泛型的类:

                当类中的成员变量或者成员方法的 形参类型/返回值类型不确定的时候,就可以把该类型定义为含有泛型的累

        MyArrayList list1 = new MyArrayList<>();
        list1.e = "张三";
        String str1 = list1.method("张三");
        System.out.println(str1);

        MyArrayList list2 = new MyArrayList<>();
        list2.e = 100;
        Integer str2= list2.method(100);
        System.out.println(str2);

        

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

        1.定义含有泛型的方法:

                修饰符<范型变量> 返回值类型 方法名称(形参列表){

                        方法体

                }

        2.泛型变量:

                任意字母。一般会写T 或者M ,方便识别

        3.什么时候会定义含有泛型的方法

                如果一个类中,某个方法的参数类型或者返回值类型不确定的时候,可以把该方法定义为含有泛型的方法

                注意:调用含有泛型的方法的时候确定其泛型的具体数据类型

    // 定义一个含有泛型的方法
    public static  T method(T t){
        return t;
    }
    
    public static void main(String[] args){
        // 指定泛型的具体数据类型为Integer
        Integer i = method(100);
        String str = method("张三");
    }

四、定义和使用含有泛型的接口

        1.定义含有泛型的接口

                public interface 接口名<泛型变量>{

                

                }

        2.泛型变量

                任意字母,一般可以使用 E

         3.使用泛型的接口

                确定接口的泛型的具体数据类型

                (1)、通过实现类的方式确定接口泛型的具体数据类型

                        public class 类名 implements 接口名<具体的数据类型>{}

                (2)、实现类实现接口的时候如果不确定接口反省的具体数据类型,可以在创建实现类对象的时候来确定接口泛型的具体数据类型

                        public class 类名<泛型变量> implements 接口名<具体的数据类型>{}

        // 接口
        public interface A {

            public abstract void method1(E e);

            public default E method2(E e){
                return e;
            }
        }
         // 实现类1
         public class Impl_1 implements A{
            @Override
            public void method1(String s) {

            }

            @Override
            public String method2(String s) {
                return null;
            }
        }
       /*
        * 实现类实现接口的时候不确定接口泛型的具体数据类型
        * 实现类类名称后面就必须跟上,否则重写的方法中的泛型将无法被定义
        *
        * 这样的实现类 在创建实现类对象的时候来确定泛型的具体数据类型
        * */

       // 实现类2
       public class Impl_2 implements A{
            @Override
            public void method1(E e) {
                System.out.println("实现类 method1");
            }

            @Override
            public E method2(E e) {
                return null;
            }
        }
   public static void main(String[] args) {

         // 创建实现类对象的时候确定接口泛型的具体数据类型
        Impl_1 impl_1 = new Impl_1();
        impl_1.method1("donglan");
        String donglan = impl_1.method2("donglan");
        System.out.println(donglan);

        // 创建实现类对象的时候不确定接口泛型的具体数据类型
        Impl_2 impl_2 = new Impl_2<>();
        impl_2.method1("donglan");
        String donglan2 = impl_2.method2("donglan");
        System.out.println(donglan2);

        Impl_2 impl_3 = new Impl_2<>();
        impl_3.method1(100);
        Integer donglan3 = impl_3.method2(100);
        System.out.println(donglan3);

    }

        总结:

                  泛型是一种位置的数据类型

                  定义在类上的泛型,使用类的时候会确定泛型的类型

                  定义在方法上的泛型,会在使用方法的时候确定泛型的类型

                  定义在接口上的泛型,会在使用接口的时候确定泛型的类型

五、泛型通配符

        1.泛型通配符的基本使用

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

                                                【?】表示位置通配符

                注意:不同往使用通配符的集合里存储数据,因为系统不知道该存储什么样的类型

                用代码来理解:

 public static void main(String[] args) {

        // 关系: String类继承Object类
        ArrayList list1 = new ArrayList<>();
        ArrayList list2 = new ArrayList<>();
        // 关系: Integer类继承Number    Number类继承Object类
        ArrayList list3 = new ArrayList<>();
        ArrayList list4 = new ArrayList<>();

        list2.add("张三");

        //method1(list1);
        method1(list2);
        //method1(list3);
        //method1(list4);

        method2(list1);
        method2(list2);
        method2(list3);
        method2(list4);


        method0(list1);
        //method0(list2); 编译报错  因为方法中的形参ArrayList 只能接收Object类型的,泛型不存在多态
        //method0(list3); 编译报错  因为方法中的形参ArrayList 只能接收Object类型的,泛型不存在多态
        //method0(list4); 编译报错  因为方法中的形参ArrayList 只能接收Object类型的,泛型不存在多态
    }

    // 定义一个方法,可以接收以上4个集合对象
    public static void method1(ArrayList list){
        Object obj = list.get(0);//运行会报错
        list.add("zhangsan");
        System.out.println("obj:"+obj);// donglan
        System.out.println("list:"+list);// [donglan,zhangsan]
    }

    public static void method2(ArrayList list){
        //Object obj = list.get(0);//运行会报错
        //list.add("zhangsan"); 编译报错,如果我们使用了通配符泛型,不能往该集合中存储数据,只能获取数据
        //System.out.println("obj:"+obj);//
        list.remove("zhangsan"); // 可以删除,不能添加
        System.out.println("list:"+list);//
    }

        2.泛型通配符的高级使用

                通配符的高级使用  -->  受限类型

                        上限:< ?  extends  类名>  只能接收该类类型或者其子类类型

                        下限:< ?  super  类名>  只能接收该类类型或者其父类类型

                上限意思就是天花板的意思,级别不能再高了,最高的级别限度

                下限意思就是地板的意思,最低的级别限度

            代码来理解:

 public static void main(String[] args) {

        // 关系: String类继承Object类
        ArrayList list1 = new ArrayList<>();
        ArrayList list2 = new ArrayList<>();
        // 关系: Integer类继承Number    Number类继承Object类
        ArrayList list3 = new ArrayList<>();
        ArrayList list4 = new ArrayList<>();

        /*
        * < ? extends 类名>         < ? super 类名>
        * */

        method1(list1);
        method1(list2);
        method1(list3);
        method1(list4);

        method2(list1);
        method2(list2);
        method2(list3);
        method2(list4);

        //method3(list1); 编译报错,因为方法参数是 上限为Number,
        //method3(list2); 编译报错,因为方法参数是 上限为Number,
        method3(list3);
        method3(list4);

        method4(list1);
        //method4(list2); 编译报错,因为方法参数是 下限为Integer
        method4(list3);
        method4(list4);

    }

    // 定义一个方法,可以接收以上四种集合对象
    public static void method1(ArrayList arrayList){}
    public static void method2(ArrayList arrayList){}

    // 定义一个方法,只可以接收list3和list4集合对象
    public static void method3(ArrayList arrayList){}

    // 定义一个方法,只可以接收list1,list3,list4集合对象
    public static void method4(ArrayList arrayList){}

你可能感兴趣的:(Java语言进阶,Java,泛型,经验分享)