• 泛型


    泛型是什么?

    泛型本质是指类型参数化。意思是允许在定义类、接口、方法时使用类型形参,当使用时指定具体类型,所有使用该泛型参数的地方都被统一化,保证类型一致。如果未指定具体类型,默认是Object类型。集合体系中的所有类都增加了泛型,泛型也主要用在集合。
     

    泛型的定义

    泛型类:public class Demo<T> {} ,T表示未知类型。
    泛型接口:public interface ImplDemo<T,V>{} ,和定义类一样(接口就是一个特殊类)。
    泛型方法:public <T>  void demo1(T name){System.out.println(name);} , public <T> T demo2(T t){ return t;}
     

    泛型的好处

    1. 编译时确定类型,保证类型安全,避免类型转换异常。
    2. 避免了强制类型转换。
    3. 代码利于重用,增加通用性。

    泛型的限制和规则

    • 泛型的类型参数只能是引用类型,不能使用值类型。
    • 泛型的类型参数可以有多个。
    • 泛型类不是真正存在的类,不能使用instanceof运算符。
    • 泛型类的类型参数不能用在静态申明。
    • 如果定义了泛型,不指定具体类型,泛型默认指定为Ojbect类型。
    • 泛型使用?作为类型通配符,表示未知类型,可以匹配任何类型。因为是未知,所以无法添加元素。
    • 类型通配符上限:<? extends T>,?代表是T类型本身或者是T的子类型。常用于泛型方法,避免类型转换。
    • 类型通配符下限。<? super T>,?代表T类型本身或者是T的父类型。
    • 除了通配符可以实现限制,类、接口和方法中定义的泛型参数也能限制上限和下限。
    定义泛型类
    public class Person<T> {
        private T name;//类型是未知的
        
        public Person(T name) {
            this.name = name;
        }    
        
        public T getName() {
            return name;
        }
        
        public void sexName(T name) {
            this.name = name;
        }
    
    }
    在上面实例中,Person类定义成泛型类,成员变量name的类型指定为T,表示未知类型。实例化该类对象后,可以看到name的类型是Object,表示可以接收任何类型。
    Person p = new Person(10);    //new Person(Object name)
    
    加上泛型后
    //使用泛型两种方式
    Person<String> ps = new Person<String>(); //new Person<String>(String name)
    Person<String> ps = new Person<>();//new Person<>(T name)
    第一种,会直接确定参数类型是什么,而第二种的参数类型是T ,但如果加入的非String类型,编译器会检查并报错。两者区别不大。在JDK1.7之后使用第二种,会自动检查泛型,可以省略后部分<>的泛型参数,建议使用第二种。
    定义泛型接口
    interface A<T>{
        void display(T value); 
        T getValue(T v);
    }
    //未对泛型接口指定具体类型
    public class Person implements A{
    
        @Override
        public void display(Object obj) {
            System.out.println();
        }
    
        @Override
        public Object getValue(Object v) {
            return null;
        }
        
    }
    当我们为泛型接口指定具体类型后,代码如下:
    
    //泛型接口
    interface A<T>{
        void display(T value); 
        T getValue(T v);
    }
    
    //为泛型接口指定具体类型
    public class Person implements A<String>{
        @Override
        public void display(String value) {
        }
        @Override
        public String getValue(String v) {
            return null;
        }
    }

    定义泛型方法

    public static void main(String[] args) {
            Integer[] arr =  {1, 8, 15, 6, 3};
            Double[] douArr = {10.5, 25.1, 4.9, 1.8};
            String[] strArr = {"我","是","字","符","串"};
            
            forArrGenric(strArr);
            
        }
        //泛型方法
        public static <T> void forArrGenric(T[] arr) {
            for(int i=0; i < arr.length; i++) {
                System.out.println(arr[i]);
            }
        }
    使用类型通配符

    使用之前,先使用常规方式来进行比较。
    public static void main(String[] args) { HashSet hs = new HashSet(); hs.add("A"); hs.add("QQ"); hs.add("Alipay"); new Test2().test2(hs); } //普通遍历Set集合,Set是泛型接口,没指定具体泛型参数会引起警告 public void test(Set s) { for(Object o : s) System.out.println(o); } //增加泛型参数,参数类型是Set<Object> public void test2(Set<Object> s) { for(Object o : s) System.out.println(o); }

    方法参数的Set集合使用了泛型参数
    <Object>,方便将参数类型转换成Object,看起来没什么错。当传入一个带泛型参数的集合时,会出现编译错误。代码如下: public static void main(String[] args) { HashSet<String> hs = new HashSet(); hs.add("A"); hs.add("QQ"); hs.add("Alipay"); new Test2().test2(hs); //error } //增加泛型参数,参数类型是Set<Object> public void test2(Set<Object> s) { for(Object o : s) System.out.println(o); } 因为泛型类不是真正存在的类,所以Set<String>和Set<Object>不存在关系,自然无法作为参数传入进去。这时我们就可以使用类型通配符,如下: //使用类型通配符作为类型参数 public void test2(Set<?> s) { for(Object o : s) System.out.println(o); } Set<?>表示可以匹配任意的泛型Set。虽然可以使用各种泛型Set了。但弊端就是类型未知,所以无法添加元素。还有范围过于广泛,所以这时可以考虑限制的类型通配符。 限制的类型通配符

    上面代码只要是泛型Set都允许被遍历,如果只想类型通配符表示一个类和其子类本身呢?设置类型通配符上限,代码如下:
    public class Test2 { public static void main(String[] args) { ArrayList<Test2> ar = new ArrayList<>(); List<Test3> lt = new ArrayList<>(); List<String> lStr = new ArrayList<>(); demo(ar); demo(lt); demo(lStr); //error } //限制的类型通配符 public static void demo(List<? extends Test2> t) { for(int i = 0; i < t.size(); i++) { System.out.println(t.get(i)); } } } class Test3 extends Test2{}//子类 <? extends T>:表示类型是T本身或者是T类型的子类类型。 <? super T>:表示类型是T类型本身或者是T类型的父类类型。叫做类型通配符的下限。使用方式都差不多。
  • 相关阅读:
    Linux 服务器 个人常用操作命令记录
    Thinkphp5.0 自定义命令command的使用
    vue初学之node.js安装、cnpm安装、vue初体验
    php实现在不同国家显示网站的不同语言版本
    array_map、array_walk、array_filter三个函数的区别
    实现简单点赞功能
    SQL语言-----数据操作
    SQL语言
    MySQL高可用架构之Keepalived+主从架构部署
    MyCAT源码分析——分析环境部署
  • 原文地址:https://www.cnblogs.com/xiaozhang666/p/13098997.html
Copyright © 2020-2023  润新知