目录
抽象类与接口
多态和接口代理
kotlin 中接口函数冲突问题
类及其成员的可见性
object(单例模式)
伴生对象和静态成员
方法重载与默认参数
扩展成员
属性代理
数据类
内部类
枚举
密封类
抽象类与接口
接口是对类的抽象, 在 kotlin 中定义一个接口如下
- interface InputDevice{
- fun input()
- }
接口也是可以继承的
interface UsbInputDevice : InputDevice
抽象类介于实际类和接口之间, 它是一个不能够直接实例化的类, 只能用来继承
abstract class UsbMouse : UsbInputDevice
kotlin 中的接口和 java 中接口的区别
我们在 kotlin 中定义一个接口
- interface A{
- var j:Int
- fun helle(){
- print(j)
- }
- }
- class B(override var j: Int) : A
可是在 java 中却不能像上面一样声明变量和方法实现
多态和接口代理
kotlin 中多态的体现
- abstract class Person(open val age : Int){
- abstract fun work()
- }
- class Engineer(age: Int):Person(age){
- init {
- println("我是工程师")
- }
- override val age : Int
- get() = 33
- override fun work() {
- println("正在画工程图")
- }
- }
- class Doctor(age: Int):Person(age){
- init {
- println("我是医生")
- }
- override fun work() {
- println("正在给病人看病")
- }
- }
接口代理实现
- interface Driver{
- fun drive()
- }
- interface Writer{
- fun write()
- }
- class SeniorManager(val driver : Driver, val writer: Writer) : Driver by driver, Writer by writer
类及其成员的可见性
object(单例模式)
object 和 class 一样, 只是只有一个实例而已, 在 kotlin 中使用单例可以直接用 object 声明类
- object MusicPlayer{
- fun play(){
- }
- }
在 java 中调用该单例
- public class TestJ {
- public void test(){
- MusicPlayer.INSTANCE.play();
- }
- }
其实 kotlin 中的 object 声明就相当于 java 中这样去声明单例
- public class MusicPlayerJava {
- public static MusicPlayerJava INSTANCE = new MusicPlayerJava();
- private MusicPlayerJava(){}
- }
伴生对象和静态成员
伴生对象有点相当于 java 中静态方法, 我们去定义一个类的伴生对象通过 object 关键字, 这样我们就可以像调用静态方法那样调用 object 中的方法, 具体实现如下
- class Latitude private constructor(val value: Double){
- companion object {
- fun ofDouble(double: Double):Latitude{
- return Latitude(double)
- }
- fun ofLatitude(latitude: Latitude):Latitude{
- return Latitude(latitude.value)
- }
- }
- }
- fun main(args : Array<String>){
- val latitude = Latitude.ofDouble(3.0)
- val latitude2 = Latitude.ofLatitude(latitude)
- }
那么在 java 中应该如何调用呢?
- public class StaticJava {
- Latitude latitude = Latitude.Companion.ofDouble(3.0);
- }
但是这样调用还是不是很方便, 我们想像调用静态方法一样调用, 这时可以加上 @JvmStatic
- class Latitude private constructor(val value: Double){
- companion object {
- @JvmStatic
- fun ofDouble(double: Double):Latitude{
- return Latitude(double)
- }
- @JvmStatic
- fun ofLatitude(latitude: Latitude):Latitude{
- return Latitude(latitude.value)
- }
- }
- }
在 java 中调用也就是这样
- public class StaticJava {
- Latitude latitude = Latitude.ofDouble(3.0);
- }
是不是和调用静态方法一样了. 下面我们再来说一下静态成员, 我声明一个 TAG, 只需要加上 @JvmField 关键字就是一个静态成员了, 在 Java 中也可以像调用静态成员变量一样调用.
- @JvmField
- val TAG = "Latitude"
函数重载与默认参数
首先我们谈谈函数签名, 函数签名包含函数名和参数的类型和顺序 (注意返回值不属于函数签名)
kotlin 中可以定义默认参数, 默认参数主要是用来避免不必要的函数重载
- class Overloads{
- fun a():Int{
- return 0
- }
- fun a(int : Int) : Int{
- return int
- }
- }
如上, 函数重载我们可以通过默认参数简化成一个方法
- class Overloads{
- fun a(int : Int = 0) : Int{
- return int
- }
- }
不过这样子写是不能兼容 java 的, 我们这时候可以加上 @JvmOverloads, 这样 java 也可以调用.
- class Overloads{
- @JvmOverloads
- fun a(int : Int = 0) : Int{
- return int
- }
- }
扩展成员
我们在 java 中总是会定义各种各样的 Utils 去实现一些类的扩展, 比如说我想去判断一个 String 是否为 null 或者为 "", 我们会去写一个 StringUtils 用来判断这种情况.
- public class StringUtils {
- public static boolean isEmpty(String str){
- return str == null || str.equals("");
- }
- }
而在 kotlin 中可以对类中的方法进行扩展 (不光是方法, 成员变量也是可以扩展的)
目前有一个需求是重复输出字符串, 但是 String 中是不存在这种复制字符串的方法的, 在 kotlin 中我们可以对 String 类进行扩展, 完整实现如下.
- fun main(args : Array<String>){
- println("abc".multiply(16))
- }
- fun String.multiply(int : Int) : String{
- val stringBuilder = StringBuilder()
- for (i in 0 until int){
- stringBuilder.append(this)
- }
- return stringBuilder.toString()
- }
上面我们提到, 除了成员方法可以扩展外, 属性也是可以进行扩展的.
- fun main(args : Array<String>){
- println("abc".a)
- "abc".b = 10
- }
- val String.a : String
- get() = "abc"
- var String.b : Int
- set(value){
- }
- get() = 5
最后补充一点, 运算符也是可以重载的哦
- fun main(args : Array<String>){
- println("abc" * 16)
- }
- operator fun String.times(int : Int) : String{
- val stringBuilder = StringBuilder()
- for (i in 0 until int){
- stringBuilder.append(this)
- }
- return stringBuilder.toString()
- }
在 java 中调用 kotlin 的扩展方法
- public class ExtendsJava {
- public static void main(String ...args){
- String result = ExtendsKt.times("abc",16);
- }
- }
属性代理
- class Delegates{
- val hello by lazy {
- "Hello World"
- }
- }
一旦我们在成员变量后面加上 by 这个关键字, 它的 get 方法就交给后边的代理对象执行了
自定义代理对象
- class X{
- private var value : String? = null
- operator fun getValue(thisRef: Any?, property: KProperty<*>): String {
- return value?:""
- }
- operator fun setValue(thisRef: Any?, property: KProperty<*>,value:String){
- this.value = value
- }
- }
数据类
给 class 加上 data 关键字后就成为一个 data class, 在编译后会生成一些有用的方法
- data class Country(val id : Int,val name : String)
- class DataClass(){
- fun test(){
- val china = Country(0,"中国")
- println(china)
- }
- }
这个时候并不需要去重写 Country 中的 toString 方法就可以直接 print 以下字符串
I/System.out: Country(id=0, name = 中国)
这就是 data class 已经帮我我们实现好了, 当然 data class 的好处还不止于此
- val china = Country(0,"中国")
- println(china.component1())
- println(china.component2())
- val(id,name) = china
- println(id)
- println(name)
component 方法并不是 data class 专属的, 也可以自己在类中定义
- class DataClass(){
- fun test(){
- val componentX = ComponentX()
- val(a, b, c, d) = componentX
- print("$a $b $c $d")
- }
- }
- 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
- }
- }
allOpen 和 noArg 插件使用
这两个插件的使用源于把 dataclass 当成 javabean 使用的时候需要一个无参的构造方法, 为了再不改变 dataclass 原有模式的情况下, 官方推出了两个插件 allOpen 和 noArg
首先我们去 gradle 配置这两个插件
创建一个注解
annotation class Poko
最后加上注解
- @Poko
- data class Country(val id:Int, val name: String)
内部类
首先我们必须知道静态内部类和非静态内部类的区别, 静态内部类不持有外部类引用, 非静态内部类持有外部类引用.
在 kotlin 中默认是静态内部类
- class Outter{
- class Inner{
- }
- }
加上 inner 关键字就是非静态内部类
- class Outter{
- inner class Inner{
- }
- }
当外部类成员变量和内部类成员变量有冲突如何引用外部成员变量
- class Outter{
- val a : Int = 0
- inner class Inner{
- val a : Int = 5
- fun hello(){
- a
- println(this@Outter.a)
- }
- }
- }
匿名内部类的实现
- class View{
- var onClickListener : OnClickListener ?= null
- }
- fun main(args : Array<String>){
- val view = View()
- view.onClickListener = object : OnClickListener{
- override fun onClick() {
- }
- }
- }
枚举
- 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 "LogLevel(id=$id)(name=$name)"
- }
- }
- fun main(args: Array<String>) {
- println(LogLevel.DEBUG.ordinal)
- LogLevel.values().map(::print)
- }
密封类
密封类的类继承关系只能在文件里面.
- 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()
- }
最后
在这里我总结出了互联网公司 Android 程序员面试涉及到的绝大部分面试题及答案做成了文档和架构视频资料免费分享给大家 [包括高级 UI, 性能优化, 架构师课程, NDK,Kotlin, 混合式开发 (ReactNative+Weex),Flutter 等架构技术资料] , 希望能帮助到您面试前的复习且找到一个好的工作, 也节省大家在网上搜索资料的时间来学习.
来源: http://www.jianshu.com/p/2d20eab7ac03