zoukankan      html  css  js  c++  java
  • 泛型的使用

    一,泛型概述

    ​ 关于泛型,先来说几句集合。都知道集合是可以存储任意对象,当我们创建一个集合时如果没有声明它的存储类型,那该集合便自动提升为Object类型。请参看如下代码:

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

    ​ 毫无疑问,以上代码会报错,首先从代码上看在集合中存储了数值类型,字符串类型。但是在使用迭代器遍历时,取出的是String类型的,那么对于数值类型来说就必然会报错。

    ​ 那么以上问题该怎么解决呢?通常对于Collection集合来说,同一个集合对象只保存一种数据类型。如下代码所示:

     		// 存储字符类型
            Collection<String> stringCollection = new ArrayList<>();
            // 存储数值类型
            Collection<Integer> integerCollection = new ArrayList<>();
            // 存储精度类型
            Collection<Double> doubleCollection = new ArrayList<>();
    

    ​ 也就是说在我们初始化集合的时候,就已经将存储存储类型固定。但是按照Java的灵活性来说,这是显然不够的,比如预先并不确定要存储的类型。因此在JDK5之后新增了泛型的语法,使我们的程序显得更为灵活。

    泛型:在方法或者类(接口)中预先的使用某种未知的数据类型。

    提示:在我们创建对象的时候,如果没有明确指出一种数据类型,那么编译器会默认为Object类。

    1.1,泛型的意义

    ​ 那说了这么多,泛型又能解决什么问题呢?针对上面的案例分析:

    ​ 1,可以将ClassCastException异常由运行期转到编译期异常。

    ​ 2,避免强制类型的转换。

    ​ 请看如上代码,在我们初始化集合时指定String数据类型,此时再存储数值类型就会在编译期报错,那么泛型又将如何运用呢。先别急,我们先看看集合中是如何定义的。

    ​ 在Array List集合源码中看出,它的存储类型是一个E,这是什么呢?

    • E,Elements:元素
    • T,Type:类型

    这就是泛型,因为我们对于集合来说它们并不知道我们要存储是什么类型,因此这就是泛型的意义。

    提示:泛型是数据类型的一部分,我们将类名与泛型合并一起看做数据类型。

    ​ 泛型,用来灵活地将数据类型应用到不同的类、方法、接口当中。将数据类型作为参数进行传递。

    二,泛型类

    ​ 编写格式:

    修饰符 class 类名称<泛型变量>{}
    

    ​ 我们还是以集合为例,请看如下集合源代码实现,以add方法作为参考。

    ​ 可以看出add方法接收的数据类型为E,与我们上一节图片中所示Array List源码实现是一致的,因为Array List接收的参数类型就是E。说这么多有些啰嗦,现在先定义一个泛型类。

    public class GenericClass<T> {
        private T key;
       public void setKey(T key){
           this.key = key;
       }
       public T getKey(){
           return key;
       }
    }
    
    public class GenericDemo {
        public static void main(String[] args) {
    
           GenericClass<String> genericString = new GenericClass<>();
           // 存储字符类型
            genericString.setKey("这是一个泛型类");
           // 获取数据
            String stringKey = genericString.getKey();
            System.out.println(stringKey);
        
            // 存储数值类型
            GenericClass<Integer> genericInteger = new GenericClass<>();
            // 存储数值1
            genericInteger.setKey(1);
            // 获取数值
            Integer integerKey = genericInteger.getKey();
            System.out.println(integerKey);
        }
    }
    

    三,泛型方法

    ​ 编写格式:

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

    ​ 例如定义泛型方法:

    public class GenericMethod {
        // 定义泛型方法
        public <T> void menthod(T t) {
            System.out.println(t.getClass());
        }
        // 返回实例化对象
        public <T> T getGenericMethod(Class<T> t) throws IllegalAccessException, InstantiationException {
            return t.newInstance();
        }
        public static void main(String[] args) throws Exception {
            GenericMethod genericMethod = new GenericMethod();
            genericMethod.menthod("abc");
            Object method = genericMethod.getGenericMethod(Class.forName("com.api.generic.User"));
            System.out.println(method);
        }
    }
    
    

    四,泛型接口

    ​ 编写格式:

    修饰符 interface 接口名称<泛型变量>{}
    

    ​ 定义泛型接口:

    public interface GenericInterface<T> {
    
        void add(T t);
    
        T getT();
    }
    

    ​ 如果泛型接口的实现类仍不确定,则还可以接着使用泛型。

    public class GenericInterfaceImpl<T> implements GenericInterface<T> {
        @Override
        public void add(T t) {
        }
    
        @Override
        public T getT() {
            return null;
        }
    }
    

    ​ 只有在创建对象的时候,要确定泛型的数据类型。

    GenericInterfaceImpl<String> genericInterface = new GenericInterfaceImpl<>();
            genericInterface.add("Hello");
    

    五,泛型通配符

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

    通配符基本使用

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

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

    举个例子大家理解使用即可:

    public static void main(String[] args) {
        Collection<Intger> list1 = new ArrayList<Integer>();
        getElement(list1);
        Collection<String> list2 = new ArrayList<String>();
        getElement(list2);
    }
    public static void getElement(Collection<?> coll){}
    //?代表可以接收任意类型
    
    注意:泛型不存在继承关系 Collection<Object> list = new ArrayList<String>();这种是错误的。
    

    六,泛型上下限

    ​ 之前设置泛型的时候,实际上是可以任意设置的,只要是类就可以设置。但是在JAVA的泛型中可以指定一个泛型的上限下限

    泛型的上限

    • 格式类型名称 <? extends 类 > 对象名称
    • 意义只能接收该类型及其子类

    泛型的下限

    • 格式类型名称 <? super 类 > 对象名称
    • 意义只能接收该类型及其父类型

    比如:现已知Object类,String 类,Number类,Integer类,其中Number是Integer的父类

    public static void main(String[] args) {
        Collection<Integer> list1 = new ArrayList<Integer>();
        Collection<String> list2 = new ArrayList<String>();
        Collection<Number> list3 = new ArrayList<Number>();
        Collection<Object> list4 = new ArrayList<Object>();
        
        getElement(list1);
        getElement(list2);//报错
        getElement(list3);
        getElement(list4);//报错
      
        getElement2(list1);//报错
        getElement2(list2);//报错
        getElement2(list3);
        getElement2(list4);
      
    }
    // 泛型的上限:此时的泛型?,必须是Number类型或者Number类型的子类
    public static void getElement1(Collection<? extends Number> coll){}
    // 泛型的下限:此时的泛型?,必须是Number类型或者Number类型的父类
    public static void getElement2(Collection<? super Number> coll){}
    

    七,泛型擦除

    ​ 在泛型的使用中还有一项重要的概念,就是泛型擦除。

    ​ 这里就不再分享了,有一篇写的很好的博客关于泛型擦除的,有兴趣的可以去看看。

    ​ 转载自:https://blog.csdn.net/briblue/article/details/76736356

    八,总结

    ​ 总体来说泛型的出现为我们的代码带来很多便利,使程序更加灵活。并且在官方文档中提出如果能使用泛型就尽量使用泛型,提高代码的可读性。

    ​ 这次关于泛型的总结相对来说并不深入,只是一些简单的描述。最后,在本文中的内容如有不适之处,欢迎多多指点。

    感谢阅读!

  • 相关阅读:
    清除内联元素间默认的间隔
    Idea配置SpringBoot热部署
    导出下载模板
    Java 使用Graphics2D 进行画图
    【Modbus】Java使用 modbus-master-tcp 读取和写入Modbus服务器数据
    解决txt文件上传oss服务器乱码的问题
    docker java.lang.NoClassDefFoundError: org/bouncycastle/** 解决
    解决SpringBoot 报错 Error parsing HTTP request header
    React+AntDesign使用Tree树控件完整展现其中的层级关系,并具有展开收起选择等交互功能
    AntDesign使用Form表单出现You cannot set a form field before rendering a field associated with the value
  • 原文地址:https://www.cnblogs.com/fenjyang/p/11474565.html
Copyright © 2011-2022 走看看