kotlin学习总结——object关键字数据类密封类嵌套类和内部类
Posted AC_Jobim
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了kotlin学习总结——object关键字数据类密封类嵌套类和内部类相关的知识,希望对你有一定的参考价值。
object关键字、数据类、密封类、嵌套类和内部类
一、object关键字
object的三种使用场景:
- 对象声明(Object Declaration)
- 伴生对象(Companion Object)
- 对象表达式(Object Expression)
1.1 对象声明
对象声明是将类的声明和定义该类的单例对象结合在一起。当 object 修饰一个 class 时,这个类就只有一个对象,称为对象声明
。(kotlin中使用object关键字来保证单例)
对象声明的初始化过程是线程安全的并且在首次访问时进行。
//使用object定义的类为单例类
object ApplicationConfig {
init {
println("ApplicationConfig load...")
}
fun doSomething(){
println("doSomething")
}
}
fun main() {
//如需引用该对象,我们直接使用其名称即可:
ApplicationConfig.doSomething()
}
注意点:
- 尽管和普通类的声明一样,可以包含属性、方法、初始化代码块以及可以继承其他类或者实现某个接口,但是它不能包含构造器(包括主构造器以及次级构造器)
- 它也可以定义在一个类的内部
class ObjectOuter {
object Inner{
fun method(){
println("声明在类的内部")
}
}
}
fun main() {
ObjectOuter.Inner.method()//声明在类的内部
}
1.2 伴生对象
在Kotlin中是没有static关键字的,也就是意味着没有了静态方法和静态成员。那么在kotlin中如果要想表示这种概念,取而代之的是
包级别函数
(package-level function)和伴生对象
。
-
语法形式:
class A{ companion object 伴生对象名(可以省略){ //define method and field here } }
-
代码实例
class ConfigMap{ //只有初始化ConfigMap类或调用load函数时,伴生对象的内容才会载入 //而且无论实例化ConfigMap类多少次,这个伴生对象始终只有一个实例存在 companion object{ private const val PATH = "xxxx" fun load() = File(PATH).readBytes() } } fun main() { //方式一 ConfigMap.Factory.load() println(ConfigMap.Factory.PATH) //方式二(推荐方式),可通过只使用类名作为限定符来调用 ConfigMap.load() println(ConfigMap.PATH) }
注意:
- 定义时如果省略了伴生对象名,那么编译器会为其提供默认的名字Companion
- 调用时伴生对象名是可以省略的
-
一个类的伴生对象只能有一个
1.3 对象表达式
Java中的匿名内部类:
- Java中如果在匿名内部类中新添加了一些属性和方法,那么在外界是无法调用的
- 一个匿名内部类肯定是实现了一个接口或者是继承一个类,并且只能是一个,用数学术语说是“有且只有一个”
interface Contents {
void absMethod();
}
public class Hello {
public Contents contents() {
return new Contents() {
private int i = 1;
public int value() {
return i;
}
@Override
public void absMethod() {
System.out.println("method invoked...");
}
};
}
public static void main(String[] args) {
Hello hello = new Hello();
hello.contents().absMethod(); //打印method invoked...
hello.contents().value(); //报错,Cannot resolve method 'value' in 'Contents'
}
}
Kotlin中的对象表达式:
有时候,我们需要创建一个对某个类做了轻微改动的类的对象,而不用为之显式声明新的子类。 Kotlin 用对象表达式和对象声明处理这种情况。
-
语法形式:
object [ : 接口1,接口2,类型1, 类型2]{} //中括号中的可省略
-
实现多个接口和类:
open class Player{ open fun load() = "loading nothing" } interface A{ fun a(): String } fun main() { //对象表达式,实现多个接口和类 val p = object : Player(),A{ override fun load() = "anonymous class load..." override fun a(): String { return "接口A的方法" } } println(p.load()) println(p.a()) }
-
不实现任何接口和类,并且在匿名内部类中添加方法:
fun main(args: Array<String>) { val obj = object { fun a() { println("a invoked") } } obj.a() //打印:a invoked }
-
匿名对象只有定义成局部变量和private成员变量时,才能体现它的真实类型。如果你是将匿名对象作为public函数的返回值或者是public属性时,你只能将它看做是它的父类,当然你不指定任何类型时就当做Any看待。这时,你在匿名对象中添加的属性和方法是不能够被访问的。
class C { // 私有函数,所以其返回类型是匿名对象类型 private fun foo() = object { val x: String = "x" } // 公有函数,所以其返回类型是 Any fun publicFoo() = object { val x: String = "x" } fun bar() { val local = object { fun method(){ println("local") } } local.method() //编译通过 val x1 = foo().x // 没问题 val x2 = publicFoo().x // 错误:未能解析的引用“x” } }
-
Kotlin 允许在匿名类对象内部访问外部的成员,与 Java 不同的是此时外部成员不必再声明为 final (Kotlin 的val)
var name: String = "Kotlin" fun test() { object { fun test(){ println("引用外部的属性 $name") } } }
二、数据类、密封类、嵌套类、内部类
2.1 数据类
数据类即JavaBean ,当我们要定义一个数据模型时使用
1、声明数据类的关键字为:data
// 定义一个名为Person的数据类
data class Preson(var name : String,val sex : Int, var age : Int)
2、编辑器为我们做的事情:
当我们声明一个数据类
时,编辑器自动为这个类做了一些事情.
- 生成
equals()
函数与hasCode()
函数- 生成
toString()
函数,由类名(参数1 = 值1,参数2 = 值2,....)
构成- 由所定义的属性自动生成
component1()、component2()、...、componentN()
函数,其对应于属性的声明顺序。- copy()函数。
3、使用数据类必须满足的条件:
- 主构造函数需要至少有一个参数
- 主构造函数的所有参数需要标记为 val 或 var;
- 数据类不能是抽象、开放、密封或者内部的;
data class Student(var name : String, val age:Int) {}
fun main() {
val student1 = Student("1", 1)
val student2 = Student("1", 1)
println(student1)//Student(name=1, age=1),重写了toString()方法
println(student1 == student2)//true,重写了equals方法,==通过equals()函数进行比较
}
4、copy()
当要复制一个对象,只改变一些属性,但其余不变,copy()
data class User(val name: String, val age: Int)
fun main(args: Array<String>) {
val u = User(name = "lioil", age = 1)
val u1 = u.copy("win") //传递第一参数,第二参数默认
val u2 = u.copy("win",2) //传递所有参数
val u3 = u.copy(age = 3) //命名参数,传递指定参数
println(u1)//User(name=win, age=1)
println(u2)//User(name=win, age=2)
println(u3)//User(name=lioil, age=3)
}
2.2 密封类
作用:用来表示受限的类继承结构。
要声明一个密封类,需要在类名前面添加 sealed
修饰符。虽然密封类也可以有子类,但是所有子类都必须在与密封类自身相同的文件中声明。(在 Kotlin 1.1 之前, 该规则更加严格:子类必须嵌套在密封类声明的内部)。
sealed class SealedExpr{
data class Person(val num1 : Int, val num2 : Int) : SealedExpr()
object Add : SealedExpr() // 单例模式
object Minus : SealedExpr() // 单例模式
}
注意:
一个密封类是自身抽象的,它不能直接实例化并可以有抽象(abstract)成员。
密封类不允许有非private构造函数(其构造函数默认为
private
)。
请注意,扩展密封类子类的类(间接继承者)可以放在任何位置,而无需在同一个文件中。
使用密封类的关键好处在于使用 when
表达式 的时候,如果能够验证语句覆盖了所有情况,就不需要为该语句再添加一个 else
子句了。当然,这只有当你用 when
作为表达式(使用结果)而不是作为语句时才有用。
package six
//密封类
sealed class LicenseStatus2 {
object UnQualified: LicenseStatus2()
object Learning: LicenseStatus2()
class Qualified(val licenseId: String): LicenseStatus2()
}
class Driver2(var status: LicenseStatus2){
fun checkLicense(): String{
//不用使用else语句,且编译器会帮你检查代码处理是否有遗漏
return when (status){
is LicenseStatus2.UnQualified -> "没资格"
is LicenseStatus2.Learning -> "在学"
is LicenseStatus2.Qualified -> "有资格,驾驶证编号:"+
"${(this.status as LicenseStatus2.Qualified).licenseId}"
}
}
}
fun main() {
println(Driver2(LicenseStatus2.Qualified("1245")).checkLicense())//有资格,驾驶证编号:1245
}
密封类的原理:实际上就是在一个私有的抽象类内部再声明多个 Java 中嵌套类也就是 static class .
2.3 嵌套类
- 调用嵌套类的属性或方法的格式为:
外部类.嵌套类().嵌套类方法/属性。在调用的时候嵌套类是需要实例化的
。- 嵌套类不能使用外部类的属性和成员
例:
class Other{ // 外部类
val numOuther = 1
class Nested { // 嵌套类
fun init(){
println("执行了init方法")
}
}
}
fun main(args: Array<String>) {
// 调用格式为:外部类.嵌套类().嵌套类方法/属性
Other.Nested().init() //执行了init方法
}
2.4 内部类
声明一个内部类使用
inner
关键字。
声明格式:inner class 类名(参数){}
- 调用内部类的属性或方法的格式为:
外部类().内部类().内部类方法/属性。在调用的时候嵌套类是需要实例化的
。- 标记为 inner 的嵌套类能够访问其外部类的成员。 内部类会带有一个对外部类的对象的引用
例:
class Other{ // 外部类
val numOther = 1
inner class InnerClass{ // 嵌套内部类
val name = "InnerClass"
fun init(){
println("我是内部类,访问外部类的成员 $numOther")//结果:我是内部类,访问外部类的成员 1
}
}
}
fun main(args: Array<String>) {
Other().InnerClass().init() // 调用格式为:外部类().内部类().内部类方法/属性
}
以上是关于kotlin学习总结——object关键字数据类密封类嵌套类和内部类的主要内容,如果未能解决你的问题,请参考以下文章