Kotlin学习—— 数据类,泛型,嵌套类与内部类,对象表达式和对象声明
Posted 刘某人程序员
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Kotlin学习—— 数据类,泛型,嵌套类与内部类,对象表达式和对象声明相关的知识,希望对你有一定的参考价值。
一.数据类
数据类和JAVA中的javabean类似,只作用于保存一些数据,所以如果创建,会默认生成一些函数,并且会被标记为data:
- equals() / hashCode()
- toString()
- componentN()
- copy()
我们来看下标准的写法
data class User(val name: String, val age: Int)
为了保证这个类的意义,所以一般都会有一些约束,比如
主构造函数需要⾄少有⼀个参数
主构造函数的所有参数需要标记为 val 或 var
数据类不能是抽象、开放、密封或者内部的
1.复制
复制是每个数据类中默认的函数,在很多情况下,我们需要复制⼀个对象改变它的⼀些属性,但其余部分保持不变,有点类似修改某个数据,看下实际代码
fun main(args: Array<String>)
val user = User("张三",18)
val newUser = user.copy(age = 19)
print(newUser.toString())
//数据
data class User(val name: String, val age: Int)
可以看到,这里的User数据类,我们声明之后,调用copy函数,改变年龄为19,然后输出
二.泛型
泛型很常见,相信大家都熟悉
class Box<T>(t: T)
var value = t
1.型变
JAVA中有通配符这一说法,但是处理起来会比较麻烦,但是在kt中,就没有这样的概念,我们来看下代码:
在图中,我们可以看到编译器会提示不同类型,也就是Object != String
JAVA会禁止这样的事情来保证运行时的安全,但是这里就会有一些影响,比如Collection中的addAll
public interface Collection<E> extends Iterable<E>
boolean addAll(Collection<? extends E> c);
为什么明明这里定义的是E,但是类型还是? extends E,然道不是:
public interface Collection<E> extends Iterable<E>
boolean addAll(Collection<E> c);
这也就是JAVA中的一个通配准则:列表优先数组
2.声明处型变
我们现在假设一个泛型
//JAVA
interface Source<T>
T nextT();
这个接口不存在任何以T为参数的方法,那么,在 Source 类型的变量中存储 Source 实例的引⽤是极为安全的⸺没有消费者-⽅法可以调⽤。但是 Java 并不知道这⼀点,并且仍然禁⽌这样操作,为了修正这一点,我们必须声明对象的类型为 Source<? extends Object> ,这是毫⽆意义的,所以在kt中,有一种方法向编译器解释这种情况,叫做声明处型变,也就是out修饰符
abstract class Source<out T>
abstract fun next(): T
fun Test(str: Source<String>)
var objects: Source<Any> = str
一般原则是:当一个类 C 的类型参数 T 被声明为 out 时,它就只能出现在 C 的成员的输出-位置,但回报是 C 可以安全地作为C 的超类。
简而言之,他们说类 C 是在参数 T 上是协变的,或者说 T 是一个协变的类型参数。你可以认为 C 是 T 的⽣产者,⽽不是 T 的消费者。
out修饰符称为型变注解,并且由于它在类型参数声明处提供,所以我们讲声明处型变。这与 Java 的使用处型变相反,其类型用途通配符使得类型协变。
另外除了 out,Kotlin 还补充了一个型变注释:in。它使得一个类型参数逆变:只可以被消费而不可以被生产
abstract class Comparable<in T>
abstract fun compareTo(other: T): Int
fun demo(x: Comparable<Number>)
x.compareTo(1.0) // 1.0 拥有类型 Double,它是 Number 的⼦类型
// 因此,我们可以将 x 赋给类型为 Comparable <Double> 的变量
val y: Comparable<Double> = x // OK!
PS:泛型这块后续用一篇专门来讲
三.嵌套类与内部类
类是可以嵌套在其他类的,这个大家都知道对吧
fun main(args: Array<String>)
val test = TestClass.OutTest().b()
print(test)
class TestClass
private val a: Int = 5
class OutTest
fun b() = 1;
1.
1.内部类
类可以标记为 inner 以便能够访问外部类的成员。内部类会带有一个对外部类的对象的引⽤
class Outer
private val bar: Int = 1
inner class Inner
fun foo() = bar
// == 1
val demo = Outer().Inner().foo()
2.匿名内部类
匿名内部类和大家想的一样,需要使用对象表达式,下面讲了对象表达式再讲匿名内部类
3.枚举类
枚举类就是想实现类型安全来枚举,实际上和我们的正常用法是一样的
enum class K
ONE,TWO,THREE,FOUR,FIVE
val k = K.ONE
a.初始化
每一个枚举都是枚举类的实例,所以我们可以这样初始化
fun main(args: Array<String>)
val k = K.FOUR
print(k.number)
enum class K(val number:Int)
ONE(1),TWO(2),THREE(3),FOUR(4),FIVE(5)
b.匿名类
枚举也可以声明自己的匿名内部类哦
fun main(args: Array<String>)
val h = H.ONE.signal()
print(h)
enum class H()
ONE
override fun signal() = TWO
,
TWO
override fun signal() = ONE
;
abstract fun signal(): H
如果想定义其他成员,需要用;分开,和JAVA一样
四.对象表达式和对象声明
有时候,我们需要创建一个对某个类做了轻微改动的类的对象,而不用为之显式声明新的子类。Java 用匿名内部类 处理这种情况。Kotlin 用对象表达式和对象声明对这个概念
这也就是上面在讲匿名内部类的时候说的,在这里体现
我们拿这个例子来说明:
//JAVA
window.addMouseListener(new MouseAdapter()
@Override
public void mouseClicked(MouseEvent e)
@Override
public void mouseEntered(MouseEvent e)
);
这是给window添加测量监听,所要实现的匿名内部类,如果是kt该如何写?
//Kotlin
val window: Window? = null
if (window != null)
window.addMouseListener(object : MouseAdapter()
override fun mouseClicked(e: MouseEvent?)
override fun mouseEntered(e: MouseEvent?)
)
Github地址:
https://github.com/LiuGuiLinandroid/Kotlin
如果有兴趣的话,可以加入我的Kotlin学习小组
我的公众号,期待你的关注
以上是关于Kotlin学习—— 数据类,泛型,嵌套类与内部类,对象表达式和对象声明的主要内容,如果未能解决你的问题,请参考以下文章