对象与泛型html
Java中有匿名类这个概念,指的是在建立类时无需指定类的名字。在Kotlin中也有功能类似的“匿名类”,叫作对象,举个例子:安全
Java匿名类bash
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 {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
printlnUserName(new Login("Czh") {
@Override
public 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是一个对象,该对象继承自上面的Login
printlnUserName(object : Login("Czh") {
override fun printlnUserName() {
}
})
}
fun printlnUserName(login: Login) {
login.printlnUserName()
}
}
复制代码
对象object还能够实现接口,以下所示:ide
//View.OnClickListener是一个interface
button.setOnClickListener(object : View.OnClickListener {
override fun onClick(v: View?) {
}
})
复制代码
对象和类同样,只能有一个父类,但能够实现多个接口,多个超类型跟在冒号:后面用逗号,
分隔。 若是只想创建一个对象,不继承任何类,不实现任何接口,能够这样写:函数
fun foo(){
val abc = object {
var a = 1
var b = 2
}
Toast.makeText(this, "${abc.a}${abc.b}", Toast.LENGTH_SHORT).show()
}
复制代码
运行代码,查看结果:post
class User {
// 私有函数,因此其返回类型是匿名对象类型
private fun getUserName() = object {
val userName = "Czh"
}
// 公有函数,因此其返回类型是 Any
fun getAge() = object {
val age = 22
}
fun get() {
getUserName().userName
//getAge().age //编译错误
}
}
复制代码
就像 Java 匿名内部类同样,Java能够用final声明变量,使匿名内部类可使用来自包含它的做用域的变量。以下所示:学习
final int age = 22;
printlnUserName(new Login() {
@Override
public void printlnUserName() {
//由于age用final声明,因此不能修改
if (age == 22){
return;
}
}
});
复制代码
而Kotlin在匿名对象中能够任意访问或修改变量age,以下所示:ui
var age = 22
printlnUserName(object : Login() {
override fun printlnUserName() {
age = 23
Toast.makeText(this@MainActivity, "$age", Toast.LENGTH_SHORT).show()
}
})
复制代码
运行代码,查看结果:this
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()
复制代码
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> {
}
复制代码
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>。
不只类能够有类型参数。函数也能够有。类型参数要放在函数名称以前:
fun <T> singletonList(item: T): List<T> {
// ……
}
//调用
val l = singletonList<Int>(1)
singletonList(l)
复制代码
相似于Java的泛型方法:
public <T> T singletonList(T item) {
// ……
}
//调用
singletonList(1);
复制代码
泛型约束可以限制泛型参数容许使用的类型,以下所示:
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的基础上做了一些改进,增长了一些语法糖,更灵活也更安全。
参考文献:
Kotlin语言中文站、《Kotlin程序开发入门精要》
推荐阅读:
从Java到Kotlin(一)为何使用Kotlin
从Java到Kotlin(二)基本语法
从Java到Kotlin(三)类和接口
从Java到Kotlin(四)对象与泛型
从Java到Kotlin(五)函数与Lambda表达式
从Java到Kotlin(六)扩展与委托
从Java到Kotlin(七)反射和注解
从Java到Kotlin(八)Kotlin的其余技术
Kotlin学习资料总汇
更多精彩文章请扫描下方二维码关注微信公众号"AndroidCzh":这里将长期为您分享原创文章、Android开发经验等! QQ交流群: 705929135