• java 泛型


    泛型

    泛型,即“参数化类型”.

    泛型,将类型由原来的具体的类型参数化,类似于方法中的变量参数,此时类型也定义成参数形式(可以称之为类型形参),然后在调用时传入具体的类型(类型实参)。

    泛型的好处

    • 类型安全,消除强制类型转换。 泛型消除源代码中的许多强制类型转换。这使得代码更加可读,并且减少了出错机会。

    • 减少重复代码。 提高代码的重用率,同样的逻辑,使用泛型后,能够支持多种类型,不同类型不用写重复代码。

    Java泛型中的标记符含义:

    E - Element (元素,在集合中使用)
    
    T - Type(Java 类)
    
    K - Key(键)
    
    V - Value(值)
    
    N - Number(数值类型)
    
    ? - 表示不确定的java类型
    
    S、U、V - 2nd(第二)、3rd(第三)、4th(第四) 类型
    
    
    

    List集合的泛型

    比如,最常见的List集合,List常用方法的源码如下:

    在List接口中采用泛型定义之后, List<E>中的E表示类型形参,声明List并指定类型E后,凡是出现E的地方均表示相同的类型(类型实参)。

    public interface List<E> extends Collection<E> {
        boolean add(E e);
    
        E get(int index);
    }
    

    示例如下:

    public class ListTest {
        public static void main(String[] args) {
        	//声明集合list的泛型<E>为 String类型
            List<String> list = new ArrayList<>();
            list.add("ab");
            list.add("cd");
            //由于list指定了泛型是String,那么add(E e)方法的参数E只能是String类型,添加整数到该集合会报错
    //        list.add(123);
    
            //由于 list 指定了泛型是 String,调用get方法直接得到String,而不需要做类型转换
            String first = list.get(0);
    
    
        }
    }
    
    

    泛型类、泛型接口和泛型方法

    泛型的常见用法有 泛型类、泛型接口、泛型方法。

    上面的 interface List<E> 就是一个典型的泛型接口。

    泛型类跟泛型接口类似,也可以在类后面声明泛型。

    泛型类

    示例如下:

    /**
     * 泛型类, User<T>定义了泛型类型为T,那么变量T data和方法T getData()中的 T类型也得跟定义的类型一样。
     *
     * @param <T>
     */
    public class User<T> {
    
        private T data;
    
        public User(T data) {
            this.data = data;
        }
    
        public User() {
        }
    
        public T getData() {
            return data;
        }
    
        public void setData(T data) {
            this.data = data;
        }
    
        public static void main(String[] args) {
            //User<Integer>定义了泛型类型为Integer, 那么data就必须是 Integer
            User<Integer> user1 = new User<>();
            user1.setData(10);
            System.out.println(user1.getData());
    
            //User<String>定义了泛型类型为 String, 那么data就必须是 String
            User<String> user2 = new User<>();
            user2.setData("Rui");
            System.out.println(user2.getData());
        }
    }
    
    

    泛型方法

    泛型方法的格式如下:

    修饰符 <声明泛型的类型> 返回的类型 方法名称();
    

    比如:

    public  <T> void getUserName(T t) {}
    

    在返回类型的前面声明 泛型类型 <T> ,那么方法的所有 T 类型与声明的类型一样。

    如果需要限制 T的类型为 继承User的类,可以使用 T extends User,如下所示:

    public  <T extends User>  void getUserName(T t) {
    
    }
    
    

    如果是多个泛型,则用逗号隔开,如:

    public  <T,M> String getUserName(T t, M m) {}
    

    示例如下:

    public class Book {
    
        /**
         * 泛型方法
         * @param t  泛型对应的参数
         * @param <T> 泛型的类型
         * @return
         */
        public  <T> String getName(T t){
            return t.toString();
        }
    
        /**
         * 存在多个泛型的泛型方法
         * @param t  第一个泛型对应的参数
         * @param m  第二个泛型对应的参数
         * @param <T>  第一个泛型的类型
         * @param <M>  第二个泛型的类型
         * @return
         */
        public  <T,M> String getMergeName(T t, M m) {
            return t.toString() + m.toString();
        }
    
        public static void main(String[] args) {
            Book book = new Book();
            System.out.println(book.getName("abc"));
            System.out.println(book.getName(123));
            System.out.println(book.getName(book));
    
            System.out.println(book.getMergeName("abc", 123));
        }
    
    }
    

    类型通配符

    类型通配符?的含义如下:

    <?extends T>表示有上限的通配符,能接受其类型和其子类的类型, 此时 T 即泛型类型的上边界
    
    <?super T> 表示有下限的通配符,能接受指定类型及其父类类型,此时 T 即泛型类型的下边界
    
    

    在List集合中,就有大量的类型通配符的应用。

        boolean addAll(Collection<? extends E> c);
        
        void sort(Comparator<? super E> c);
    

    类型通配符的使用,如下:

    public class GenericTest {
    
    
        class Father {
    
        }
    
        class Son extends Father {
    
        }
    
        /**
         * 使用了类型通配符,只允许 继承了Father的类作为泛型的类型
         * @param list
         */
        public static void select(List<? extends Father> list) {
    
        }
    
    
    
        public static void main(String[] args){
            List<Father> list1 = new ArrayList<>();
            List<Son> list2 = new ArrayList<>();
            List<String> list3 = new ArrayList<>();
            select(list1);
            select(list2);
            //list3的泛型为 String,并没有继承 Father,编译会报错: Required type: List <? extends Father>
    //        select(list3);
        }
    
    }
    
    • 类型通配符与泛型方法的区别:

      类型通配符既可以在方法签名处定义形参的类型, 也可以用于定义变量的类型;

      但是泛型方法中的泛型形参必须在对应方法中声明.

    参考资料:

    https://www.cnblogs.com/lwbqqyumidi/p/3837629.html

    https://juejin.cn/post/6940449645877264391

    https://blog.csdn.net/qq_39505065/article/details/89490776

  • 相关阅读:
    (Go)03.go类型
    (Go)02.go 安装delve调试工具测试
    (Go)01.Windows 安装 Go语言开发环境以及使用
    etcd创建集群并增加节点
    libhiredis.so.0.13 => not found 缺少
    Linux查找并杀死僵尸进程
    k8s istio 配置请求的路由规则
    k8s 安装并试用Istio service mesh
    k8s Job、Cronjob 的使用
    k8s Gitlab CI/CD 之自动编译Docker镜像并推送到指定的Registry
  • 原文地址:https://www.cnblogs.com/expiator/p/16168967.html
Copyright © 2020-2023  润新知