聊一聊泛型的可空性(kotlin)

简介: 什么?泛型本身也可以是nullable?上来就抛这么个问题实在是不够友好~ 首先回顾,什么是泛型?[Oracle Java Tutorials](https://docs.oracle.com/javase/tutorial/extra/generics/index.html) > Introduced in J2SE 5.0, this long-awaited enhancemen

什么?泛型本身也可以是nullable?上来就抛这么个问题实在是不够友好~

首先回顾,什么是泛型?Oracle Java Tutorials

Introduced in J2SE 5.0, this long-awaited enhancement to the type system allows a type or method to operate on objects of various types while providing compile-time type safety. It adds compile-time type safety to the Collections Framework and eliminates the drudgery of casting.

泛型的本质是参数化类型,也就是说操作的数据类型被指定为一个参数。简单来讲,泛型就是操作类型的占位符。

那,为什么要使用泛型?Oracle Java Tutorials

In a nutshell, generics enable types (classes and interfaces) to be parameters when defining classes, interfaces and methods. Much like the more familiar formal parameters used in method declarations, type parameters provide a way for you to re-use the same code with different inputs. The difference is that the inputs to formal parameters are values, while the inputs to type parameters are types.

泛型的好处是在编译的时候做类型安全检查,并且所有的强制转换都是自动和隐式的,提高代码的重用率。

在深入讨论泛型的可空性之前,首先看一个简单的例子 (kotlin中更多泛型的介绍,以及其与java泛型的区别,可以查看Generics)

    fun <T> whoAmI(t: T) {
        val clazz = t::class
        println("I'm $clazz")
    }

上面的代码是编译不过的,问题在于

image-20181106093104446.png

nullable type 'T'是什么鬼?OK,我们按照提示,为参数t加上!!强制标识为not-null (关于!!的使用,可以查看 Null Safety)

image-20181106093259249.png

WTF~ 哔~ 卒~

在继续讨论之前,先关注两个概念,type parametertype argument,在一个函数中,前者是函数参数的类型(类型),如translate(java.lang.String, java.lang.String)中的java.lang.String,而后者则是函数调用时传入的具体值(类型),如translate("Hello You!", "zh-cn")中的Hello Youzh-cn,泛型作为一个占位符,占的正是type parameter的位

首先简单了解一下argument的可空性,kotlin中控制函数参数值(类属性值等)的nullable是通过?符号实现的,默认均为non-nullable,如以下代码片段是编译不过的

image-20181107090844996.png

只有指定参数namenullable,才可以顺利编译

image-20181107091014490.png

同样,对应泛型类,我们也可以指定nullablenon-nullabletype argument

image-20181107092315176.png

从上例中可以看到,null在kotlin中的类型为Nothing?(kotlin中一切皆为对象)

更多内容请参考 Null Safety

说了这么多,到底什么是泛型的可空性(type argumentnullable)?

上例中,之所以可以将forestA指定为Forest<Tree?>,是因为,每一个nullabletype argument都有一个隐式边界Any?,即如下两种类声明完全等价

    // T的隐式边界为Any?
    class Forest<T>
    
    // 显示指定T的边界为Any?
    class Forest<T : Any?>
    
    // 显示指定T的边界为Tree?
    class Forest<T : Tree?>

如果将Forest中的泛型强制指定为non-nullable会发生什么

image-20181107094503992.png

什么?不能将nullableTree?应用到Forest类了!这是因为Forest类的定义中,我们强制将泛型的边界指定为了non-nullableTree

所以,回到文章的开头,函数whoAmI的错误信息nullable type 'T'指的是哪个鬼?泛型T的默认边界为Any?,即T : Any?,所以,我们只需要显示指定Tnon-nullable即可

image-20181107101306195.png

至此,对于nullablenon-nullabletype parametertype argument是否有所了解?

目录
相关文章
|
6月前
|
安全 Java Kotlin
Kotlin泛型:灵活的类型参数化
Kotlin泛型:灵活的类型参数化
|
4月前
|
缓存 安全 Android开发
Android经典实战之用Kotlin泛型实现键值对缓存
本文介绍了Kotlin中泛型的基础知识与实际应用。泛型能提升代码的重用性、类型安全及可读性。文中详细解释了泛型的基本语法、泛型函数、泛型约束以及协变和逆变的概念,并通过一个数据缓存系统的实例展示了泛型的强大功能。
45 2
|
1月前
|
存储 安全 Java
Kotlin教程笔记(30) - 泛型详解
Kotlin教程笔记(30) - 泛型详解
|
2月前
|
存储 安全 Java
Kotlin教程笔记(30) - 泛型详解
Kotlin教程笔记(30) - 泛型详解
31 3
|
2月前
|
存储 安全 Java
Kotlin教程笔记(30) - 泛型详解
Kotlin教程笔记(30) - 泛型详解
|
2月前
|
存储 安全 Java
Kotlin教程笔记(30) - 泛型详解
Kotlin教程笔记(30) - 泛型详解
28 0
|
2月前
|
存储 安全 Java
Kotlin教程笔记(30) - 泛型详解
本教程详细讲解了Kotlin中的泛型概念,包括协变、逆变、类型投影及泛型函数等内容。适合已有Java泛型基础的学习者,深入理解Kotlin泛型机制。快速学习者可参考“简洁”系列教程。
33 0
|
6月前
|
安全 Java 编译器
Android面试题之Java 泛型和Kotlin泛型
**Java泛型是JDK5引入的特性,用于编译时类型检查和安全。泛型擦除会在运行时移除类型参数,用Object或边界类型替换。这导致几个限制:不能直接创建泛型实例,不能使用instanceof,泛型数组与协变冲突,以及在静态上下文中的限制。通配符如<?>用于增强灵活性,<? extends T>只读,<? super T>只写。面试题涉及泛型原理和擦除机制。
42 3
Android面试题之Java 泛型和Kotlin泛型
|
Kotlin
Kotlin中接口、抽象类、泛型、out(协变)、in(逆变)、reified关键字的详解
Kotlin中接口、抽象类、泛型、out(协变)、in(逆变)、reified关键字的详解
109 0
|
安全 Java 编译器
Kotlin 泛型 VS Java 泛型
Kotlin 泛型 VS Java 泛型
91 0