学习Kotlin(四)对象与泛型
推荐阅读:
学习Kotlin(一)为什么使用Kotlin
学习Kotlin(二)基本语法
学习Kotlin(三)类和接口
学习Kotlin(四)对象与泛型
学习Kotlin(五)函数与Lambda表达式
学习Kotlin(六)扩展与委托
学习Kotlin(七)反射和注解
学习Kotlin(八)其他技术
Kotlin学习资料总汇
目录
- 1.对象
1.1 匿名类与对象
1.2 静态类成员与伴生对象 - 2.泛型
2.1 型变
2.2 类型投影
2.3 泛型函数
2.4 泛型约束
1.对象
1.1 匿名类与对象表达式
Java中有匿名类这个概念,指的是在创建类时无需指定类的名字。在Kotlin中也有功能相似的“匿名类”,叫做对象,举个例子:
Java匿名类
public class Login {private String userName;public Login(String userName) {this.userName = userName;}public void printlnUserName() {System.out.println(userName);}
}public class JavaActivity extends AppCompatActivity {@Overrideprotected void onCreate(@Nullable Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);printlnUserName(new Login("Czh") {@Overridepublic void printlnUserName() {super.printlnUserName();}});}public void printlnUserName(Login login) {login.printlnUserName();}
}
Kotlin实现上面的代码,要用关键字object创建一个继承自某个(或某些)类型的匿名类的对象,如下所示:
class KotlinActivity : AppCompatActivity() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)//object是一个对象,该对象继承自上面的LoginprintlnUserName(object : Login("Czh") {override fun printlnUserName() {} })}fun printlnUserName(login: Login) {login.printlnUserName()}
}
对象object还可以实现接口,如下所示:
//View.OnClickListener是一个interface
button.setOnClickListener(object : View.OnClickListener {override fun onClick(v: View?) {}
})
对象和类一样,只能有一个父类,但可以实现多个接口,多个超类型跟在冒号:后面用逗号,
分隔。如果只想建立一个对象,不继承任何类,不实现任何接口,可以这样写:
fun foo(){val abc = object {var a = 1var b = 2}Toast.makeText(this, "${abc.a}${abc.b}", Toast.LENGTH_SHORT).show()
}
运行代码,查看结果:
请注意,匿名对象可以用作只在本地和私有作用域中声明的类型。如果你使用匿名对象作为公有函数的返回类型或者用作公有属性的类型,那么该函数或属性的实际类型会是匿名对象声明的超类型,如果你没有声明任何超类型,就会是 Any。在匿名对象中添加的成员将无法访问。如下所示:
class User {// 私有函数,所以其返回类型是匿名对象类型private fun getUserName() = object {val userName = "Czh"}// 公有函数,所以其返回类型是 Anyfun getAge() = object {val age = 22}fun get() {getUserName().userName//getAge().age //编译错误}
}
- 内部类访问作用域内的变量
就像 Java 匿名内部类一样,Java可以用final声明变量,使匿名内部类可以使用来自包含它的作用域的变量。如下所示:
final int age = 22;
printlnUserName(new Login() {@Overridepublic void printlnUserName() {//因为age用final声明,所以不能修改if (age == 22){return;}}
});
而Kotlin在匿名对象中可以任意访问或修改变量age,如下所示:
var age = 22
printlnUserName(object : Login() {override fun printlnUserName() {age = 23Toast.makeText(this@MainActivity, "$age", Toast.LENGTH_SHORT).show()}
})
运行代码,查看结果:
1.2 伴生对象
Java中有静态类成员,而Kotlin中没有,要实现像静态类成员的功能,就要用到伴生对象。
Java静态成员:
class User {static User instance = new User();public void printlnUser() {}
}
//调用
User.instance.printlnUser()
Kotlin类内部的对象声明可以用 companion 关键字标记:
class User {companion object {var instance = User()}fun printlnUser() {}
}
//调用
User.instance.printlnUser()
泛型
2.1型变
Java泛型
public class Box<T> {public T value;public Food(T t) {value = t;}
}new Box<String>("123");
new Box<Integer>(1);
对应的Kotlin泛型
class Box<T>(t: T) {var value = t
}
var box: Box<String> = Box("123")
var box2: Box<Int> = Box(123)
可以看出Java跟Kotlin定义泛型的方法都是差不多的,不同的是Java中的泛型有通配符,而Kotlin没有。举个例子:
List<String> strings = new ArrayList<String>();
List<Object> objects = strings;//编译错误
Java编译器不认为List是List的子类,所以编译不通过。那我们换种写法:
List<String> strings = new ArrayList<String>();
List<Object> objects = new ArrayList<Object>();
objects.addAll(strings);//编译通过
为什么调用addAll()方法就能编译通过呢,看一下他的源码:
boolean addAll(Collection<? extends E> c);
Java泛型提供了问号?
通配符,上面的<? extends E>代表此方法接受 E 或者 E 的 一些子类型对象的集合。所以可以通过addAll()方法把List赋值给List。
Kotlin的泛型没有提供通配符,取而代之的是out
和in
修饰符。先举个例子:
//用out修饰T
class Box<out T> {
}
(红色波浪线标记处为编译错误)
//用in修饰T
class Box<in T> {
}
(红色波浪线标记处为编译错误)
对比上面两段代码可以看出,用out来修饰T,只能消费T类型,不能返回T类型;用in来修饰T,只能返回T类型,不能消费T类型。简单来说就是 in 是消费者, out 是生产者。
####2.2 类型投影上面说到了out
和in
修饰符,如果我们不用他们来修饰泛型,会出现这种情况:
class Box<T> {
}
编译不通过,因为Array对于类型T是不可变的,所以Box和Box谁也不是谁的子类型,所以编译不通过。对于这种情况,我们还是可以用out
和in
修饰符来解决,但不是用来修饰Box,如下所示:
fun test(strs: Box<Any>) {var objects: Box<in String> = strs//编译通过
}fun test2(strs: Box<String>) {var objects: Box<out Any> = strs//编译通过
}
上面的解决方式叫做类型投影,Box相当于 Java 的 Box<? extends Object>、Box相当于 Java 的 Box<? super Object>。
2.3 泛型函数
不仅类可以有类型参数。函数也可以有。类型参数要放在函数名称之前:
fun <T> singletonList(item: T): List<T> {// ……
}//调用
val l = singletonList<Int>(1)
singletonList(l)
类似于Java的泛型方法:
public <T> T singletonList(T item) {// ……
}//调用
singletonList(1);
2.4 泛型约束
泛型约束能够限制泛型参数允许使用的类型,如下所示:
Kotlin代码
fun <T : Comparable<T>> sort(list: List<T>) {
}sort(1) //编译错误
sort(listOf(1)) //编译通过
上述代码把泛型参数允许使用的类型限制为 List
Java中也有类似的泛型约束,对应的代码如下:
public static <T extends Comparable> List<T> sort(List<T> list){
}
如果没有指定泛型约束,Kotlin的泛型参数默认类型上界是Any,Java的泛型参数默认类型上界是Object
总结
本篇文章对比了Java匿名类、静态类与Kotlin对象的写法和两种语言中对泛型的使用。相对来说,Kotlin还是在Java的基础上作了一些改进,增加了一些语法糖,更灵活也更安全。
原文链接:https://juejin.im/post/5a805c7c6fb9a0634f40956e
学习Kotlin(四)对象与泛型相关推荐
- java学习笔记(四)----对象、数组作为参数传递,静态变量、静态方法的使用,内部类,使用文档注释
***对象作为参数传递*** class passparam { int x; public static void main(String[] args) { passparam obj = ...
- v8学习笔记(四) 对象机制
v8对象机制 1.概述 v8中每一个API对象都对应一个内部实现对象(堆对象) 2.对象创建过程 (1)v8::internal::Factory类:创建各种内部对象(v8::internal::) ...
- 学习Kotlin(八)其他技术
推荐阅读: 学习Kotlin(一)为什么使用Kotlin 学习Kotlin(二)基本语法 学习Kotlin(三)类和接口 学习Kotlin(四)对象与泛型 学习Kotlin(五)函数与Lambda表达 ...
- 学习Kotlin(七)反射和注解
推荐阅读: 学习Kotlin(一)为什么使用Kotlin 学习Kotlin(二)基本语法 学习Kotlin(三)类和接口 学习Kotlin(四)对象与泛型 学习Kotlin(五)函数与Lambda表达 ...
- 学习Kotlin(六)扩展与委托
推荐阅读: 学习Kotlin(一)为什么使用Kotlin 学习Kotlin(二)基本语法 学习Kotlin(三)类和接口 学习Kotlin(四)对象与泛型 学习Kotlin(五)函数与Lambda表达 ...
- 学习Kotlin(五)函数与Lambda表达式
推荐阅读: 学习Kotlin(一)为什么使用Kotlin 学习Kotlin(二)基本语法 学习Kotlin(三)类和接口 学习Kotlin(四)对象与泛型 学习Kotlin(五)函数与Lambda表达 ...
- 学习Kotlin(三)类和接口
推荐阅读: 学习Kotlin(一)为什么使用Kotlin 学习Kotlin(二)基本语法 学习Kotlin(三)类和接口 学习Kotlin(四)对象与泛型 学习Kotlin(五)函数与Lambda表达 ...
- 学习Kotlin(二)基本语法
推荐阅读: 学习Kotlin(一)为什么使用Kotlin 学习Kotlin(二)基本语法 学习Kotlin(三)类和接口 学习Kotlin(四)对象与泛型 学习Kotlin(五)函数与Lambda表达 ...
- 学习Kotlin(一)为什么使用Kotlin
推荐阅读: 学习Kotlin(一)为什么使用Kotlin 学习Kotlin(二)基本语法 学习Kotlin(三)类和接口 学习Kotlin(四)对象与泛型 学习Kotlin(五)函数与Lambda表达 ...
最新文章
- .NetCore Winform控制台 做HTTP Host,简易接口
- KVM虚拟机添加硬盘
- 给枚举值增加扩展数据
- 让员工、用户粉丝化,从选好社区软件开始
- nodejs 图片处理模块 rotate_如何针对数据不平衡做处理?
- 腾讯朋友、钉钉等被微信违规公示点名;谷歌更新安卓修复数百万台芯片漏洞;微软终止支持.NET Core 3.0 | 极客头条...
- Docker Swarm的前世今生
- NFS服务及FTP服务
- CentOS7 安装ffmpeg
- 浅谈Spring中Bean的生命周期
- 关闭IDEA双击shift全局搜索
- c语言编程电影院票务系统,C++课程设计----电影院售票系统
- 使用python实现多个excel文件合并到一个excel的不同sheet中
- 如何使用SQL判断身份证号码第18位是否符合规则
- 将tensorflow与微信小程序结合,微信开发者工具使用tensorflowJS插件出错:Error: Plugin tfjsPlugin has not registered.
- Idea 中最常用的10款插件(提高开发效率),一定要学会使用!
- PHP输出分割线,dede标签调用大全dedecms隔五行一个分割线_PHP教程
- 极限脱出 量子计算机,《极限脱出3:零时困境》难点解密攻略 剧情通关密码一览...
- 如何布置项目到远程服务器上,如何用远程服务器布置项目
- uinavgationcontroller
热门文章
- 分类VS标签,一文带你看懂数据中台为什么要建标签体系?
- 知识归纳,程序猿必备的21张(神经网络、线性代数、可视化等)数据挖掘速查表
- MATLAB 查看程序执行内存最大使用值
- KeyError: [] not found in axis_高调又有质感,女星最爱的至IN单品原来是它!
- Python入门100题 | 第062题
- 数据分析系列:绘制折线图(matplotlib)
- urllib.parse包学习
- Pytorch运行时报错No module named ‘matplotlib‘--解决办法
- Jupyter notebook与Spyder,以及Jupyter notebook与Spyder集成插件
- 解决服务器连接错误Host ‘XXX’ is not allowed to connect to this MySQL server