Java 泛型小结

摘要:
泛型有两个主要好处:消除显示的强制类型转换,改进代码重用,提供更强的类型检查,避免在运行时使用ClassCastException3,以及使用类型参数作为占位符来指示在运行时将类型分配给类。表示不确定的java类型4。有界泛型˂?Classc1=newArrayList<Integer>().getClass();Classc2=newArrayList<Long>().getClass();System.out.println;这是由Java泛型的类型擦除引起的,因为编译器在编译期间会将ArrayList<Integer>和ArrayList>都擦除到ArrayList中。Java在创建泛型实例时应避免创建新类,以避免在运行时过度消耗的原因。

1、什么是泛型?

 

泛型(Generics )是把类型参数化,运用于类、接口、方法中,可以通过执行泛型类型调用 分配一个类型,将用分配的具体类型替换泛型类型。然后,所分配的类型将用于限制容器内使用的值,这样就无需进行类型转换,还可以在编译时提供更强的类型检查。 

 

2、泛型有什么用?

 

泛型主要有两个好处:

 

(1)消除显示的强制类型转换,提高代码复用

 

(2)提供更强的类型检查,避免运行时的ClassCastException

 

3、泛型的使用

 

类型参数(又称类型变量)用作占位符,指示在运行时为类分配类型。根据需要,可能有一个或多个类型参数,并且可以用于整个类。根据惯例,类型参数是单个大写字母,该字母用于指示所定义的参数类型。下面列出每个用例的标准类型参数:

 

E:元素

K:键

N:数字

T:类型

V:值

S、U、V 等:多参数情况中的第 2、3、4 个类型

? 表示不确定的java类型(无限制通配符类型)

 

4、有界泛型

<? extends T>:是指 “ 上界通配符 (Upper Bounds Wildcards) ”

 

<? super T>:是指 “ 下界通配符 (Lower Bounds Wildcards) ”

 

—这里有个坑

如 List<? extends T> 大家以为元素为 T以及其所有子类的对象 的List。其实不是。元素类型 仅指T的某一个不确定的子类,是单一的一个不确定类,没有具体哪个类。因此不能插入一个不确定的。

 

List<? super T> 大家以为元素为 T以及其父类的对象 的List。其实不是,元素类型 仅指T的某一个不确定的父类,是单一的一个不确定类(只确定是T的父类),没有具体哪个类。

 

因此:

 

不能往List<? extends T>中插入任何类型的对象。唯一可以保证的是,你可以从中读取到T或者T的子类。

 

可以往List<? super T>中插入T或者T子类的对象,但不可以插入T父类的对象。可以读取到Object或者Object子类的对象(你并不知道具体的子类是什么)

总结一下:

如果频繁支持读取数据,不要求写数据,使用<? extends T>。即生产者 使用 <? extends T>;

如果频繁支持写入数据,不特别要求读数据,使用<? super T>。即消费者 使用 <? super T>;

如果都需要支持,使用<T>。 

5、类型擦除

Java的泛型在编译期间,所有的泛型信息都会被擦除掉。 

  • Class c1 = new ArrayList<Integer>().getClass();  

    Class c2 = new ArrayList<Long>().getClass();   

    System.out.println(c1 == c2); 

    这就是 Java 泛型的类型擦除造成的,因为不管是 ArrayList<Integer> 还是 ArrayList<Long>,在编译时都会被编译器擦除成了 ArrayList。Java 之所以要避免在创建泛型实例时而创建新的类,从而避免运行时的过度消耗。

6、泛型类型信息 

  • 那么,如果我们确实某些场景,如HTTP或RPC或jackson需要获取泛型进行序列化反序列化的时候,需要获取泛型类型信息。

    可以参照如下:

  • 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    //获取运行时的泛型类型信息
    publicclassTest2 {
      
        staticclassParameterizedTypeReference<T> {
            protectedfinal Type type;
      
            publicParameterizedTypeReference() {
                Type superClass = this.getClass().getGenericSuperclass();
                //if (superClass instanceof Class) {
        // throw new IllegalArgumentException(
    //"Internal error: TypeReference constructed without actual type information");
                //  } else {
                    this.type = ((ParameterizedType) superClass).getActualTypeArguments()[0];
                //}
            }
      
            publicType getType() {
                returntype;
            }
        }
      
        publicstaticvoidmain(String[] args) {
    // System.out.println(new ParameterizedTypeReference<String>().getType());
    // java.lang.ClassCastException: java.lang.Class cannot be cast to java.lang.reflect.ParameterizedType
    // 此处会输出报错,因此ParameterizedTypeReference 应不能直接实例化,可以考虑加abstract
      
            System.out.println(newParameterizedTypeReference<String>() { }.getType());
    // ParameterizedTypeReference 的匿名内部类,可以触发super(),
    //即 ParameterizedTypeReference()的构造器逻辑,正常运行
        }
      
    }

      

  • 注意一个关键点:

    可以通过定义类的方式(通常为匿名内部类,因为我们创建这个类只是为了获得泛型信息)在运行时获得泛型参数。

免责声明:文章转载自《Java 泛型小结》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇appium+Python真机运行测试demo的方法make的link_directories命令不起作用下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

SQL 里ESCAPE的用法

TABLES:makt. SELECT SINGLE * FROMmakt WHERE spras = 1 AND maktx LIKE '%/_' ESCAPE '/' . SQL中escape的用法使用 ESCAPE 关键字定义转义符。 在模式中,当转义符置于通配符之前时,该通配符就解释为普通字符。例如,要搜索在任意位置包含字符串...

【Ubuntu】Ubuntu常用文件操作命令

Ubuntu下修改目录权限需要先用 sudo 来获得管理员权限,格式如下: sudo chmod 600 ××× (只有所有者有读和写的权限) sudo chmod 644 ××× (所有者有读和写的权限,组用户只有读的权限) sudo chmod 700 ××× (只有所有者有读和写以及执行的权限) sudo chmod 666 ××× (每个人都有读和...

C#集合与泛型集合

看到这个标题,大家应该就知道有泛型集合,就有非泛型集合 既然都是集合,咱们今儿就简单的来对比讲解下 需要记住的不算太多,理解记忆、理解记忆  2017-11-0411:39:09 C# 泛型集合之非泛型集合类与泛型集合类的对应: *****ArrayList对应List       ***HashTable对应Dictionary *****Queue对应...

奇技淫巧:F#泛型特化的最终优化

上回讲到,F#中module里的泛型变量实际上是泛型函数。由此,在一个泛型特化的实现中出了岔子。最后通过泛型得以解决。使用 F# 来做泛型特化,相比 C# 有这个优势:F# 中直接支持函数赋值,而无须使用委托。避免了 C# 例子里面,为了节省 Lumbda 与委托之间的转换,而做出的丑陋的反射、拆箱操作。代码不再这么艰涩,我们重新来看看这段代码: modu...

配置typeAliasesPackage支持通配符包路径扫描

mybatis的xml文件中需要写类的全限定名,较繁琐,可以配置自动扫描包路径给类配置别名,两种配置方式。 方式一: mybatis-config.xml中配置 <typeAliases>   <package name="com.xiaomu.context.config.model"/> </typeAliases&g...

MQTT协议中的topic

1、MQTT协议中的topic 定阅与发布必须要有主题,只有当定阅了某个主题后,才能收到相应主题的payload,才能进行通信。 2、 主题层级分隔符——“/” 主题层级分隔符使得主题名结构化。如果存在分隔符,它将主题名分割为多个主题层级。 斜杠(‘/’ U+002F)用于分割主题的每个层级,为主题名提供一个分层结构。当客户端订阅指定的主题过滤器包含两种通...