kotlin笔记 八 (七)对象声明与伴生对象.md

如果对象是函数式接口(只有一个抽象方法的接口),则可以使用带接口类前缀的Lambda表达式创建对象,如:Runnable

	Var r=Runnable{

		......(run()方法实现)

	}

1、对象表达式

对象表达式成员:初始化块、属性、方法、内部类(不能包含嵌套类),不能有构造器

对象表达式相当于Java中的匿名内部类,但功能更强大:

  1. 对象表达式可以只用指定父类型,也可以有一个或多个父类型

语法格式:

object[:0-N个父类型(父类类、接口)]{

	初始化块
	属性
	方法
	内部类,不能包含嵌套类
	



}
  1. 对象表达式不能是抽象类,系统在创建对象表达式时就会立即创建对象,因此不允许将对象表达式定义为抽象类
  2. 对象表达式不能定义构造器,但可以有初始化块
  3. 对象表达式可以包含内部类,不能包含嵌套类

Kotlin中表达式:

  1. 表达式在局部范围内(函数或者方法中)或者使用private修饰对象表达式,Kotlin编译器可以识别对象表达式的真实类型;比如:
    fun main(args:Array){
    var obj=object {
    var name=“leslie”
    fun test(){

     	}
    
    
     }
    

    var obj2=object:outputable {
    var name=“leslie”
    fun test(){

     		}
     	override fun output(msg:String){
    
     	}
    
    
     	}
    

    }

这里编译器是可以识别obj变量的类型的,因此也就可以调用其变量以及方法,无论是父类重写的方法还是自己新增的方法、属性

  1. ***(作为成员变量)***非private修饰的对象表达式就和Java中的匿名内部类一样了,编译器只会把该对象表达式当成他父类(接口)处理,不能识别器真实类型,如果对象表达式没有父类,就当成Any类处理,自然对象表达式中新增的属性、方法就调用不到,只能调用继承、重写的方法、属性

    class Sub{
    //1、private修饰的对象表达式
    private var obj={
    var name:String=“leslie”

     	override fun test(mas:String){
    
    
     		}
    
     }
    
     //2、非private
     internal var obj2=object:Outputable{
     	var name:String="leslie"
    
     	override fun test(mas:String){
    
    
     		}
    
     	}
    
     //3、(单表达式函数),对象表达式作为函数返回值
     private fun say()=object:Outputable{
     	var name:String="leslie"
    
     	override fun test(mas:String){
    
    
     		}
    
     	}
    

    //4、(单表达式函数),对象表达式作为函数返回值
    internal fun say()=object:Outputable{
    var name:String=“leslie”

     	override fun test(mas:String){
    
    
     		}
    
     	}
    

    }
    第一和第三种情况由于能识别变量真实类型调用其name属性(obj.name、say().name)自然没有问题,而第二种和第四种情况不能识别其真实类型,只能当做父类型处理,编译期类型即为父类型,由于没有name属性,自然报错;

还有一点就是:java中要求匿名内部类访问局部变量时,局部变量必须final修饰,就是说该局部变量不能别被修改,而Kotlin中可以修改该局部变量;

2、对象声明

其作用就是实现单例模式;

语法

object 对象声明名称[:0-N个父类型]{
	//定义属性
	//方法
	//嵌套类,不能定义内部类(非静态内部类)
	//初始化块


	}

对象声明和对象表达式语法大体格式都一样,也有一些区别:

  1. 对象表达式是一个表达式(可以看做一个对象),可以被赋值给变量,而对象声明不是表达式,不能用于赋值
  2. 对象声明可以包含嵌套类,但不能包含内部类;而对象表达式只能包含内部类而不能包含嵌套类
    3.*** 对象声明不能定义在函数或方法内,但对象表达式可嵌套在其他对象声明中或非内部类中***

对象声明定义位置

  1. 在kotlin文件中定义对象声明:

    interface Outputable{
    fun output(msg:String)
    }

    abstract class Product(var price:Double){
    abstract val name:String
    abstract fun printInfo()
    }

    object MyObj1:Outputable{
    override fun output(msg: String) {
    Log.d(“TAG”,“重写从父类继承到的方法”)
    }

    }

    object MyObj2{
    init {
    Log.d(“TAG”,“初始化块”)
    }
    var name=“Kotlin”
    fun test(){
    Log.d(“TAG”,“test方法”)
    }
    class Foo

    }

调用:MyObj1.output(“输出设备”)

  1. 在类体中定义

     class ObjectDecl{
    
        object  MyObj3{
             init {
                 Log.d("TAG","定义在类体中的对象声明的初始块")
             }
           var name:String="leslie"
           class Foo
           fun info(){
               Log.d("TAG","定义在类体中的对象声明的方法")
           }
     
         }
    
    
     }
    

调用:ObjectDecl.MyObj3.info()

对象声明所定义的对象是该类的唯一实例,通过对象声明的名称直接访问该类的唯一实例;

MyObj1.output(“输出设备”)

在类中定义对象声明

伴生对象

在类中定义对象声明,使用"companion"修饰符,这样对象就变成了伴生对象;

伴生对象作用:就是为外部类提供静态属性、静态方法,弥补kotlin没有静态成员的不足(嵌套类可以看做外部类的静态成员),伴生对象中的方法、属性就可看做外部类的静态属性、静态方法

  1. 一个类最多只能定义一个伴生对象,伴生对象就相当于外部类的对象,可以直接通过外部类直接调用伴生对象的成员;
  2. 伴生对象的名称可以省略,如果省略后,要访问伴生对象,就通过Companion名称访问伴生对象即:外部类.Companion;那伴生对象可以访问了,访问伴生对象的方法、属性也就轻而易举了,即:外部类.Companion.属性/方法

语法:

	companion object 伴生对象名称:(0-N)父类型{

	//定义属性
	//方法
	//嵌套类,不能定义内部类(非静态内部类)
	//初始化块

	}

如:

	interface  Outputable{
    fun output(msg:String)
}



	class MyClass{
    companion object MyObj3:Outputable {
            //伴生对象中属性相当于外部类静态成员变量
        val name="name属性值"
        //伴生对象中的方法相当于外部类中静态方法
        override fun output(msg: String) {

           for (i in 1..6){
               println("<h${i}>${msg}</h${i}>")
           }
        }

    }


}

	fun main(args:Array<String>){
    	MyClass.output("leslie")
    	println(MyClass.name)
}

Kotlin中取消了static修饰符,伴生对象就是Kotlin弥补中没有静态成员的不足;从上面的例子可以看出伴生对象中的属性、方法分别相当于外部类的静态变量、静态方法.

注意:这里Kotlin只是利用伴生模拟java中静态成员,但伴生对象的属性、方法依然是伴生对象的实例成员,并不属于伴生对象所在的外部类;

伴生对象扩展方法

如果一个类具有伴生对象,允许为伴生对象扩展方法和属性,而为伴生对象扩展方法和属性,就就相当于为外部类扩展静态变量、静态方法

如:

	fun MyClass.Object3.test(){}


	val MyClass.Object3.foo
		get()="lelsie"

如果伴生对象省略了名称

	fun Myclass.Companion.test(){
			println("伴生对象扩张方法")
		}

	val MyClass.Companion.info

		get()="leslie"

总结:关于伴生对象、对象表达式、对象声明

对象表达式:(1)、实现的java中匿名内部类功能 (2)、可以定义在文件、函数或方法中、或者类中

对象声明 :(1)、实现的是java中单例类功能、(2)、可以定义在文件、类中、不能定义在函数或者方法中

伴生对象 :(1)、实现为类提供静态成员的功能 (2)、只能定义在类中

当三者定义在类中:

  1. 对象表达式对于外部类来说看做实例变量,可以访问外部类所有成员(静态、实例成员变量),但是外部类不能访问对象表达中成员变量
  2. 对象声明对于外部类:相当于一个静态成员变量(静态内部单例类),不能访问外部类的实例成员变量,反过来外部类不能访问对象声明中的成员变量;
  3. 伴生对象对于外部类相当于:一个静态成员变量(不能访问外部类的实例变量),反过来外部类可以访问伴生对象中定义的任何变量、方法;
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值