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

    八,总结

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

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

    感谢阅读!

  • 相关阅读:
    动态生成 Excel 文件供浏览器下载的注意事项
    JavaEE 中无用技术之 JNDI
    CSDN 泄露用户密码给我们什么启示
    刚发布新的 web 单点登录系统,欢迎下载试用,欢迎提建议
    jQuery jqgrid 对含特殊字符 json 数据的 Java 处理方法
    一个 SQL 同时验证帐号是否存在、密码是否正确
    PostgreSQL 数据库在 Windows Server 2008 上安装注意事项
    快速点评 Spring Struts Hibernate
    Apache NIO 框架 Mina 使用中出现 too many open files 问题的解决办法
    解决 jQuery 版本升级过程中出现 toLowerCase 错误 更改 doctype
  • 原文地址:https://www.cnblogs.com/fenjyang/p/11474565.html
Copyright © 2011-2022 走看看