zoukankan      html  css  js  c++  java
  • 理解Java泛型 通配符 ? 以及其使用

    什么是泛型:

    泛型从字面上理解,是指一个类、接口或方法支持多种类型,使之广泛化、一般化和更加通用。Java中使用Object类来定义类型也 能实现泛型,但缺点是造成原类型信息的丢失,在使用中容易造成ClassCastException。

    Java泛型带到的好处:

    1. 使得一个类或方法中的类型参数化,最终达到代码复用的效果。( 不使用泛型,你可能需要每种情况的类或方法都要定义一遍 )
    2. 实现类型检查的功能,避免ClassCastException。(这是相对于使用Object类型实现泛型而言。因为我可以每个类都定义一遍来实现所谓的类型检查。)

    泛型自定义:类、接口、方法

    //定义泛型类,接口的定义和类一样
    class G1<T> {
        T content;
    }
    
    // 定义泛型方法,方法的头部使用<T>声明,注意结构
    class GMethod1 {
    
        // 一般泛型方法定义
        public static <T> void method1(T params) {
    
        }
    
        // 返回值也为泛型
        public static <E> E method2(E params) {
            E content = params;
            return content;
        }
    
    }
    
    // extends 的使用,限定泛型的范围,等于或者是extends的子类;只有extends,没有super,通配符才有extends和super
    class G2<T extends Number> {
        T content;
    }

    泛型的使用

        //泛型类或接口的使用
        List<String> list = new ArrayList<>();
    
        //泛型方法的使用,在方法前面使用<>传入类型
        <String>gMethod1.method1("str");
        <Integer>gMethod1.method1(new Integer(1));
    
        //如果入参的参数中使用了T,则可以省略方法前面的<>,编译器可以自行识别出其类型
        gMethod1.method1("str");
        gMethod1.method1(new Integer(1));

    通配符?

    什么时候会用通配符:

    通配符只有在修饰一个变量时会用到,使用它可方便地引用包含了多种类型的泛型;

        public static void main() {
    
            //不使用通配符
            ArrayList<Object> arr = new ArrayList<Object>();
            // ArrayList<Object> arr = new ArrayList<String>(); 编译不通过,arr只能引用包含Object的集合
    
            //使用通配符
            ArrayList<?> arr2;
            arr2 = new ArrayList<String>();
            arr2 = new ArrayList<Integer>();
            arr2.get(0);    //返回的,是一个Object对象,通配符会使原集合包含类型信息丢失,也是通配符的使用代价
    
        // 通常在方法参数中才会使用通配符,使得这个方法可以引用多种泛型集合。这个和范型方法不一样,这里只是一个引用变量
        void gMethod(ArrayList<? extends Number> param) {
        }

    可以看到,通配符使用方便的同时,使原集合包含类型信息丢失。

    通配符的extends super关键字

    详解:https://blog.csdn.net/qq_35923521/article/details/77717308

            ArrayList<? extends Number> arr3; // Number 是 Integer、Float的父类; ArrayList<Number> arr3只能引用 ArrayList<Number>
            arr3 = new ArrayList<Integer>();
            arr3 = new ArrayList<Float>();
            // arr3 = new ArrayList<String>(); 编译不通过,String 和 Number不存在继承关系
    
            arr3.get(0);    //返回的,是一个Number对象
            arr3.add(null); //使用过通配符修饰的集合变量,只能add(null),因为这个集合中包含的类型已经确定,只是类型信息已经丢失了,add(Object)也不行

    无限定通配符?

    ArrayList<?> arr3;  无通配符等同于 ArrayList<? extends Object> arr3;   //用于取值get(),不能赋值set()

    扩展:不使用泛型的变量和另一种方式

            //这样使用功能和通配符一样,可以多种引用,但一般不推荐这样使用
            ArrayList a4;
            a4 = new ArrayList<String>();
            a4 = new ArrayList<Integer>();
            a4.add(new Integer(1));
            a4.add(new String("str"));//和通配符引用不能add不一样,这样方式可以add多种类型元素,但一般不推荐
    
            a4.get(0);  //返回的,是一个Object对象
  • 相关阅读:
    Java 集合系列06之 Vector详细介绍(源码解析)和使用示例
    Java 集合系列03之 ArrayList详细介绍(源码解析)和使用示例
    Java 集合系列02之 Collection架构
    Java 集合系列01之 总体框架
    [转载] 散列表(Hash Table) 从理论到实用(下)
    [转载] 散列表(Hash Table)从理论到实用(中)
    [转载] 散列表(Hash Table)从理论到实用(上)
    Android 之窗口小部件高级篇--App Widget 之 RemoteViews
    Android控件之GridView
    红黑树(一)之 原理和算法详细介绍
  • 原文地址:https://www.cnblogs.com/mzzcy/p/7231892.html
Copyright © 2011-2022 走看看