zoukankan      html  css  js  c++  java
  • Java泛型

    1.概述

    泛型:把类型明确的工作推迟到创建对象或调用方法的时候才去明确的特殊的类型。也就是说在创建对象或调用方法时才知道具体的类型,而在定义类或方法时不需要明确,而是使用通用的类型代替。在使用时把类型当做参数进行传递。

    设计原则:只要在编译时期没有出现警告,那么运行时期就不会出现ClassCastException异常。

    泛型的由来:早期Java是使用Object来代表任意类型的,但是向下转型有强转的问题,这样程序就不太安全。而使用泛型,不用强制转换使得代码更加简洁,提升了可读性和稳定性。

    2.泛型常用值

    泛型有几种的常用的值,如下表

    说明
    T Type的简称,代表java类
    E Element的简称,代表元素 (用在集合中)
    K Key的简称,代表键,主要用于Map类
    V Value的简称,代表值,主要用于Map类
    类型通配符,表示不确定的类型,可使用任意类型

    3. T的用法

    3.1泛型类

    把泛型定义在类上,使用该类的时候,才把类型明确下来。然后在方法中就可以使用传入的类型。

    1)定义泛型类

    需求:传入一个List集合,无论什么类型,只要有元素就取第一条数据。

    import java.util.List;
    
    public class MyClass<T> {  // 1
    
        public T getFirst(List<T> list) { //2
            if (list == null || list.size() == 0) {
                return null;
            }
            return list.get(0);
        }
    
    }

    在代码中,1处的<T>是给类添加了泛型。2处有两个T,前面的T是指定方法的返回值。后面的<T>是给List类添加了泛型,从而保证List的元素类型和方法返回值一致。

    2)使用泛型类

        public static void main(String[] args) {
            MyClass<String> myClass = new MyClass<>();
            List<String> list = new ArrayList<>();
            list.add("张三");
            list.add("tom");
            System.out.println(myClass.getFirst(list));//张三
    
            MyClass<Map<String, String>> myClass2 = new MyClass<>();
            List<Map<String, String>> list2 = new ArrayList<>();
            Map<String, String> map = new HashMap<>();
            map.put("name", "tom");
            Map<String, String> map2 = new HashMap<>();
            map2.put("age", "20");
            list2.add(map);
            list2.add(map2);
            System.out.println(myClass2.getFirst(list2));//{name=tom}
        }

     当传入String类型时,就返回String类型;传入Map类型时就返回Map类型。

    3.2泛型方法

    若仅仅在某一个方法上需要使用泛型,那么就不需要对整个类添加泛型,而是给方法添加泛型即可。

    将上述的泛型类进行修改,变成泛型方法:

    1)定义泛型方法

    import java.util.List;
    
    public class MyClass {
    
        public <T> T getFirst(List<T> list) {
            if (list == null || list.size() == 0) {
                return null;
            }
            return list.get(0);
        }
    }

    在方法上有三个T,第一个<T>是指定此方法是一个泛型方法,第二个和第三个T的用法同上。

    2)使用泛型方法

        public static void main(String[] args) {
            MyClass myClass = new MyClass();
            List<String> list = new ArrayList<>();
            list.add("张三");
            list.add("tom");
            System.out.println(myClass.getFirst(list));//张三
    
            MyClass myClass2 = new MyClass();
            List<Map<String, String>> list2 = new ArrayList<>();
            Map<String, String> map = new HashMap<>();
            map.put("name", "tom");
            Map<String, String> map2 = new HashMap<>();
            map2.put("age", "20");
            list2.add(map);
            list2.add(map2);
            System.out.println(myClass2.getFirst(list2));//{name=tom}
        }

    通过对比可以发现,这种方式比泛型类简单一点,但效果是一样的,可根据需求进行选择。

    4. E的用法

    由于E表示元素,主要用在List集合,因此直接放List的部分源码:

    public class ArrayList<E> extends AbstractList<E>
            implements List<E>, RandomAccess, Cloneable, java.io.Serializable
    {
        private static final long serialVersionUID = 8683452581122892189L;
    
        ....
    }

    这是ArrayList类的定义,使用E作为泛型。

    5. K、V的用法

    由于K、V表示键和值,主要用在Map中,因此直接放Map的部分源码:

    public class HashMap<K,V> extends AbstractMap<K,V>
        implements Map<K,V>, Cloneable, Serializable {
    
        private static final long serialVersionUID = 362498820763181265L;
       ...
    
    }

    6. ?的用法

    ?虽然可以表示任何类型,但在单独使用时只能用在方法的参数类型上。

    6.1定义泛型方法

    需求:遍历不同类型的集合的元素并打印

        public void listFor(List<?> list){
            if (list != null && list.size() != 0) {
                list.forEach(item->{
                    System.out.println(item);
                });
            }
        }

    这里使用?代替了集合的元素类型。

    6.2 Class<?>用法

     上一小节,传递的参数都是先创建了对象并赋值,再把这个对象通过参数进行传递的。那么当只需要明确参数的类型,不需要对象中的值时,可以使用Class<?>。可以用在类的类型和方法的参数上。

    1)用在方法的参数上

        public void getClassField(Class<?> pojoClass) throws NoSuchFieldException {
            Field field = pojoClass.getClass().getDeclaredField("name");
            System.out.println(field.getGenericType());
        }

    上述代码是通过反射机制用来获取类中name属性的类型,若不存在就会抛出异常。

    调用方式:

    MyClass myClass2 = new MyClass();
    myClass2.getClassField(MyClass2.class);

    传递时,指定的类,后面使用.class标识。除此之外,还可以用在构造方法上,例如:

    public class MyClass2 {
    
      private Class<?> entityClass;
    
      public MyClass2(Class<?> entityClass) {
        this.entityClass = entityClass;
      }
      
    }

    调用:

    MyClass2 myClass22 = new MyClass2(String.class);

    在创建对象时传入指定类型。

    就是这么简单,你学废了吗?感觉有用的话,给笔者点个赞吧 !
  • 相关阅读:
    解决本地浏览器的跨域问题
    页面嵌入iframe关于父子传参调用
    仿微信、qq聊天,@好友功能
    创建新react项目 运行npm start 报错踩过的坑
    前端向后端获取数据的三种方法:ajax、axios、fetch
    观察者模式代码详解
    代理模式实现图片预加载、懒加载
    网站登录注册-Session 和token的总结
    浅谈MVC、MVVM的区别
    vue中methods、computed、watch区别
  • 原文地址:https://www.cnblogs.com/zys2019/p/14841044.html
Copyright © 2011-2022 走看看