Kotlin 进阶之路4 面向对象
2018-05-06 本文已影响14人
香沙小熊
1.面向对向编程
- 本质上就是解决如何用程序描述世界的问题
- 讨论如何把实际存在东西映射成程序的类和对象
- 一种程序设计的思路、思想、方法
/**
* 面向对向编程
* 对某种事物进行抽象化,称之为建模
*
*/
//kotlin 定义:class 类名 constructor(属性列表){更多的属性和方法描述}
//构造器:用来设置类新实例的出厂配置
//类要被继承需要加open
open class Chinese constructor(val sex: Boolean, var region: String) {
//普通属性,与变量定义相似
open val skin = "yellow"
//组合属性,由其它属性计算而来(get)
val avgLife: Double
get() {
when (this.region) {
"Shanghai" -> {
return 82.4
}
"Beijing" ->{
return 80.0
}
else -> {
return 72.1
}
}
}
//组合属性反过来可以影响其它属性(set,可选) this代表实例
var avgSalary : Int
get(){
when(this.region){
"Shanghai" ->{ return 4000}
"Beijing" ->{ return 5100}
else ->{ return 3500}
}
}
set(value) {
when (value) {
in 4500..Int.MAX_VALUE -> {
this.region ="Beijing"
}
in 2800..4100->{
this.region ="Shanghai"
}
else -> {
this.region = "homeland"
}
}
}
//方法:厨艺
open fun cook(): Unit {
val meau = arrayOf("宫爆鸡丁","番茄炒鸡蛋","葱爆牛肉")
val desc = meau.reduce{s1,s2->s1+","+s2}
println("我会${desc}")
}
}
class BeijingPeople(sex: Boolean, region: String = "Beijing") : Chinese(sex, region) {
val greatBuilding="the Forbidden City"
//override覆盖属性好方法
override val skin ="BeijingYellow"
override fun cook() {
super.cook()
val meau = arrayOf("北京烤鸭","北京炸酱面","北京包子")
val desc = meau.reduce{s1,s2->s1+","+s2}
println("我还会${desc}")
}
}
class ShanghaiPeople(sex: Boolean, region: String = "Shanghai") : Chinese(sex, region){
val greatBuilding="the Oriental Pearl Tower"
override val skin ="ShanghaiYellow"
override fun cook() {
super.cook()
val meau = arrayOf("大闸蟹","小汤包","芝士焗面")
val desc = meau.reduce{s1,s2->s1+","+s2}
println("我还会${desc}")
}
}
fun main(args: Array<String>) {
//实例化一个类
val Lili = BeijingPeople(true)
Lili.avgSalary = 6000
println(Lili.region)
println(Lili.avgSalary)
Lili.cook()
println()
val Jack = ShanghaiPeople(true)
Lili.avgSalary = 5000
println(Jack.region)
println(Jack.avgSalary)
Jack.cook()
}
Beijing
5100
我会宫爆鸡丁,番茄炒鸡蛋,葱爆牛肉
我还会北京烤鸭,北京炸酱面,北京包子
Shanghai
4000
我会宫爆鸡丁,番茄炒鸡蛋,葱爆牛肉
我还会大闸蟹,小汤包,芝士焗面
2.抽象类和接口
抽象类:理解为半成品
接口:类似于协议或者某种成品就有的功能
接口
- 不能有状态
- 必须有类对其进行实现后实现
- 接口,直观理解就是一种约定
Kotlin的接口与Objective-C的Protocol比较类似
- 举例
interface InputDevice{
fun input(event: Any)
}
抽象类
- 实现了一部分协议的半成品
- 可以有状态,可以有方法实现
- 必须由子类继承后使用
抽象类和接口的共性
- 比较抽象,不能直接实例化
- 有需要子类(实现类)实现的方法
- 父类(接口)变量可以接受子类(实现类)的实例赋值
抽象类和接口的区别
- 抽象类有状态,接口没有状态
- 抽象类有实现方法,接口只能有无状态的默认实现
- 抽象类只能单继承,接口可以多实现
- 抽象类反应本质,接口提现能力
interface InputDevice {
fun input(event: Any)
}
interface USBInputDevice : InputDevice
interface BLEInputDevice : InputDevice
abstract class USBMouse(val name:String) : USBInputDevice,OpticalMouse {
override fun input(event: Any) {
}
override fun toString(): String {
return name
}
}
interface OpticalMouse{
}
class LogitechMouse:USBMouse("罗技鼠标"){
}
class Computer {
fun addUSBInputDevice(inputDevice: USBInputDevice) {
//插入输入设备
println("add usb input device:$inputDevice")
}
fun addBLEInputDevice(inputDevice: BLEInputDevice) {
//插入输入设备
println("add input device:$inputDevice")
}
fun addInputDevice(inputDevice: InputDevice) {
when (inputDevice) {
is BLEInputDevice -> {
addBLEInputDevice(inputDevice)
}
is USBInputDevice -> {
addUSBInputDevice(inputDevice)
}
else -> {
throw IllegalArgumentException("输入设备不支持")
}
}
}
}
fun main(args: Array<String>) {
val computer = Computer()
val mouse = LogitechMouse()
computer.addInputDevice(mouse)
}
add usb input device:罗技鼠标
3.继承(实现)
继承(实现)语法要点
- 父类需要open才可以被继承
- 父类方法、需要open才可以被覆写
- 接口、接口方法、抽象类默认为open
- 覆写父类(接口)成员需要override关键字
- class D:A(),B,C
- 注意继承类时实际上调用了父类的构造方法
- 类只能单继承,接口可以多实现
接口代理
- class Manager(driver:Driver):Driver by driver
- 接口方法实现交给代理类实现
接口方法冲突
- 接口方法可以有默认实现
- 签名一致且返回值有冲突
- 子类(实现类)必须覆写冲突方法
- super<[父类(接口)名]>.方法名
abstract class Person(open val age: Int) {
open fun work() {
}
}
class Coder(age: Int) : Person(age) {
override val age: Int
get() = 0
override fun work() {
super.work()
println("我是程序员")
}
}
class Doctor(override val age: Int) : Person(age) {
override fun work() {
super.work()
println("我是医生")
}
}
fun main(args: Array<String>) {
val person = Coder(28)
person.work()
println(person.age)
val person2 = Doctor(25)
person2.work()
println(person2.age)
}
我是程序员
0
我是医生
25
class Manager : Driver, Writer {
override fun write() {
}
override fun drive() {
}
}
//写法一
//class SeniorManager(val driver: Driver,val writer: Writer):Driver,Writer{
// override fun drive(){
// driver.drive()
// }
// override fun write(){
// writer.write()
// }
//}
//简写二
class SeniorManager(val driver: Driver, val writer: Writer) : Driver by driver, Writer by writer
class CarDriver : Driver {
override fun drive() {
println("开车了")
}
}
class PPTWriter :Writer{
override fun write(){
println("做PPT了")
}
}
interface Driver {
fun drive() {
}
}
interface Writer {
fun write() {
}
}
fun main(args: Array<String>) {
val driver = CarDriver()
val writer = PPTWriter()
val seniorManager = SeniorManager(driver,writer)
seniorManager.drive()
seniorManager.write()
}
开车了
做PPT了
interface InputDevice {
fun input(event: Any)
}
interface USBInputDevice : InputDevice
interface BLEInputDevice : InputDevice
abstract class USBMouse(val name:String) : USBInputDevice,OpticalMouse {
override fun input(event: Any) {
}
override fun toString(): String {
return name
}
}
interface OpticalMouse{
}
class LogitechMouse:USBMouse("罗技鼠标"){
}
class Computer {
fun addUSBInputDevice(inputDevice: USBInputDevice) {
//插入输入设备
println("add usb input device:$inputDevice")
}
fun addBLEInputDevice(inputDevice: BLEInputDevice) {
//插入输入设备
println("add input device:$inputDevice")
}
fun addInputDevice(inputDevice: InputDevice) {
when (inputDevice) {
is BLEInputDevice -> {
addBLEInputDevice(inputDevice)
}
is USBInputDevice -> {
addUSBInputDevice(inputDevice)
}
else -> {
throw IllegalArgumentException("输入设备不支持")
}
}
}
}
fun main(args: Array<String>) {
val computer = Computer()
val mouse = LogitechMouse()
computer.addInputDevice(mouse)
}
add usb input device:罗技鼠标
4.Kotlin和Java可见性对比
Kotlin | Java |
---|---|
public | public |
private | priavte |
protected | protected |
- | default(包内可见) |
internal(模块类可见) | - |
5.对象声明和表达式
object
- 只有一个实例的类
- 不能自定义构造方法
- 可以实现接口、继承父类
- 本质上就是单例模式最基本的实现
/**
* 有时候只要对某各类进行改造,供零时使用,避免继承
* 对象声明和表达式就很有作用
*
* 面向对象编程的优化,避免一些继承导致的代价过高,保持代码的整洁
*/
//对中国人来说,这个类,可能各省人适合继承
open class Chinese(var name: String) {
open val skin = "yellow"
}
fun main(args: Array<String>) {
//但如果外国人入籍,就不适合用继承
//对象表达式:val 对象名 = object : 类,接口 {//属性或方法的override定义}
val Jack= object : Chinese ("Jack Marry")
{
override val skin = "white"
}
println(Jack.skin)
//纯对象表达式:临时使用,无须继承任何类
val loc = object {
var x = 100
var y = 200
}
println(loc.x)
//相当于调用函数
NetworkRequestManager.register()
//半生对象的方法,与类关联性强
IDCard.create()
}
//对象声明,不能用在函数中
//一般用于对其他类使用上的包装
object NetworkRequestManager{
fun register(){
println("连接网络注册中...")
}
}
//半生对象:一般用于创建一个类的实例"工厂"方法
//Java中的 静态成员
class IDCard{
companion object {
fun create() = IDCard()
}
}
white
100
连接网络注册中...
6.半生对象与静态成员
- 每个类可以对应一个伴生对象
- 伴生对象的成员全局独一份
- 伴生对象的成员类似Java的静态成员
- 静态成员考虑用包级函数、变量替代
- JvmField和JvmStatic的使用
fun main(args: Array<String>) {
val a = minOf(args[0].toInt(), args[1].toInt())
val latitude = Latitude.ofDouble(3.0)
val latitude2 = Latitude.ofLatitude(latitude)
println(Latitude.TAG)
}
class Latitude private constructor(val value: Double) {
companion object {
@JvmStatic
fun ofDouble(double: Double): Latitude {
return Latitude(double)
}
fun ofLatitude(latitude: Latitude): Latitude {
return Latitude(latitude.value)
}
@JvmField
val TAG:String = "Latitude"
}
}
Latitude
JvmStatic JvmField 用于Java类调用
public class StaticJava {
public static void main(String[] args){
Latitude latitude = Latitude.ofDouble(4);
System.out.println("Java:"+Latitude.TAG);
}
}
Java:Latitude
6.方法重载Overloads 和默认参数
方法重载Overloads
- 名称相同、参数不同的方法
- Jvm函数签名的概念:函数名、参数列表
- 跟返回值没有关系
默认参数
- 为函数参数设定一个默认值
- 可以为任意位置的参数设置默认值
- 函数调用产生混淆时用具名参数
两者关系
- 避免定义关系不大的重载
- 方法重载最好能转化为默认参数
- 不好的设计:
- List.remove(int)
- List.remove(Object)
//方法重载和函数名有和参数列表有关系,和函数返回值没关系
class Overloads {
// fun a(): Int {
// return 0
// }
@JvmOverloads //默认参数 是给java调用的
fun a(int: Int = 0): Int {
return int
}
}
fun main(args: Array<String>) {
val overloads = Overloads()
overloads.a()
val integerList = ArrayList<Int>()
integerList.add(555)
integerList.add(2)
integerList.add(3)
integerList.add(4)
integerList.add(9)
integerList.add(45)
println(integerList.toString())
integerList.removeAt(1)
integerList.remove(9)
println(integerList.toString())
}
[555, 2, 3, 4, 9, 45]
[555, 3, 4, 45]
7.扩展成员
- Java调用扩展成员类似调用静态方法
- 为现有类添加方法、属性
- fun X.y():Z{...}
- val X.m 主义扩展属性不能初始化,类似接口属性
fun main(args: Array<String>) {
println("abc" * 16)
"abc".b = 5
println("abc".b)
}
operator fun String.times(int: Int): String {
val stringBuilder = StringBuilder()
for (i in 0 until int) {
stringBuilder.append(this)
}
return stringBuilder.toString()
}
val String.a: String
get() = "abc"
var String.b: Int
set(value) {
}
get() = 5
abcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabc
5
8.属性代理
- 定义方法:
- val/var <property name>:<Type> by
<expression>
- 代理者需要实现相应的setValue/getValue方法:
- lazy原理剖析
9.数据类
- 再见,JavaBean
- 默认实现的copy,toString等方法
- componentN方法
- allOpen和noArg插件 在编译器 把final关键字去掉
import com.haocai.kotlindemo.annotations.Poko
@Poko
data class Country(val id: Int, val name: String)
class ComponentX {
operator fun component1(): String {
return "您还,我是"
}
operator fun component2(): Int {
return 1
}
operator fun component3(): Int {
return 1
}
operator fun component4(): Int {
return 0
}
}
fun main(args: Array<String>) {
val china = Country(0, "中国")
println(china)
println(china.component1())
println(china.component2())
val (id, name) = china
println(id)
println(name)
// for ((index, value) in args.withIndex()) {
// println(index)
// println(value)
// }
val componentX = ComponentX()
val (a, b, c, d) = componentX
println("$a $b $c $d")
}
10.内部类
- 定义在类内部的类
- 与类成员有相似的访问控制
- 默认是静态内部类,非静态用inner关键字
- this@Outter,this@Inner的用法
- 没有定义名字的内部类
- 类名编译时生成,类似Outter$1.class
- 可继承父类、实现多个接口,与Java注意区别
Kotlin写法:
open class Outter {
val a: Int = 0
inner class Inner {
val a: Int = 5
fun hello() {
println(this@Outter.a)
}
}
}
interface OnClickListener {
fun onClick()
}
class View {
var onClickListener: OnClickListener? = null
}
fun main(args: Array<String>) {
val inner = Outter().Inner()
inner.hello()
val view = View()
//匿名内部类 即可以实现接口,同时继承外部类(如,Outter())
view.onClickListener = object : Outter(),OnClickListener{
override fun onClick() {
}
}
}
0
Java类似写法:
public class InnerClassJava {
private int a;
public static void main(String... args) {
InnerClassJava innerClassJava = new InnerClassJava();
Inner inner = innerClassJava.new Inner();
//Inner inner = new Inner(); 报错 除非Inner 是静态
inner.hello();
View view = new View();
view.setOnClickListener(new OnClickListener() {
@Override
public void onClick() {
}
});
}
public class Inner {
public void hello() {
System.out.println(InnerClassJava.this.a); //非静态内部类可以持有外部类的状态
}
}
}
0
11.枚举
- 实例可数的参数,注意枚举也是类
- 可以修改构造,添加成员
- 可以提升代码的表现力,也有一定的性能开销
enum class LogLevel(val id: Int) {
VERBOSE(0), DEBUG(1), INFO(2), WARN(3), ERROR(4), ASSERT(5);
fun getTag(): String {
return "$id,$name"
}
override fun toString(): String {
return "$name,$ordinal"
}
}
class LogLevel2 protected constructor() {
companion object {
val VERBOSE = LogLevel2()
val DEBUG = LogLevel2
val INFO = LogLevel2
val WARN = LogLevel2
val ERROR = LogLevel2
val ASSERT = LogLevel2
}
}
fun main(args: Array<String>) {
println(LogLevel.INFO.getTag())
println(LogLevel.DEBUG.ordinal)
LogLevel.values().map(::println)
}
2,INFO
1
VERBOSE,0
DEBUG,1
INFO,2
WARN,3
ERROR,4
ASSERT,5
12.密封类
- 子类可数(从v1.1开始,只需要与密封类在同一个文件中)
- 枚举是实例可数
sealed class PlayerCmd{
class Play(val url:String ,val position:Long = 0):PlayerCmd()
class Seek(val position:Long ):PlayerCmd()
object Pause:PlayerCmd()
object Resume:PlayerCmd()
object Stop:PlayerCmd()
}
enum class PlayerState{
IDLE,PAUSE,PLAYING
}