zoukankan      html  css  js  c++  java
  • Java 泛型及相关使用

    面试时遇到一个问题,泛型如何获取真实的类型?GG,下来以后查了相关资料,看了几遍才懂是啥意思,写在这里牢记!

    泛型

    泛型——就是将类型的明确推迟到创建对象或执行方法时再进行。泛型相当于一个参数,修饰这个类实际上是什么。
    举例来说:
    ArrayList中,E就是一个未定的参数,而ArrayList中,Integer就被固定为一个确定的实际参数了。
    整个ArrayList被称作一个泛型类型,而ArrayList被称作参数化的类型(ParameterizedType)。
    定义一个含泛型参数T的类,然后在类中设置一个T变量,和在类中直接定义一个Object类相比,有如下的好处:

    1. 在创建这个泛型类时,T的类型就被固定下来了,不会出现被传入错误参数的情况;
    2. 获取T的时候,获取到的是实际类型,而不需要再进行一次强转,以免出现强转问题。

    在实例化一个泛型类时,如果不使用<>指定类型,或者使用<?>指定类型,那么泛型参数就相当于Object,泛型类就失去了泛型的作用。
    在实例化一个泛型类时,如果使用<?>定义,可以在?后面附加条件extends A或 super A。前者表示届时这个参数化类型变量应该是A的子类,后者表示届时这个参数化类型变量应该是B的超类(祖先类)。

    此外,在定义时,可以使用来缩小填入的参数的类型范围。

    泛型擦除

    泛型类在编译后,<>中的类型信息会被擦除,在内存中实际表现为Object类。而在get()等方法需要返回确切类型的地方,实际的泛型参数类型会被直接写入。
    例如ArrayList,在编译后,内存中仅表现为ArrayList,其get()方法会由

    E get(){/* ... */}
    

    变成

    Integer get(){/*  ... */}
    

    以ArrayList为例,调用get()方法从内部Object[]数组中拿到原始数据,然后强转为Integer并返回。

    既然有泛型擦除的概念,那么对于一个表面定型,其实不定型的ArrayList来说,要插入一个别的元素也是可以做到的。使用反射拿到ArrayList的add(Object o)方法,即可插入一个其他元素。

        ArrayList<Integer> ai = new ArrayList<>();
        ai.add(123);
        try {
            ai.getClass().getDeclaredMethod("add",Object.class).invoke(ai,"string");
        } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
            e.printStackTrace();
        }
        for (Object o:ai)
            System.out.println(o);
        for (Integer i:ai)
            // 运行时会报ClassCastException,因为有一个String无法被转为Integer
            System.out.println(i);
    

    泛型获取真实类型

    泛型如何获取到真实类型呢?我们分为三种情况来分析

    1.某个类继承了某个泛型类型

        private static class Generic<T extends Number>{
            T data;
            int id;
        }
    
        private static class ExtendedGeneric extends Generic<Integer>{
            private void te(){
    
            }
        }
    
        public static void main(String[] args) throws Exception {
            Type t= ((ParameterizedType) ExtendedGeneric.class.
                    getGenericSuperclass()).getActualTypeArguments()
                    [0];
            System.out.println(t.getTypeName());
        }
    
    运行结果:java.lang.Integer
    

    2.某个类实现了某个泛型接口

    
        private interface GenericInterface<P>{
            P getP();
        }
    
        private static class ImplGeneric implements GenericInterface<Pipe>{
            @Override
            public Pipe getP() {
                return null;
            }
        }
    
        public static void main(String[] args) throws Exception {
            Type t= ((ParameterizedType) ImplGeneric.class.
                    getGenericInterfaces()[0]).getActualTypeArguments()
                    [0];
            System.out.println(t.getTypeName());
        }
    
    运行结果:java.nio.channels.Pipe
    

    提示:这里和情况1很类似,只是父类只能有一个,接口可以有很多,所以getGenericSuperclass()返回的是一个Type,而getGenericInterfaces()返回的是一个Type[]数组。

    3.某个方法的返回参数为泛型类型

    这种情况下没有什么靠谱的方法,如果能确保这个泛型类型不为空,且值是统一的(不存在前述的那种反射写入其他类型的情况),可以通过不靠谱的方法得到。代码如下:

        public static void main(String[] args) throws Exception {
            ArrayList<String > strings = new ArrayList<>();
            strings.add("123");
            Class<?> c= ArrayList.class.getDeclaredMethod("get", int.class)
                    .invoke(strings,0).getClass();
            System.out.println(c.getName());
        }
    
    运行结果:java.lang.String
    
  • 相关阅读:
    gridFS-Nginx的安装与使用
    centos下利用phantomjs来完成网站页面快照截图
    linux下安装php的svn模块
    在Thinkphp3.1中使用Mongo的具体操作
    CentOS 6.4安装mongo的php扩展包
    在centos6.3下安装php的Xdebug
    在yum安装lamp的环境下安装coreseek以及php的sphinx扩展
    CentOS 6.4下通过YUM快速安装配置LAMP服务器(Apache+PHP5+MySQL)
    微信中web页面实现和公众号中查看图片一样的效果
    ionic学习教程地址梳理
  • 原文地址:https://www.cnblogs.com/pravez/p/12542190.html
Copyright © 2011-2022 走看看