当前位置: 首页 > news >正文

省建设厅网站安徽/欧美网站建设

省建设厅网站安徽,欧美网站建设,建设银行网站怎么下载,做网站是找什么人###Kotlin面向对象 ####类的定义与初始化 示例代码如下所示: //需要被继承的话,需要加上open标识 //类的成员需要加上var标识 open class Human(var name: String, var age: Int) {//构造方法的方法体init {println("我是一个${this.javaClass.simp…

###Kotlin面向对象

####类的定义与初始化

示例代码如下所示:

//需要被继承的话,需要加上open标识
//类的成员需要加上var标识
open class Human(var name: String, var age: Int) {//构造方法的方法体init {println("我是一个${this.javaClass.simpleName},$name,今年岁$age")}
}//通过冒号:来继承,成员的初始化类似于C++
class Man(name: String, age: Int) : Human(name, age) {//成员函数	   fun say() {println("你好,我是$name,年龄是$age")}
}//类只有属性没有方法的话,就不需要大括号了
class Woman(name: String, age: Int) : Human(name, age)fun main(args: Array<String>) {//构造类的对象val m = Man("楠宝宝", 20)m.say()val wm = Woman("璐宝宝", 18)//类似于Java,Kotlin中任意类都是Any的子类println(m is Any)
}
复制代码

其中,类的最完整的写法是要加上修饰符和constructor(构造函数):

open class Human public constructor(var name: String, var age: Int) {init {println("我是一个${this.javaClass.simpleName},$name,今年岁$age")}
}
复制代码

####类的属性

如下面的代码所示,类的属性可以在构造方法的参数列表中用var或者val定义,也可以在类内部定义。(注意:没有var或者val声明的都为构造方法的一般形参)

class Man(var name: Int, args: Int) {var age: Int = 0
}
复制代码

Kotlin中默认为属性实现了get/set方法,但是我们可以重写,可以修改访问权限,比如我们在get/set中打印一句话:

class Man(var name: Int, args: Int) {var age: Int = 0protected set(value) {println("我是set方法")field = value}get() {println("我是get方法")return field}
}
复制代码

属性的初始化:

class Xclass Man(var name: Int, args: Int) {//基本的几种类型可以直接用默认值初始化var age: Int = 0//var用lateinit关键字延迟初始化lateinit var s: String//val用lazy延迟初始化val x: X by lazy {//传入的是一个Lambda表达式,返回值是X类型X()}
}
复制代码
  • 属性的初始化尽量在构造方法中完成,如果无法完成初始化,那么尝试降级为局部变量
  • 基本的几种类型可以直接用默认值初始化,var用lateinit关键字延迟初始化,val用lazy延迟初始化
  • 可空类型慎用null初始化,因为可空类型使用起来比较麻烦

####接口与抽象类

接口可以理解为是一种协议,不能够有状态;而抽象类可以理解为半成品,可以有状态。

例子代码如下:

interface A {//接口中的变量不可以初始化,也就是不能有状态,必须由类实现后使用var i: Int//与Java不一样,Kotlin中的接口可以有没有状态的默认实现fun a() {println(i)}
}abstract class B {//抽象类中的变量必须初始化var j = 10//抽象方法必须复写abstract fun b()//非抽象方法不用复写,需要添加open关键字才能覆写fun c(){}
}class C(override var i: Int) : B(), A {override fun a() {super.a()}override fun b() {}
}
复制代码

####接口代理

通过by关键字可以进行接口代理:

interface IA {fun a()
}class A() : IA {override fun a() {println("test")}
}//接口代理,IA的实现实际上是交给a来进行代理
class B(val a: A) : IA by a {}fun main(args: Array<String>) {val a = A()val b = B(a)b.a()}
复制代码

####接口方法冲突

接口方法可以有默认实现。

接口冲突:签名一致,而且返回值类型相同的冲突。这时候子类(实现类)必须覆写冲突的方法,并且通过泛型类解决冲突,例如:

interface A {fun a(): Int {return 1}
}interface B {fun a(): Int {return 2}
}abstract class C() {open fun a(): Int {return 2}
}class D() : C(), A, B {override fun a(): Int {return super<A>.a()}
}
复制代码

####继承

  • 父类需要open才能被继承,抽象类除外
  • 父类的方法、属性需要open才可以被覆写,默认都final
  • 接口、接口方法、抽象类默认为open
  • 覆写父类、接口的成员需要override关键字
  • 继承类的时候实际上调用的父类的构造方法

####类成员的可见性

Kotlin中比较特殊的是internal关键字,是模块(Module)可见。

####单例

通过object关键字可以实现最简单的单例:

object MusicPlayer {fun play() {println("啦啦啦")}
}fun main(args: Array<String>) {MusicPlayer.play()}
复制代码

注意:

  • 这种单例只有一个实现的对象
  • 不能自定义构造方法
  • 可以实现接口、继续父类

本质上,通过反编译成Java代码之后可以看到其实是最简单的单例的实现:

public final class MusicPlayer {public static final MusicPlayer INSTANCE;public final void play() {String var1 = "啦啦啦";System.out.println(var1);}private MusicPlayer() {INSTANCE = (MusicPlayer)this;}static {new MusicPlayer();}
}
复制代码

在Java中是这样使用这个单例的:

MusicPlayer.INSTANCE.play();
复制代码

####伴生对象与静态成员

注意点:

  • 每个类都可以对应一个伴生对象
  • 伴生对象的成员全局只有一个,是单例
  • 相当于Java中的静态成员

例子:

class MusicPlayer {companion object {var SONG = "《萌萌哒》"@JvmFieldvar TAG = MusicPlayer.javaClass.simpleNamefun play(song: String) {println("啦啦啦:$song")}@JvmStaticfun stop() {}}}fun main(args: Array<String>) {val song = MusicPlayer.SONGMusicPlayer.play(song)}
复制代码

在Java中调用的时候,加上JvmField、JvmStatic注解以后可以直接调用,不加的话必须间接调用,例如:

String song = MusicPlayer.Companion.getSONG();
MusicPlayer.Companion.play(song);String tag = MusicPlayer.TAG;
MusicPlayer.stop();
复制代码

注意,当不是特别必要的时候,应该考虑使用包级函数,这样就可以解决使用一个类的方法导入了整个类的麻烦了,例如:

public inline fun minOf(a: Int, b: Int): Int {return Math.min(a, b)
}
复制代码

####方法重载与默认参数

JVM函数签名:函数名、参数列表,注意不包括返回值类型。

方法重载:方法重载主要是名称相同、参数不同的方法。

默认参数:可以为任意一个参数设置默认参数,函数调用产生混淆的时候使用具名参数即可。

下面是一个最简单的方法重载与默认参数的例子:

class A() {@JvmOverloadsfun a(a: Int = 0) {println(a)}fun a(s: String) {println(s)}
}
复制代码

因为Java中没有默认参数,因此需要传参。需要添加@JvmOverloads才可以省略参数,直接使用默认参数。

######Tips:尽量避免使用重载。

####扩展成员

为了弥补一些类的不足,我们可以通过扩展成员来进行二次加工,例如我们可以扩展方法与属性:

//扩展方法
operator fun String.times(time: Int): String {val sb = StringBuilder()for (i in 0 until time) {sb.append(this)}return sb.toString()
}//扩展属性
val String.a: Stringget() = "abc"var String.b: Stringget() = "abc"set(value) {}fun main(args: Array<String>) {val s = "1"//println(s.times(5))println(s * 5)println(s.a)println(s.b)}
复制代码

注意:

  • 扩展属性不能够直接初始化,需要通过实现get方法。
  • Java调用扩展方法、属性的相关信息,暂时放一放……

####属性代理

通过by关键字可以代理属性,类似于接口的代理:

class TestClass() {val s1 by lazy {"1"}val s2 by Delegates()var s3 by Delegates()override fun toString(): String {return "被代理的TestClass"}
}class Delegates() {operator fun getValue(thisRef: Any?, property: KProperty<*>): String {println("getValue 代理了 $thisRef 类的 ${property.name} 属性")return "2"}operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {println("setValue 代理了 $thisRef 类的 ${property.name} 属性")}
}fun main(args: Array<String>) {val t = TestClass()println(t.s1)println(t.s2)println(t.s3)}
复制代码
  • 对于val,代理类需要有getValue方法
  • 对于val,代理类需要有getValue方法以及setValue方法

######Tips:代理是为了屏蔽内部的细节实现,例如我们有一个File属性,通过代理的方式,就可以把文件读取的代理写进代理里面了。

lazy也是一个代理,实现如下:

//Lazy的接口定义
public interface Lazy<out T> {public val value: Tpublic fun isInitialized(): Boolean
}//Lazy的扩展方法
@kotlin.internal.InlineOnly
public inline operator fun <T> Lazy<T>.getValue(thisRef: Any?, property: KProperty<*>): T = value//而Lazy的实现类是SynchronizedLazyImpl
@kotlin.jvm.JvmVersion
public fun <T> lazy(initializer: () -> T): Lazy<T> = SynchronizedLazyImpl(initializer)private class SynchronizedLazyImpl<out T>(initializer: () -> T, lock: Any? = null) : Lazy<T>, Serializable {private var initializer: (() -> T)? = initializer@Volatile private var _value: Any? = UNINITIALIZED_VALUEprivate val lock = lock ?: this//override了Lazy的value,并且重写了get方法override val value: Tget() {val _v1 = _value//如果初始化了,直接返回if (_v1 !== UNINITIALIZED_VALUE) {@Suppress("UNCHECKED_CAST")return _v1 as T}//如果没有初始化,那么需要进行初始化//lazy有三种模式,默认是线程安全的return synchronized(lock) {val _v2 = _valueif (_v2 !== UNINITIALIZED_VALUE) {@Suppress("UNCHECKED_CAST") (_v2 as T)}else {val typedValue = initializer!!()_value = typedValueinitializer = nulltypedValue}}}override fun isInitialized(): Boolean = _value !== UNINITIALIZED_VALUEoverride fun toString(): String = if (isInitialized()) value.toString() else "Lazy value not initialized yet."private fun writeReplace(): Any = InitializedLazyImpl(value)
}
复制代码

lazy有三种模式,默认是线程安全的模式:

@kotlin.jvm.JvmVersion
public fun <T> lazy(mode: LazyThreadSafetyMode, initializer: () -> T): Lazy<T> =when (mode) {LazyThreadSafetyMode.SYNCHRONIZED -> SynchronizedLazyImpl(initializer)LazyThreadSafetyMode.PUBLICATION -> SafePublicationLazyImpl(initializer)LazyThreadSafetyMode.NONE -> UnsafeLazyImpl(initializer)}
复制代码

例如我们需要使用非线程安全的lazy:

val s1 by lazy(mode = LazyThreadSafetyMode.NONE) {"1"
}
复制代码

####数据类

类似于Java中的Bean,Kotlin中有数据类data class:

data class Person(val name: String, val age: Int)fun main(args: Array<String>) {val p = Person("璐宝宝", 18)println(p)
}
复制代码

通过观看Kotlin的字节码,然后反编译成Java代码:

public final class Person {@NotNullprivate final String name;private final int age;@NotNullpublic final String getName() {return this.name;}public final int getAge() {return this.age;}public Person(@NotNull String name, int age) {Intrinsics.checkParameterIsNotNull(name, "name");super();this.name = name;this.age = age;}@NotNullpublic final String component1() {return this.name;}public final int component2() {return this.age;}@NotNullpublic final Person copy(@NotNull String name, int age) {Intrinsics.checkParameterIsNotNull(name, "name");return new Person(name, age);}// $FF: synthetic method// $FF: bridge method@NotNullpublic static Person copy$default(Person var0, String var1, int var2, int var3, Object var4) {if((var3 & 1) != 0) {var1 = var0.name;}if((var3 & 2) != 0) {var2 = var0.age;}return var0.copy(var1, var2);}public String toString() {return "Person(name=" + this.name + ", age=" + this.age + ")";}public int hashCode() {return (this.name != null?this.name.hashCode():0) * 31 + this.age;}public boolean equals(Object var1) {if(this != var1) {if(var1 instanceof Person) {Person var2 = (Person)var1;if(Intrinsics.areEqual(this.name, var2.name) && this.age == var2.age) {return true;}}return false;} else {return true;}}
}
复制代码

可以看到:

  • Kotlin的数据类默认实现了toString、copy等方法
  • Kotlin的数据类是一个final类,不可以被继承,也没有默认的无参构造方法
  • Kotlin中有componentN方法,用于返回第几个属性

#####componentN方法

我们在Kotlin中可以这样赋值,本质上是调用了componentN方法:

val p = Person("璐宝宝", 18)
val (name, age) = p
复制代码

通过看字节码,可以看到的确是调用了componentN方法:

LINENUMBER 8 L1
NEW com/nan/kotlin/Person
DUP
LDC "\u7490\u5b9d\u5b9d"
BIPUSH 18
INVOKESPECIAL com/nan/kotlin/Person.<init> (Ljava/lang/String;I)V
ASTORE 1
复制代码

L2 LINENUMBER 9 L2 ALOAD 1 ASTORE 4 ALOAD 4 INVOKEVIRTUAL com/nan/kotlin/Person.component1 ()Ljava/lang/String; ASTORE 2 ALOAD 4 INVOKEVIRTUAL com/nan/kotlin/Person.component2 ()I ISTORE 3 ACONST_NULL ASTORE 4 L3

又例如我们在遍历数组的时候也可以这样写:

for ((index, value) in args.withIndex()) {println("$index : $value")
}
复制代码

withIndex()方法的实现如下:

public fun <T> Array<out T>.withIndex(): Iterable<IndexedValue<T>> {return IndexingIterable { iterator() }
}
复制代码

其中IndexedValue就是一个数据类:

public data class IndexedValue<out T>(public val index: Int, public val value: T)
复制代码

当然,一般的类也可以有componentN方法,注意是需要加上operator,因为这是操作符重载的方法:

class Test() {operator fun component1(): String {return "哈哈"}operator fun component2(): Int {return 1}
}fun main(args: Array<String>) {val (str, i) = Test()}
复制代码

#####构造方法与final的解决

因为Kotlin中的数据类都是final类不能被继承,又没有提供默认的构造方法,因此不能被一些含有反射构造类的框架使用。为了解决这个问题,需要引入两个插件,gradle脚本如下:

buildscript {//省略一些代码dependencies {//添加两个插件classpath "org.jetbrains.kotlin:kotlin-noarg:$kotlin_version"classpath "org.jetbrains.kotlin:kotlin-allopen:$kotlin_version"}
}//省略一些代码
apply plugin: 'kotlin-noarg'
apply plugin: 'kotlin-allopen'//添加配置
noArg{annotation("com.nan.annotations.PoKo")
}allOpen{annotation("com.nan.annotations.PoKo")
}//省略一些代码
复制代码

其中的PoKo注解是一个自定义的注解:

annotation class PoKo
复制代码

最后通过看字节码可以发现我们的数据类已经不是final类型,并且有默认的构造方法了:

public class Person {//省略一些代码public Person() {}
}
复制代码

但是这是在编译出来字节码之后修改字节码实现的,我们自己调用的时候还是不能访问。但是我们可以通过类似于反射的手段来进行访问。

####内部类

#####内部类的访问控制

先来看一段Java代码:

public class OutterJava {//注意这里的访问权限public class InnerJava {}public static void main(String[] args) {}}
复制代码

注意,内部的访问控制分为以下几种:

  1. private:只有在外部类OutterJava的范围内可以访问
  2. protect:在外部类OutterJava及其子类的范围内可以访问
  3. 不写权限(默认):同一个包都可以访问
  4. public:所有类都可以访问

然后来看Kotlin代码:

class Outter {private class Inner {}
}
复制代码

如此类推。

#####静态内部类与非静态内部类

先来说说非静态内部类,看一段Java代码:

public class OutterJava {public int i;public class InnerJava {public void test() {//非静态内部类持有外部类的this引用//比如下面两句代码是等价的System.out.println(i);System.out.println(OutterJava.this.i);}}public static void main(String[] args) {//不能直接实例化内部类的对象//InnerJava inner = new InnerJava();OutterJava outter = new OutterJava();//非静态内部类需要用外部类的对象进行实例化InnerJava inner = outter.new InnerJava();}}
复制代码

可以看出:

  1. 非静态内部类持有外部类的状态,即this引用
  2. 非静态内部类需要用外部类的对象进行实例化

下面来看静态内部类的Java代码:

public class OutterJava {public int i;public static class InnerJava {public void test() {//静态内部类持有外部类的this引用//比如下面两句代码是等价的//System.out.println(i);//System.out.println(OutterJava.this.i);}}public static void main(String[] args) {InnerJava inner = new InnerJava();}}
复制代码

可以看出:

  1. 静态内部类没有持有外部类的状态、this引用
  2. 静态内部类不需要用外部类的对象进行实例化

在Kotlin中,内部类默认都是静态内部类,如果需要定义非静态内部类,需要加上inner关键字:

class Outter {val i: Int = 0inner class Inner {val i: Int = 1fun test() {//访问自己的iprintln(this.i)println(this@Inner.i)//访问外部类的iprintln(this@Outter.i)}}
}fun main(args: Array<String>) {val outter = Outter()val inner = outter.Inner()}
复制代码

下面来看看默认下的静态内部类:

class Outter {val i: Int = 0class Inner {val i: Int = 1fun test() {//访问自己的iprintln(this.i)println(this@Inner.i)//静态内部类不能访问外部类的i//println(this@Outter.i)}}
}fun main(args: Array<String>) {//静态内部类可以直接初始化val inner = Outter.Inner()}
复制代码

使用场景:

  1. 内部实例必须依赖外部类的实例才能运行,使用非静态内部类
  2. 只是逻辑上的关系,可以不依赖实例的时候,使用静态内部类

#####匿名内部类

关于匿名内部类,看下面的例子:

open class Test {}interface OnClickListener {fun onClick(view: View)
}class View {private var mOnClickListener: OnClickListener? = nullfun setOnClickListener(listener: OnClickListener) {this.mOnClickListener = listener}
}fun main(args: Array<String>) {val view = View()view.setOnClickListener(object : Test(), OnClickListener {override fun onClick(view: View) {}})}
复制代码

注意:

  1. 通过object类写一个匿名内部类。
  2. 与Java不同的是,写匿名内部类的时候,可以直接继承的关系,如上面的代码所示。但是这种用法用得不多。
  3. 通过查看字节码,匿名内部类在运行的时候还是会分配一个类名的,甚至我们可以通过反射去获取

####枚举类的定义、静态方法和属性

枚举类也是一个类,只不过这种类比较特殊。下面是一个Kotlin的枚举类的基本使用例子:

enum class Lang(val mHello: String) {ENGLISH("hello"),CHINESE("你好");fun sayHello() {println(mHello)}
}fun main(args: Array<String>) {Lang.CHINESE.sayHello()//打印顺序println(Lang.CHINESE.ordinal)println(Lang.CHINESE.name)//通过名字求枚举Lang.valueOf("CHINESE").sayHello()//打印所有枚举Lang.values().map(::println)}
复制代码

下面几个注意的地方的:

  • Kotlin中枚举类同过enum class类定义,在Java中只是把class省略了而已。编译出来的字节码内容如下:

      //实质上Kotlin把枚举编译成字节码以后,构造方法protected,并且是final类型,不可继承public final enum com/nan/kotlin/Lang extends java/lang/Enum  {public final static enum Lcom/nan/kotlin/Lang; ENGLISHpublic final static enum Lcom/nan/kotlin/Lang; CHINESE//在这里的静态块(类加载的时候)里面初始化所有枚举实现static <clinit>()V//构造方法是protect的,但是protected <init>(Ljava/lang/String;ILjava/lang/String;)V}
    复制代码

####密封类

密封类是子类可数,枚举类是实例可数。

在Kotlin1.1之前密封类只能在内部类定义,1.1之后可以在同一个文件中定义。

//sealed class,子类可数
sealed class PlayerCmd {//有很多个实例有参数,枚举不能做到,因为实例有限class Play(val url: String, val position: Long = 0) : PlayerCmd()class Seek(val position: Long = 0) : PlayerCmd()//只有一个实例object Pause : PlayerCmd()object Resume : PlayerCmd()object Stop : PlayerCmd()}
复制代码

对比枚举类:

//枚举,实例可数
enum class PlayerState{IDEL,PAUSE,PLAYING
}
复制代码

如果觉得我的文字对你有所帮助的话,欢迎关注我的公众号:

我的群欢迎大家进来探讨各种技术与非技术的话题,有兴趣的朋友们加我私人微信huannan88,我拉你进群交(♂)流(♀)

http://www.lbrq.cn/news/1241983.html

相关文章:

  • 智慧团建网站怎么转团关系/高端营销型网站制作
  • 淮南网站推广/百度首页网站推广多少钱一年
  • 厚街手机网站建设/外链购买交易平台
  • 怎么网站代备案/百度一下 官方网
  • wordpress 调用文章内容/关于seo如何优化
  • 番禺制作网站报价/搜索引擎名词解释
  • 网站建设主要包括两个方面/太原seo公司
  • 个人主页模板图片导航栏/搜索引擎优化大致包含哪些内容或环节
  • 想要将网站信息插到文本链接怎么做/南京seo公司哪家
  • 如何做网站站内搜索/网络营销专业学什么
  • 国际网站建设公司/seo优化对网店的推广的作用为
  • 网站管理助手ftp/深圳最好的外贸seo培训
  • 空间坐标系做图网站/湖北百度seo排名
  • 天津网站建设培训学校/信息流广告公司排名
  • dedecms导入网站模板/网络舆情的网站
  • asp.net做三个网站/软文广告发稿
  • 字体设计图片/佛山seo联系方式
  • 网站制作工具 织梦/国内网络销售平台有哪些
  • 图片制作在线生成器免费版/宁波网络推广优化公司
  • 南昌网站开发公司电话/杭州seo公司排名
  • 建筑公司转让/武汉seo公司
  • 兼职做网站这样的网站/网络推广外包哪家好
  • 网上做代销上哪个网站/友情链接2598
  • 一个企业做网站的目的/域名备案查询
  • 用html做企业门户网站/企业qq
  • 网站建设佰金手指科捷一/北京网站建设开发公司
  • 在线营销型网站/优化网站排名费用
  • 深圳住房和建设局网站富士锦园/开平网站设计
  • 哪类型网站容易做/网站排名优化制作
  • 深圳网站建设者/seo怎么收费的
  • MC0364魔法链路
  • Typora v1.10.8 好用的 Markdown 编辑器
  • 力扣热题100---------206.反转链表
  • 李宏毅深度学习教程 第4-5章 CNN卷积神经网络+RNN循环神经网络
  • HarmonyOS】鸿蒙应用开发中常用的三方库介绍和使用示例
  • UE5 动态扫描波