赞
踩
类及初始化举例:
主构造函数、次构造函数、init代码块
class AnimalMainSecConstructor constructor(val context: Context, val name: String){
init {
println("init")
context.toast("$name")
}
//调用次级构造函数声明类的实例时,必须调用主构造函数
constructor(context: Context, name: String, sex: Int):this(context, name){
println("second constructor")
val sexName:String = if(sex==0) "male" else "female"
context.toast("this $name is $sexName")
}
}
只有次级构造函数
class AnimalMainOnlySecConstructor {
//含有默认参数
constructor(context: Context, name:String = "AnimalMain"){
println("sub instructor 1")
context.toast("anmimal name $name")
}
//含有默认参数
constructor(context: Context, name:String = "AnimalMain", sex:Int = 0){
println("sub instructor 2")
val sexName:String = if(sex==0) "male" else "female"
context.toast("animal name $name, sex is $sexName")
}
}
说明:
constructor
关键字可以省略。constructor
前面)添加@JvmOverloads
注解, 否则只能调用不含默认参数的完整构造函数进行实例声明。class AnimalMainSimple constructor(var context: Context, val name:String = "AnimalMain", val sex:Int = 0){
//非空的成员属性必须在声明时赋值或者在构造函数中赋值
//否则编译器会报错"Property must be initialized be abstract"
var sexName:String
init {
context.toast("AnimalMain Init, name $name")
sexName = if(sex==0) "公" else "母"
}
}
调用:
var animal = WildAnimalMember(animalName, animalSex)
println( "这只${animal.name}是${animal.sexName}的")
说明:
val
和var
关键字,可以在编译时自动在类中声明对应的变量。class AnimalMainSimple constructor(var context: Context, val name:String = "AnimalMain", val sex:Int = 0){
var sexName:String
init {
context.toast("AnimalMain Init, name $name")
sexName = if(sex==0) "公" else "母"
}
fun getDesc(tag:String):String {
return "欢迎来到$tag: 这只${name}是${sexName}的。"
}
}
调用:
var animal = WildAnimalMember(animalName, animalSex)
println( "描述信息是${animal.getDesc("动物园")}")
/静态变量/静态方法
伴生对象是的引入是为了Kotlin用于声明静态成员, 可以在伴生对象中声明静态变量和静态方法
class WildAnimalCompanion(var name:String, val sex:Int = 0) {
var sexName:String
init {
sexName = if (sex==0) "male" else "female"
}
fun getDesc(tag:String):String {
return "欢迎来到$tag: 这是${name}是${sexName}的。"
}
//在类加载时就运行伴生对象的代码块,其作用相当与Java中的static{}代码块
//关键字companion表示伴随,object表示对象, WildAnimal表示伴生对象的名称
companion object WildAnimal{
//静态常量的值不可变的,所以要使用关键字val修饰
val MALE = 0
val FEMALE = 1
val UNKNOWN = -1
fun judgeSex(sexName:String): Int{
var sex:Int = when(sexName){
"male" -> MALE//0
"female" -> FEMALE//1
else -> UNKNOWN//-1
}
return sex
}
}
}
调用:
WildAnimalCompanion.WildAnimal.judgeSex("male") //正常调用
WildAnimalCompanion.judgeSex("male") //伴生对象名称可以省略,有点静态调用的意思
Kotlin类成员分为实例成员和静态成员两种。实例成员包括成员属性和成员方法,其中与入参同名的成员属性可以在构造函数中直接声明,外部必须通过类的实例才能访问类的成员属性和成员方法。类的静态成员包括静态属性与静态方法,它们在类的伴生对象中定义,外部可以通过类名直接访问该类的静态成员。
Kotlin类默认是final的,不能被继承, 方法默认也是final,默认不能Override, 如果希望类被继承或者方法可以被覆写,则必须使用open修饰符。
open class Bird (var name:String, val sex:Int = 0) {
//
}
Kotlin开放修饰符取值说明
开放修饰符 | 说明 |
---|---|
public | 对所有人开放。Kotlin的类、函数、变量不加开放性修饰符的话,默认是public类型 |
internal | 只对本模块内部开放,这是Kotlin新增关键字,对于APP开发来说,本模块便是App本身 |
protected | 只对自己和子类开放 |
private | 只对自己开放,即私有 |
说明:
按照上一节说明,我们来声明一个类及其子类
下面声明Bird类
//Kotlin的类默认是final,如果需要继承,父类必须声明为open
//否则编译器报错“The type is final, so it cannot be inherited from”
open class Bird (var name:String, val sex:Int = MALE) {
//变量、方法、类默认是public,可以省略
//public var sexName:String
var sexName:String
init {
sexName = getSexName(sex)
}
//私有的方法既不能被外部访问,也不能被子类继承,因此open和private不能共存
//否则编译器会报错:Modifier 'open' is incompatiable with ‘private’
//open private fun getSexName(sex:Int):String {
open protected fun getSexName(sex:Int):String {
return if(sex==MALE) "公" else "母"
}
fun getDesc(tag:String):String {
return "欢迎来到$tag:这只${name}是${sexName}的。"
}
companion object BirdStatic{
val MALE = 0
val FEMALE = 1
val UNKNOWN = -1
fun judgeSex(sexName:String):Int {
var sex:Int = when (sexName) {
"公","雌" -> MALE
"母","雄" -> FEMALE
else -> UNKNOWN
}
return sex
}
}
}
继承Bird类生成Duck类
//注意父类Bird已经在构造函数声明了属性,故而子类Duck无须重复声明属性
//也就是说,子类的构造函数在输入参数前面不需要再加val和var
class Duck(name:String="Duck", sex:Int = Bird.MALE) : Bird(name, sex) {
}
定义鸵鸟类
class Ostrich(name:String="鸵鸟", sex:Int = Bird.MALE) : Bird(name, sex) {
//继承protected方法,标准写法是“override protected”
//override protected fun getSexName(sex:Int):String {
//protected默认继承过来默认是protected, 可以省略protected
//override fun getSexName(sex:Int):String {
//protected方法继承过来之后只允许将可见性升级为public,但不能降级为private
override public fun getSexName(sex:Int):String {
return if(sex==MALE) "雄" else "雌"
}
}
说明:
abstract
修饰,内部有abstract
修饰的抽象方法, 无法实例化, 需要子类继承时重写抽象方法,方可使用子类实例化对象。abstract
修饰的方法默认是open
类型的抽象类代码示例:
//定义抽象鸡类
abstract class Chicken(name:String, sex:Int, var voice:String):Bird(name, sex) {
val numberArr:Array<String> = arrayOf("1", "2", "3","4","5", "6","7","8","9","10", "11")
//抽象方法必须在子类进行重写,所以可以省略关键字open,因为abstract方法默认是open类型
//open abstract fun callOut(time:Int):String
abstract fun callOut(time:Int):String
}
//定义公鸡类
class Cock(name: String = "鸡",sex: Int = Bird.MALE, voice: String = "wowowo"):Chicken(name, sex, voice){
override fun callOut(times: Int): String {
var count = when {
times<=0 -> 0
times>=10 -> 9
else -> times
}
return "$sexName $name $voice 叫了${numberArr[count]}声,原来它是在报晓。"
}
}
//定义母鸡类
class Hen(name: String = "鸡",sex: Int = Bird.FEMALE, voice: String = "gegege"):Chicken(name, sex, voice){
override fun callOut(times: Int): String {
var count = when {
times<=0 -> 0
times>=10 -> 9
else -> times
}
return "$sexName $name $voice 叫了${numberArr[count]}声,原来它是在下蛋。"
}
}
fun myChickenTest(){
//公鸡叫
Cock().callOut(15)
//母鸡叫
Hen().callOut(13)
}
说明:
代码举例:
定义 Behavior 接口
interface Behavior {
//Kotlin与Java一样不允许多多重继承,即不能同时继承两个及两个以上类
//否则编译器报错"Only one class may appear in a supertype list"
//所以仍然需要接口interface来间接实现多重继承功能
// 接口不能带构造函数, 否则编译器报错 "An interface may not have a constructor"
//interface Behavior(val action:String) {
//接口内部方法默认是抽象的,可以不加abstract和open
open abstract fun fly():String
//比如下面这个swim方法没加关键字abstract,也无需在此处实现方法
fun swim():String
//Kotlin接口和Java区别在于,Kotlin接口内部允许实现方法
//此时该方法不是抽象方法,就不能加abstract
//不过该方法依然是open类型,接口内部所有方法默认是open类型
fun run():String {
return "大多数鸟类不擅长跑,只有鸵鸟才擅长跑。"
}
//Kotlin的接口允许声明抽象属性,实现该接口的类必须重载该属性
//与接口内部方法一样,抽象属性前面的open和abstract也可以省略
//open abstract var skilledSports:String
var skilledSports:String
}
定义Goose
继承Bird
类并实现Behavior
接口
class Goose (name:String = "鹅", sex:Int = Bird.MALE):Bird(name, sex), Behavior{
override fun fly(): String {
return "鹅能飞一点点,但是飞不高,也飞不远"
}
override fun swim(): String {
return "鹅擅长游泳"
}
//因为接口已经实现了run方法,所以这里可以不用实现该方法,当然也可以实现
override fun run(): String {
//super用来调用父类的属性或者方法,由于kotlin接口允许实现方法,因此super
//所指对象也可以是interface
return super.run()
}
override var skilledSports: String = "游泳"
}
Goose
实例化
fun test(){
var goose = Goose()
goose.fly()
goose.swim()
goose.run()
}
类似于Java中的静态内部类, 嵌套类前面无修饰符,无法访问外部类
嵌套类举例:
class Tree(var treeName: String){
class Flower(var flowerName: String) {
fun getName() :String {
return "flowerName = $flowerName"
//不能访问外部类成员,如treeName, 编译器报错“Unresolved reference:***”
//return “this treename ${treeName} has a flower $flowerName”
}
}
}
使用:
val peachBlossom = Tree.Flower("桃花")
val name = peachBlossom.getName()
内部类前面有修饰符inner
内部类举例:
class Tree(var treeName: String){
inner class Flower(var flowerName: String) {
fun getName() :String {
//只有声明为内部类(关键字inner),才能访问外部类的成员
return "this treename $treeName has a flower $flowerName"
}
}
}
使用:
val peach = Tree("Peach Tree").Flower("Peach flower")
val name = peach.getName()
和Java枚举类很像
枚举类举例:
//无构造函数
enum class SeasonType {
SPRING, SUMMER,AUTUMN, WINTER
}
//有构造函数
enum class SeasonName(val seasonName: String) {
SPRING("春天"),
SUMMER("夏天"),
AUTUMN("秋天"),
WINTER("冬天")
}
枚举类使用
btn_class_name.setOnClickListener {
var seasonName: String;
if(count%2 == 0) {
seasonName = when (count++%4) {
SeasonType.SPRING.ordinal -> SeasonType.SPRING.name
SeasonType.SUMMER.ordinal -> SeasonType.SUMMER.name
SeasonType.AUTUMN.ordinal -> SeasonType.AUTUMN.name
SeasonType.WINTER.ordinal -> SeasonType.WINTER.name
}
} else {
seasonName = when (count++%4) {
SeasonName.SPRING.ordinal -> SeasonName.SPRING.seasonName
SeasonName.SUMMER.ordinal -> SeasonName.SUMMER.seasonName
SeasonName.AUTUMN.ordinal -> SeasonName.AUTUMN.seasonName
SeasonName.WINTER.ordinal -> SeasonName.WINTER.seasonName
}
}
}
密封类是为解决枚举值判断多余分支的问题,像一种更加严格的枚举类,其内部有且仅有自身的实例对象,所以是一个有限的自身实例的集合。
密封类举例:
sealed class SeasonSealed {
class Spring(var name:String) :SeasonSealed()
class Summer(var name:String) :SeasonSealed()
class Autumn(var name:String) :SeasonSealed()
class Winter(var name:String) :SeasonSealed()
}
密封类使用
btn_class_sealed.setOnClickListener {
var season = when(count++%4) {
0 -> SeasonSealed.Spring("Spring")
1 -> SeasonSealed.Summer("Summer")
2 -> SeasonSealed.Autumn("Autumn")
else -> SeasonSealed.Winter("Winter")
}
tv_class_name.text = when(season) {
is SeasonSealed.Spring -> season.name
is SeasonSealed.Summer -> season.name
is SeasonSealed.Autumn -> season.name
is SeasonSealed.Winter -> season.name
}
}
简化了Bean的创建,和Java相比省去许多模板代码, 数据类自带copy、toString、equals等方法
数据类举例:
data class Plant(var name:String, var stem:String, var leaf:String, var flower:String, var seed:String){
//如果类里面没有代码块,大括号可以省略
}
数据类对象创建及使用
var lotus = Plant("植物1","植物2","植物3","植物4","植物5")
var lotus2 = lotus.copy()
如HashMap、ArrayList, 创建实例时才确定类型
泛型类举例:
//类定义
class Box<T>(t: T) {
var value = t
}
//实例化
val box: Box<Int> = Box<Int>(1) // 或者
val box1 = Box(1) // 编译器会进行类型推断,1 类型 Int,所以编译器知道我们说的是 Box<Int>
var boxString = Box<String>("Runoob")
官方文档翻译
https://hltj.gitbooks.io/kotlin-reference-chinese/content/txt/classes.html
Kotlin for android Developer
https://wangjiegulu.gitbooks.io/kotlin-for-android-developers-zh/content/lei_ji_cheng.html
Android官方的Kotlin页
https://developer.android.google.cn/kotlin
菜鸟教程-Kotlin
https://www.runoob.com/kotlin/kotlin-tutorial.html
使用Kotlin构建Android MVVM应用程序
https://www.jianshu.com/p/77e42aebd7bb
参考教材
《Kotlin从零到精通Android开发》
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。