JAVA基础_泛型

Posted 高山仰止

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JAVA基础_泛型相关的知识,希望对你有一定的参考价值。

什么是泛型


泛型是提供给javac编译器使用的,可以限定集合中的输入类型,让编译器挡住源程序中的非法输入,编译器编译带类型说明的集合时会去除掉”类型”信息,是程序的运行效率不受影响,对于参数化的泛型类型,getClass()方法返回值和原始类型完全一样。由于编译生成的字节码会擦除泛型的类型信息,只要能跳过编译器,就可以往某个泛型集合中加入其它类型的数据,例如,用反射得到集合,然后再调用add()方法即可


GenericDemo.java

public class GenericDemo {
    
    public static void main(String[] args) {
        
        // 未使用泛型,则可以添加任意Object类型的数据
        List noGrnerics = new ArrayList<>();
        noGrnerics.add(1);
        noGrnerics.add("hello");
        noGrnerics.add("1L");
        noGrnerics.add(new GenericDomain(1L,"Generic"));
        // 由于没有使用泛型,在取出数据时必须要知道某个位置上的某个数据的数据类型,并加以强制转换,否则要出错,除非用Object接收。
        Integer integer = (Integer) noGrnerics.get(0);
        System.out.println("integer = " + integer);
        // 由于不知道某个位置上的数据类型,用Object接收
        Object objIndex1 = noGrnerics.get(1);
        System.out.println("objIndex1 = " + objIndex1);
        Object objeIndex3 = noGrnerics.get(3);
        System.out.println("objeIndex3 = " + objeIndex3);
        // 虽然可以通过类对象来知道类属性,但是这样不是太麻烦了吗??
        System.out.println("objeIndex3.getClass() = " + objeIndex3.getClass());
    
        
        // 使用泛型
        List<String> strs = new ArrayList<>();
        strs.add("str1");
        strs.add("str2");
        strs.add("str3");
        // 因为指定了这个List中只能放置String类型的数据,当这里放置其他类型的数据时就会报错,因为不能装进去
        // 从某种角度上可以认为泛型解决了强制类型转换,使数据特征更明显,拥有一致性
//        strs.add(1);
        String str = strs.get(0);
        System.out.println("str = " + str);
        
    }

}

绕过编译时泛型,添加非泛型类型数据:GenericDemo2.java

public class GenericDemo2 {

    /**
     * 程序目标,向一个List<String>的泛型数组中添加Integer类型的数据
     * 
     * @param args
     */
    public static void main(String[] args) {

        List<String> strs = new ArrayList<>();
        strs.add("str1");
        strs.add("str2");
        strs.add("str3");
        strs.add("str4");
        // 这里是添加不进去的,因为指定了泛型类型,且没有泛型擦除
        // strs.add(new Integer(1));
        System.out.println("Before add a Integer value : " + strs);

        // 通过泛型在运行时擦除的原理,利用反射向泛型中添加Integer数据
        Class<List<String>> clazz = (Class<List<String>>) strs.getClass();
        try {
            // 这里在利用反射获取add方法时,如果参数类型指定为String.class,
            // 则说明add方法为,java.util.ArrayList.add(java.lang.String)
            // 而我们传入了一个Integer类型的数据,则显然不能添加成功,会抛出 java.lang.NoSuchMethodException
            clazz.getDeclaredMethod("add", String.class).invoke(strs, new Integer(1));
            // 这里原因一样,java.util.ArrayList.add(java.lang.Integer) 但是用的int,
            // 请记住,java是强类型语言,这里不存在自动装箱和拆箱
            clazz.getDeclaredMethod("add", Integer.class).invoke(strs, 2);
            // 这里也是不正确的,因为Class<List<String>>指定了放String
            clazz.getDeclaredMethod("add", Integer.class).invoke(strs, new Integer(4));
            //同上
            clazz.getDeclaredMethod("add", int.class).invoke(strs, 5);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //正确做法
            try {
                clazz.getDeclaredMethod("add", Object.class).invoke(strs, 3);
                System.out.println("strs = " + strs);
                // 只有Object能行
                clazz.getDeclaredMethod("add", String.class).invoke(strs, "4");
                System.out.println("strs = " + strs);
            } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException
                    | NoSuchMethodException | SecurityException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        System.out.println("After add a Integer value : " + strs);
    }

    
}


以上是关于JAVA基础_泛型的主要内容,如果未能解决你的问题,请参考以下文章

JAVA基础_泛型

Java基础_集合泛型

阶段1 语言基础+高级_1-3-Java语言高级_04-集合_02 泛型_3_定义和使用含有泛型的类

操作 Java 泛型:泛型在继承方面体现与通配符使用

Java基础系列--08_集合1

Java泛型:类型擦除