面向对象的本质:可以提升抽象的级别,以构建更大,更复杂的系统。简单点说就是,更好的应对需求不断变化的情况。武器就是:抽象!
这部分只讲和Java不同的一些点。
1. 构造函数
一个类可以有一个主构造函数,同时可以拥有多个次构造函数。这是乱的不得了。
- 主构造函数
- 竟然跑到类头去了,直接放在类名的后面。
- 参数必须声明类型。
- 默认是public。
- 如果没有(public/private/protected)修饰,也没有任何注解。 Contructor也可以不写。
- 参数可是val,也可以是var。
- 可以有初始化值。
- 如果继承了一个类,那个类的构造初始化,也可以在类头处理。
class Student Constructor(var name:String, var age:Int){ //默认是public
}
class Student public Constructor(var name:String, var age:Int){
}
class Student private Constructor(var name:String, var age:Int){
}
class Student @AutoWire Constructor(var name:String, var age:Int){
}
class Student(var name:String, var age:Int){ //如果没有(public/private/protected)修饰,也没有任何注解。 Contructor也可以不写。
}
class Student Constructor(var name:String, var age:Int = 20){ //可以有初始化值。
}
class Student public Constructor(var name:String, var age:Int):Person(name){ //如果继承了一个类,那个类的构造初始化,也可以在类头处理。
}
- init
- 由于主构造函数没有函数体。所以初始化放在了init模块中。相当于函数体了。
class Student (var age: Int, var name: String ){ private var mAge: Int private var mName: String init { mAge = age mName = name } }
- 除了用init初始化,还可以直接在属性上初始化。
class Student (var age: Int, var name: String ){ private var mAge: Int = age private var mName: String = name }
- 次构造函数
在类体中,也可以声明前缀有Constructor的构造函数,次构造函数不能有声明val或var。
class Student {
Constructor(name:String, age:Int){
}
}
如果类既有主构造函数, 又有次构造函数。并且主构造函数初始化了父类的构造函数, 就是用this表示。this可以指代同类的其他构造函数, 这个和Java一样。
class Student(override var name:String, var age:Int):Person(name) {
constructor(name:String, age:Int, weight:Int):this(name, age){ //这个this是主构造函数
}
constructor(name:String) :this(name,20,60) { //这个this是上面那个构造函数
}
}
open class Person(open var name: String) {
}
- 私有构造函数
只要如下这么写就可以了,加个private.
class Student private (var name:String, var age:Int){ //主构造函数私有
private constructor(name:String) :this(name,20) {次构造函数私有
}
}
- 默认构造函数
和Java一样,默认也有一个无参构造函数。
- 实例化类
实例化类是不需要new这个关键词的。很不习惯。
2. 类的属性
- Kotlin的类属性都需要手动初始化, 不像java都给你初始化好了,比如基本类型都是初始化0, 对象都是初始化为null。
- Kotlin的setter/getter,和C#很像,就是有点不伦不类。由于C#和Java一样,属性都是初始化好的,而Kotlin由于需要初始化属性,所以不能像C#一样用大括号括起来。另外,无法制定只重写abstract的getter或者setter。
1. 当public时,默认就是getter/setter方法。
class Student { var name: String = "" var age: Int = 1 } var student:Student= Student("",1) student.age =1 //默认自带getter/setter student.name =""
2. 下面是自动生成且隐藏的方法。
set(vaule){ field = value } get() = field
3. 当你需要修改getter/setter时,可以这样写:
class Student {
var age: Int = 1
get() = field
set(value) {
if (value < 18)
field = 18
else if (value >= 18 && value <= 30)
field = value
else
field = value - 3
}
}
4. 当属性有val修饰时,常量为只读属性, 所以只有getter方法。
-
抽象类与抽象方法
- 这一块基本和Java一样。 唯一不一样的地方是,在抽象类中的非抽象方法,默认是final的,不能被重写,如果想被子类重写,必须用“open”修饰。 这样设计,不知道有什么好处。
- 在子类被重写的方法要用override修饰。
- 抽象属性
由于在Kotlin中,属性是自带getter/setter的,所以就存在抽象属性的概念了。抽象属性在抽象类中不能被初始化,而在子类中必须初始化,否则子类也是抽象类。
abstract class Student {
abstract var name: String
abstract var age: Int
}
如果子类中有主构造函数,可以在主构造函数里初始化,如下:
class Person(override var name: String, override var age: Int) :Student() {
}
如果没有主构造函数,就要对抽象属性手动初始化。
class Person : Student() {
override var name: String = ""
override var age: Int =1
}
- 实现接口
这一块也差不多和java一样。
- 对于父类的包访问权限成员变量,如果子类和父类都在同一个包,则子类可以继承,否则不许。
- 当子类和父类的方法一样时,用super来访问父类的方法。
- 当有多个一样的父类方法时,用super<具体父类>.来访问方法。
继承
所有的类都默认继承Any,有点像Java的Object, 但是又有不同,因为只有equals(), hashcode(), toString()三个方法。不像JAVA Object还有clone/wait/notify/finanlize等。
枚举类
Abstruct class Enum():Comparable{
public final val name:String
public final val ordinal:Int
}
name和ordinal是唯二的两个属性。分别表示枚举对象的值和下标位置。和Java类似。 比较好的是和C#一样,枚举值为自增加一。
使用enumValues()方法可以遍历打印枚举。
enum class RGB{
RED(200), GREEN(100),BLUE(50)}
}
val rgbs = enumValues<RGB>.joinToString{"${it.rgb}:${it.name}:${it.ordinal}"}
输出rgbs:200: RED:0, 100: GREEN:1,50: BLUE:2
枚举常量也可以声明自己的匿名类。这种用法以前倒是没见过。
enum class ActivityLifeState{
onCreate{
override fun signal()=onStart()
}
abstract fun signal():ActivityLifeState
}
var oncreate= ActivityLifeState.onCreate
oncreate.signal()
object关键词
很好的场景就是一些Utils的工具类了。
Kotlin中没有静态属性和方法,但是可以用object关键词。在类名前加object关键词,就相当于在类型前加了static, 变成了静态类,用法也一样,用类名调用方法和成员属性。而且成员属性默认都是final static的。而且不能实例化object关键词修饰的类。
把object修饰的类,反编译到Java代码后就容易理解了。
public final class User{
private final static String name = "alan";
private static final User INSTANCE;
private User(){
INSTANCE = (User)this
name ="alan"
}
static {
new User();
}
}
在类中嵌套使用object关键词, 这个用法和java静态类一样。
匿名object
有时候仅仅是一个简单的对象,可以用匿名object。但是只能在本地和私有作用域里声明使用。
class AnonymousObjectType{
private fun privateFoo()=object{
val x:String="x"
}
fun publicFoo()=object{
val x:String="x" //无法访问到
}
fun test(){
val x1 = privateFoo().x //正确,WORK
//val x2 = publicFoo().x//Error
}
}
匿名内部类
内部类。不再像java那样默认带有外部对象的引用了。
setOnClickListener(object:OnFilteredClickListener(){
override fun onFilteredClick(v: View?) {
TODO("Not yet implemented")
}
})
未完待续