相比较java来说 没有太大改变 我们一起来看下 这章节我不在粘java的例子了 但是 会做简单总结 这样大家能看的更明确一点
接口
java
public interface _Clickable {
void click();
}
public class _ClickAbleImpl implements _Clickable{
@Override
public void click() {
}
}
kotlin
kotlin 默认public 同时 能够包含非抽象方法 但是 该方法必须被显示实现 否则会报错(kotlin 强制要求提供自己的实现)
class ClickableImpl:Clickable{
override fun click() {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
override fun getName():String {
super.getName()
}
}
kotlin使用 : 来代替 implements 和 extends 其他基本一致
修饰符
java
class 和 method 默认修饰符是 open 就是我们能够为该class 创建子类 并且重写需要的方法 除非我们使用finial来修饰
kotlin
class和method 默认是close 就是默认使用finial修饰 如果想继承和重写 必须使用open 修饰 class和method 我们同样 可以显示的使用finial来禁止method被重写
类中修饰符意义
finial : 不能被重写 类中成员默认使用
open: 可以被重写 需要显示声明
abstract : 必须被重写
可见性修饰符
public private protected 这三个和java是一样的
internal 只在模块中可见(kotlin特有的)--模块 即 一组一起编译的文件 我理解就是model
内部类和嵌套类 (默认是嵌套类)
内部类 默认持有外部类对象的引用 嵌套类 不持有外部类对象的引用
这两个是什么意思呢 ?
java:
内部类: class B{...} 嵌套类:(静态内部类): classB{...}
class A{...} static class A{...}
kotlin :
内部类 :class B{...} 嵌套类: class B{...}
inner class A{...} class A{....}
如果想从inner class 访问 ouer class 那么需要使用this@outer 来获取外部类对象
密封类
kotlin 特有概念 能够限制子类数量的 类
对于接口类 InterA 我们想 只要两个子类 classA :InterA class _A :InterA 这时候我们就可以使用密封类 scale
scale class InterA{
classA :InterA {...}
class _A :InterA {...}
}
注:子类必须卸载接口类里面(1.1中已经去掉了这个限制) 前面我们说过对于class 和method默认是close 不支持 继 承和重写 但是 scale 默认是open
类的声明
前面我们已经说过继承或者实现一个类 我们使用 :来替代implement 和 extends 那么下面我们看下类的初始化以及声明
主构造方法:
在kotlin中我们可以使用 class A constructor (val name:String) 来定义一个类 没有任何方法体
这样声明就相当于java中 class A { public A(String name){}} 也就是后面加上() 就代表了我们的构造方法
这样的构造方法称为主构造方法 constructor 可以省略 class A (val name:String)
我们看下 构造方法中的参数是怎么工作的
class A(val name :String){
val _name:String
init{ _name=name} //初始化语句
}
construct :声明构造方法 (无论主构造或者是从构造)
init :引入初始化块 类被创建的时候执行
val:表示会被初始化value初始化
java:默认实现无参构造
kotlin : open class A 我们这样定义一个类 表示该类只有一个无参构造方法 但是如果我们继承该类 必须显示调用A()
class B:A()
注意:kotlin 和java一样 接口是没有构造方法的 所以 实现接口不需要加()
多种构造方式
open class View{
constructor(ctx:Context){...}
constructor(ctx:Context,attr:Int){...}
}
上面的demo中没有主构造方法 只有两个从构造方法
我们来继承下 该类
class MyView :View{
constructor (ctx:Context) :this(ctx,0)
constructor(ctx:Context,attr:Int):super(ctx:Context,attr:Int){}
}
这个是不是比较熟悉 我们java 自定义View中经常这么写 一个参的构造方法 委托当前类中两个参的实现 两个参的委托View中的默认实现
注:如果类没有主构造方法 那么每个从构造方法必须初始化 基类 或者委托给初始化了基类的构造方法
数据类:
java 中 我们通常需要手动实现 equals 和 toString
kotlin中 帮助我们实现了这些通用方法
data class User(val name :String,val age:Int)
注:数据类的参数类型 最好是val 虽然 var 也可以 但是很有可能在线程中 被修改值
为了更方便val 的数据操作 kotlin 生成了一个方法 copy 这样我们就可以手动修改值了
val Bob=User("Bob",0)
Bob.copy(age=18)
copy有单独的生命周期 并不会影响原始实例的位置 很方便修改
手动实现copy
class User(val name :String,val age:Int){
...
fun copy(name:String=this.name,age:Int=this.age)=User(name,age)
}
委托类(by)
我们使用继承实现某个类的时候 必须实现里面所有的抽象方法 但是很多方式我们根本不需要 或者是完全可以使用默认实现 我们只想修改我们需要的就好了 那么我们看下 demo
class DelegationCollection(innerList:ArrayList<SimpleDemoUtils.User>) :Collection<SimpleDemoUtils.User> {
override val size: Int
get() = TODO("not implemented") //To change initializer of created properties use File | Settings | File Templates.
override fun contains(element: SimpleDemoUtils.User): Boolean {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
override fun containsAll(elements: Collection<SimpleDemoUtils.User>): Boolean {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
override fun isEmpty(): Boolean {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
override fun iterator(): Iterator<SimpleDemoUtils.User> {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}}
害怕 我们看下 使用委托 之后 世界都安静了 为什么不用实现了呢 因为我们将实现 全部委托给了 innerList 而innerList是ArrayList 本身就已经继承自 Collection 实现了所有抽象方法了
class DelegationCollection(innerList: ArrayList<SimpleDemoUtils.User>) : Collection<SimpleDemoUtils.User> by innerList {}
那么我们只需要修改我们需要的就好了 我们写个完成的demo
/**
* @author zhangyanjiao
* @desc 我们想统计下 add 进来的元素个数
* hash 过滤重复元素 所以添加个数 和 真正添加进去的个数不完全相同 ok 我们测下
*/
class DelegationCollection<T>(val innerList:MutableCollection<T> = HashSet()) : MutableCollection<T> by innerList {
var addCount: Int = 0
override fun add(element: T): Boolean {
addCount++
return innerList.add(element)
}
override fun addAll(elements: Collection<T>): Boolean {
addCount += elements.size
return innerList.addAll(elements)
}
}
class ClickableImpl:Clickable{
override fun click() {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
override fun getName():String {
super.getName()
}
}
class ClickableImpl:Clickable{
override fun click() {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
override fun getName():String {
super.getName()
}
}
private fun delegation() {
val map = DelegationCollection<Int>()
map.addAll(listOf(1, 1, 2, 3))
Log.d("SecondActivity", "add count=${map.addCount},remain count =${map.size}")
}
结果
interface Clickable {
fun click()
fun getName():String="Clickable "
}
D/SecondActivity: add count=4,remain count =3
object 关键字
使用场景
- 对象声明 是定义单例的一种方式
- 伴生对象可以支持工厂和其他与这个类相关 但调用时并不依赖实例的方法 成员可以通过类名来访问
- 对象表达式 用来替代java的匿名内部类
单例 实现
object MyUtils{
fun add(a:Int,b:Int){
return a+b
}
}
调用方式:
MyUtils.add(1,2)
伴生对象(工厂方法 和静态成员 的实现)
kotlin 不能拥有静态成员,但是之前我们说顶层函数和成员 相当于静态来使用 但是顶层函数不能访问类的私有成员 。(也就是私有成员不能再类外部的顶层函数中使用)
那么此时我们就可以用工厂方法来解决
companion :标记对象 可以直接通过容器名直接访问这个对象的方法和属性 不需要显示制定对象名称(很像static 方法调用)
class A{
companion object{
fun foo(){
...
}
}
}
调用
A.foo()
使用工厂方法代替从构造方法
class User(val name:String){
companion object{
fun newSubUserScribing(email:String){
return User(email)
}
}
}
对象表达式:匿名内部类
java
class A{
btView.setOnclickListener(new OnClickListener(){
...})
}
kotlin
class A{
btView.setOnclickListener(object:OnclickListener(){...})
}
使用object声明并创建了一个实例 但是该实例并没有名称 只是实现OnCLickListener 在java中 匿名内部类 只能实现一个接口 但是kotlin中能够实现多个
关于对象表达式 我们会在下一章具体说 这里先跳过~