• Java泛型简介、定义和使用含有泛型的类、定义和使用含有泛型的方法、定义和使用含有泛型的接口、泛型通配符?、受限泛型


    泛型简介:

    集合中存储数据的类型称之为泛型,泛型是一种未知的数据类型,当不知道使用什么数据类型的时候可以使用泛型;

    当创建对象时在指明数据类型并赋值给泛型即可;泛型也可以看做是一个变量,用来存储数据。

    常见泛型中:字母E表示元素,字母T表示Type,当然如果泛型的数据类型已知的话可以传入确定的数据类型,如String,底层实际是将String传递给了E

    import java.util.ArrayList;//导包
    import java.util.Iterator;
    public class Generic{
        public static void main(String[] args){
            // 1.集合中为了安全,一般是需要指定数据类型的,<类型>,类型值除int(Integer)、char(Character),其它类型将数据类型的首字母大写即可
            ArrayList<String> arraylist = new ArrayList<String>();
            arraylist.add("星期一");
            System.out.println(arraylist); // [星期一]
            arraylist.add("星期二");
            System.out.println(arraylist); // [星期一, 星期二]
    
            // 2.使用泛型的好处:避免数据类型转换,存什么类型取什么类型;将运行期异常提升到了编译器;泛型的弊端:指明数据类型后只能存储指定类型的数据。
            ArrayList<Integer> arrayInt = new ArrayList<Integer>();
            arrayInt.add(10);
            System.out.println(arrayInt);
            // arrayInt.add("20"); // 泛型是什么类型,在新增数据的时候就是什么数据类型的数据,否则编译不通过
            arrayInt.add(20);
            System.out.println(arrayInt);
    
            // 3.集合不使用泛型时,默认数据类型是Object,可以存储任意类型的数据,此时不安全会发生异常。
            ArrayList list = new ArrayList();
            list.add('1');
            list.add("abc");
            list.add(12);
            System.out.println(list); // 编译时提示: Generic.java使用了未经检查或不安全的操作; 打印结果:[1, 1, abc]
    
            // 4.使用迭代器遍历list:
            // 获取集合的迭代器:
            Iterator iter = list.iterator();
            //遍历并打印数据:
            //hasNext判断是否有元素
            while (iter.hasNext()) {
                // next获取元素
                Object item = iter.next();
                System.out.println(item);
    
                // 向下转型时会抛出异常:Exception in thread "main" java.lang.ClassCastException: java.base/java.lang.Integer cannot be cast to java.base/java.lang.String at Generic.main(Generic.java:37),使用泛型约束后在编译时就会提示
                String str = (String) item;
                System.out.println(str.length());
                System.out.println(str);
            }
        };
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43

    定义和使用含有泛型的类:

    定义泛型类时只需要在类名称后面加<类型>,类里面的数据类型用尖括号中的类型代替,使用泛型类时和普通类一样创建,区别就是可以使用泛型创建对象,也可以不使用泛型创建对象,但是不使用泛型创建对象时,它默认是Object类型,而且也是不推荐的,如下面E的使用:

    泛型类:

    // 定义含有泛型的类时,在类名称后面写<类型>即可,E表示任意元素的泛型
    public class GenericClass<E> {
    //public class GenericClass{
        // 1.定义一个含有泛型的类(模拟ArrayList集合),泛型是一个未知的数据类型,当不确定数据类型的时候可以使用泛型,泛型可以接收任意数据类型,在创建对象时在指明数据类型:
        private E name;
    //    private String name;
    
        public E getName() {
    //    public String getName() {
            return name;
        }
    
        public void setName(E name) {
    //    public void setName(String name) {
            this.name = name;
        }
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    使用泛型类:

    public class UserGenerIcClass {
        public static void main(String[] args) {
            // 1.使用GenericClass类,不传泛型时默认是Object类型
            GenericClass gc = new GenericClass();
            // 当创建类的时候,如果数据类型是写死的,那么在这里设置和读取的时候也只能是指定写死的类型,如:
            gc.setName("苦海");
            System.out.println(gc.getName());// 苦海
    
            // 2.使用泛型创建对象:
            GenericClass<Integer> gcInt = new GenericClass<Integer>();
            // gcInt.setName('1'); 使用了泛型,如果数据类型不符合就会编译不通过
            gcInt.setName(18);
            System.out.println(gcInt.getName());// 18
    
            GenericClass<Character> gcChar = new GenericClass<Character>();
            gcChar.setName('f');
            System.out.println(gcChar.getName());// f
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

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

    定义含有泛型的方法:

    // 含有泛型的方法:泛型定义在方法修饰符和返回值之间,如: public <泛型> 返回值类型(参数(使用泛型)){}
    public class DefGenericMethodsClass {
        // 前面定义了泛型,后面括号中才可以使用:这里S是随便写的,这里可以写任意字符串
        public <S> void defGenericMethods(S s) {
            System.out.println(s);
        }
    
        // 定义一个含有泛型的静态方法:
        public static <S> void staGenericMethods(S s) {
            System.out.println(s);
        }
    
        // 定义一个普通的方法:
        public static void commonMethods (String s) {
            System.out.println(s);
        }
    }
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    使用含有泛型的方法:

    public class UseGenericMethodsClass {
        public static void main(String[] args) {
            // 创建含有泛型方法的对象:
            DefGenericMethodsClass gm = new DefGenericMethodsClass();
            // 调用含有泛型的方法,传递什么类型,泛型就是什么类型
            gm.defGenericMethods(10); // 10
            gm.defGenericMethods('a'); // a
            gm.defGenericMethods("121"); // 121
    
            // 调用静态方法:
            DefGenericMethodsClass.staGenericMethods("静态方法");
            // 调用普通方法:接收参数时必须指定类型,且传参数时也要求一直
            gm.commonMethods("hello");
            // gm.commonMethods(true); // 定义什么类型,传递什么类型,否则报错
            // gm.commonMethods(123);
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

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

    定义含有泛型的接口:

    // 定义含有泛型的接口:在接口名称后面加<类型>
    public interface DefGenericInterface<S> {
        // 定义一个抽象方法:
        public abstract void methods(S s);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    使用含有泛型的接口,有两种方式:

    方式一接口实现类:

    // 使用含有泛型的接口第一种方式:定义接口实现类,实现接口,指定接口泛型:
    public class UseGenericInterface implements DefGenericInterface<String> {
        @Override
        public void methods(String s) {
            System.out.println(s);
        };
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    方式一使用接口实现类:、

    // 定义一个普通的类使用接口实现类:
    public class UseGenericInterfaceClass {
        public static void main(String[] args) {
            UseGenericInterface gi = new UseGenericInterface();
            gi.methods("hello"); // hello
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    方式二接口实现类:

    // 使用含有泛型的接口第二种方式:接口使用什么泛型,实现类就用什么泛型,类跟着接口走,相当于定义了一个含有泛型的类,创建对象时指定泛型的类型
    public class UseGenericInterfaceTwo<S> implements DefGenericInterface<S> {
        @Override
        public void methods(S s) {
            System.out.println(s);
        };
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    方式二使用接口实现类:

    public class UseGenericInterfaceClassTwo {
        public static void main(String[] args) {
            UseGenericInterfaceTwo<Integer> gi = new UseGenericInterfaceTwo<Integer>();
            gi.methods(255); // 255
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    泛型通配符?:

    当使用泛型类或者接口时,传逆的数据中,泛型类型不确定,可以通过通配符表示。但是一旦使用泛型的通配符后,只能使用Objet类中的共性方法,集合中元素自身方法无法使用,只能接收数据,不能往集合中存储数据:

    import java.util.ArrayList;
    import java.util.Iterator;
    
    // 泛型通配符:只能作为方法的参数使用,不能创建对象使用,如下面定一个万能遍历结合的方法
    public class GenericWildcard {
        public static void main(String[] args) {
            ArrayList<Integer> list1 = new ArrayList<Integer>();
            list1.add(1);
            list1.add(2);
            forEachArrayList(list1);
    
            ArrayList<Character> list2 = new ArrayList<Character>();
            list2.add('z');
            list2.add('a');
            forEachArrayList(list2);
        }
        public static void forEachArrayList(ArrayList<?> list) {
            // 获取遍历器:
            Iterator<?> item = list.iterator();
            while(item.hasNext()){
                Object it = item.next();
                System.out.println(it);
            }
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    受限泛型:

    前面设置泛型的时候是没有做限制的,只要是类都可以设置,但是在Java的泛型中可以指定一个泛型的上限和下限:

    泛型上限:只能接收该类型及其子类

    格式:类型名称 对象名称

    泛型下限: 只能接收该类及其父类

    格式:类型名称 对象名称

    import java.util.ArrayList;
    import java.util.Collection;
    
    public class GenericLimit {
        public static void main(String[] args) {
            // 定义多个类型的集合并测试受限泛型:
            Collection<Integer> list1 = new ArrayList<Integer>();
            getElementExtends(list1);
            // getElementSuper(list1); // 报错:只能传入当前类型或父类
    
            Collection<String> list2 = new ArrayList<String>();
            // getElementExtends(list2); // 报错:String和Number没有上下级关系
            // getElementSuper(list2); // 报错:String和Number没有上下级关系
    
            Collection<Number> list3 = new ArrayList<Number>();
            getElementExtends(list3);
            getElementSuper(list3);
    
            Collection<Object> list4 = new ArrayList<Object>();
            getElementExtends(list3);
            getElementSuper(list3);
        }
        // 类之间的继承关系:
        // Integer 继承-> Number 继承-> Object
        // String 继承-> Object
    
        // 定义一个泛型下限:传入的类型只能是Number或子类
        public static void getElementExtends(Collection<? extends Number> param){};
        // 定义一个泛型上限:传入的类只能是Number或父类
        public static void getElementSuper(Collection<? super Number> param){};
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    提示:本文图片等素材来源于网络,若有侵权,请发邮件至邮箱:810665436@qq.com联系笔者删除。
    笔者:苦海

  • 相关阅读:
    C++中的中介者模式
    HTTP请求报文与响应报文
    【Docker Compose】Docker ComposeV2新版本的日常使用
    酷睿i5 12450h和i5 12650h差多少 i512450h和i512650h对比
    动态规划 | 不同路径、整数拆分、不同的二叉搜索树 | leecode刷题笔记
    顺子日期(蓝桥杯)
    打造一套属于自己的php开发框架(一)封装Db类
    基于jsp的学生培训管理系统
    GFS分布式文件系统
    [云原生] K8s之ingress
  • 原文地址:https://blog.csdn.net/weixin_46758988/article/details/128088586