一、泛型
-
泛型是什么?
泛型是程序设计语言的一种特性。允许程序员在强类型程序设计语言中编写代码时定义一些可变部分,那些可变部分在使用前必须作出指明。
更通俗的说,泛型就是一种将类型参数化以达到代码复用提高软件开发工作效率的一种数据类型,泛型类是引用类型,是堆对象。
-
泛型的好处
-- 架构开发的利器
--使我们的代码或开发出来的框架更加地好用
--增加程序的健壮性,避免运行时可能引发的ClassCastException
虽然Java中也存在泛型,但是相比较于kotlin还是有很大的差别,下面我们就来学习一下泛型。
-
内容介绍
![](https://img.haomeiwen.com/i26012968/9a2d674c8c900bf9.png)
-
泛型接口
定义一个泛型接口,并再定义一个类去实现这个泛型接口
interface Drinks<T> {
fun taste(): T
fun price(t: T)
}
class Sweet {
val price = 5
}
class Coke : Drinks<Sweet> {
override fun taste(): Sweet {
println("可乐是甜的")
return Sweet()
}
override fun price(t: Sweet) {
println("可乐的价格是${t.price}")
}
}
在使用时泛型T接受了类Sweet对象。
-
泛型类
abstract class Colors<T>(var t: T) {
abstract fun printColor()
}
class Blue{
val color="蓝色"
}
class BlueColor(t: Blue): Colors<Blue>(t) {
override fun printColor() {
println("color: ${t.color}")
}
}
-
泛型方法
fun <T> fromJson(json:String,tclass:Class<T>):T?{
val t=tclass.newInstance()
return t
}
如上,该方法接收一个json字符串和一个tclass的泛型类,返回一个泛型类,这里我直接才用参数泛型类的newInstance()获取一个实例作为了返回参数。
-
泛型约束
fun <T : Comparable<T>> sort(list: List<T>): Unit {}
fun test2() {
sort(listOf(1, 2, 3))//正确,Int是Comparable<Int>的子类型
//sort(listOf(Blue()))//错误,Blue类不是Comparable<Blue>的子类型
}
-
泛型中的out与in
在kotlin中out代表协变,in代表逆变,为了加深理解我们可以将协变看做Java中的上界通配符,将逆变看做Java中的下界通配符:
//kotlin使用协变
fun sumOfList(list: List<out Number>){
}
//java使用上界通配符
void sumOfList(List<? extends Number> list){
}
//kotlin使用逆变
fun addNumbers(list: List<in Int>){
}
//java使用下界通配符
void addNumbers(List<? super Interger> list){
}
二、注解
-
注解的定义和使用
//和一般的声明差不多,只是在类名前面加上annotation
annotation class Apidoc(val value:String)
@Apidoc("修饰类")
class Box{
@Apidoc("修饰变量")
val a=20
@Apidoc("修饰方法")
fun test(){
}
}
-
注解中的元注解
和Java一样在Kotlin中一个Kotlin注解类自己本身也可以被注解,可以给注解类
加注解,我们把这种注解称为元注解。
Kotlin中的元注解类定义于kotlin.annotation包中,主要有:
- @Target:定义注解能够应用于那些目标对象
- @Retention: 注解的保留期
- @Repeatable:标记的注解可以多次应用于相同的声明或类型
- @MustBeDocumented:修饰的注解将被文档工具提取到API文档中
4种元注解,相比Java中5种元注解少了@Inherited,在这里四种元注解中最常用的是前两种,接下来我们就来重点分析下前两种元注解:
@Target:
@Target顾名思义就是目标对象可以将限制注解能够使用的对象,也就是我们定义的注解能够应用于那些目标对象,并且可以同事指定多个作用的目标对象。
![](https://img.haomeiwen.com/i26012968/1d4731244576d91f.png)
如上图,我们在定义的注解上面加上@Target(AnnotationTarget.CLASS)限制该注解只能用于修饰类,下面修饰变量和修饰方法的地方就会报错。
那除了限制修饰类还有那些限制呢?我们不妨来看一下它的源码:
public enum class AnnotationTarget {
/** Class, interface or object, annotation class is also included */
CLASS,
/** Annotation class only */
ANNOTATION_CLASS,
/** Generic type parameter */
TYPE_PARAMETER,
/** Property */
PROPERTY,
/** Field, including property's backing field */
FIELD,
/** Local variable */
LOCAL_VARIABLE,
/** Value parameter of a function or a constructor */
VALUE_PARAMETER,
/** Constructor only (primary or secondary) */
CONSTRUCTOR,
/** Function (constructors are not included) */
FUNCTION,
/** Property getter only */
PROPERTY_GETTER,
/** Property setter only */
PROPERTY_SETTER,
/** Type usage */
TYPE,
/** Any expression */
EXPRESSION,
/** File */
FILE,
/** Type alias */
@SinceKotlin("1.1")
TYPEALIAS
}
其他的修饰限制属性就是上面这些,至于每个属性分别有啥作用,自己去翻译吧,这里就不一一解释了。
@Retention:
@Retention可以理解为保留期,先来看它的一些源码参数值:
public enum class AnnotationRetention {
/** Annotation isn't stored in binary output */
SOURCE,
/** Annotation is stored in binary output, but invisible for reflection */
BINARY,
/** Annotation is stored in binary output and visible for reflection (default retention) */
RUNTIME
}
Retention接收一个AnnotationRetention 的参数,该参数主要有以下三种时期,如果不接收它默认保留在运行时期;
SOURCE------源代码时期
BINARY------编译时期
RUNTIME-----运行时期
-
注解的使用场景
- 提供信息给编译器:编译器可以利用注解来处理一些,比如一些警告信息,错误等
- 编译阶段时处理:利用注解信息来生成一-些代码,在Kotlin生成代码非常常见,一些内置的注解为了与JavaAPI的互操作性,往往借助注解在编译阶段生成一些额外的代码
- 运行时处理:某些注解可以在程序运行时,通过反射机制获取注解信息来处理一些程序逻辑
接下来我们通过一个小案例来熟悉一下注解的使用及使用场景。 -
注解案例:自定义注解实现API调用时的请求方法检查
fun main() {
fire(ApiGetClass())
}
//定义一个枚举类存放请求方式
public enum class Method {
GET, POST
}
//定义注解类,参数为枚举类
@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.RUNTIME)
annotation class HttpMethod(val method: Method)
//采用注解使用GET请求
@HttpMethod(Method.GET)
class ApiGetClass {
var name: String
get() = "/api/ApiGetClass"
set(value) {}
}
fun fire(api: ApiGetClass) {
//利用放射拿到运行时的注解
val annotation = api.javaClass.annotations
//因为返回的annotation是数组,所以需要找到它并进行类型转换
val method1 = annotation.find { it is HttpMethod } as HttpMethod
println("通过反射得知该方法通过${method1.method}方法请求")
}
网友评论