我的kotlin学习笔记(一)——对象
2018-03-07 19:02
621 查看
正儿八经上班第一天,刚刚想写的什么的时候,发现同事在项目里面使用了kotlin。真不知道是该高兴奈还是该高兴奈,总有人推着你前进。那我也开始吧。半年前看过一点,现在忘得差不多了,写的比较乱,都是边开发边学习。
————————-jjj的kotlin学习笔记————————-
1、对象
1.1、对象表达式
先回顾下java的匿名内部类:匿名内部类就是没有名字内部类,因为没有名字只能使用 一次。
那kotlin中如何表达匿名内部类?
这时候对象表达式就登场了:
如果父类有构造函数,则必须传递相应的构造函数;
如果有多个父类,则使用逗号分隔,写在冒号后面。
如果只需要一个对象,没有父类的情况。
值得注意的是,匿名对象可以用作本地(同一方法里)和私有(private)作用域中。具体原因看链接文档
1.2、对象声明和伴生对象
由于kotlin移除了static的概念,便引入对象声明。
对象声明由object关键字+名称表示,对象声明不能用在赋值语句的右边,使用场景:
到这里,先回顾下什么是单例?
单例是种设计模式;使用时,单例的对象必须保证只有一个实例存在,不允许自由构造对象。因此单例的构造函数不对外开放,通常为private。
单例模式的分类:
下面依次分析下各模式:
饿汉式:最简单的实现方式,在类加载的时候就会对实例进行创建,实例在整个程序周期都存在,这也是它的缺点:该类只要加载单例就会被创建,即使没用到,所以容易形成了内存浪费。优点是:只在类加载的时候创建一次实例,不会存在多个线程创建多个实例的情况,避免多线程同步的问题。
懒汉式:解决了饿汉式的类加载后单例创建的问题,懒汉式的单例只在需要的时候才创建,如果单例已经创建,再次调用接口不会重新创建新的对象,而是返回之前的创建对象。但是懒汉模式没有考虑线程安全问题,多个线程可能并发调用它的getInstance()方法,导致创建多个实例,这时候可以加上同步锁。
双重校验锁:懒汉式中使用synchronized修饰的同步方法比一般方法要慢很多,如果多次调用单例方法将存在性能问题。双重校验锁调整了synchronized修饰的位置,并在同步代码块外多了一层instance为空的判断。因此,大部分情况下,调用getInstance()都不会执行到同步代码块,从而提高了程序性能。但也不是万无一失的,设立涉及到java中的指令重排优化,最终结果到时候双重校验锁失效,不过jdk1.5版本后新增的volatile关键字可以解决这个尴尬问题。
总之双重校验锁既实现了延迟加载,又解决了线程并发问题,同时还解决了执行效率的问题。
静态内部类:这种加载方式利用了类加载机智保证只创建一个instanc实例。与饿汉模式一样,不存在多线程并发的问题。不一样的是,静态内部类是在内部类里面创建对象实例的,只要应用中不使用内部类,JVM就不会去加载这个单例类,也不会去创建单例对象,从而实现了懒汉式的延迟加载。
枚举:上面的四种单例模式都有两个共同的缺点:
(1)需要额外的工作来实现序列化
(2)可以使用反射强行调用私有构造函数
枚举很好的解决了这两个问题,使用枚举除了线程安全和防止反射调用构造器之外,还提供了自动序列化机制,防止序列化的时候创建新的对象。奇怪的是在实际工作中,很少有人用枚举。
————————————分割线———————————
kotlin声明单例模式,请参考原文
你可能会发现,原来object类型的单例模式,本质上就是饿汉式加载,即在类加载的时候创建单例。
kotlin的懒汉式加载:
先了解下kotlin中伴生对象:类内部的对象声明可以用companion关键字标记,
懒汉式加载特征:
1. 显示声明构造方法为private;
2. companion object用来在class内部声明一个对象;
3. LazySingleton 的实例instance通过lazy来实现懒汉式加载
4. lazy默认情况下线程是安全的,可以避免多个线程同事访问生成多个实例的问题
对于实例初始化花费时间较少,并且内存占用较低的话,应该使用object形式的饿汉式加载。否则使用懒汉式。
————————-jjj的kotlin学习笔记————————-
1、对象
1.1、对象表达式
先回顾下java的匿名内部类:匿名内部类就是没有名字内部类,因为没有名字只能使用 一次。
// 匿名内部类: new 类名或接口名(){ 重写方法; }; // 常见实例 textView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { ... } });
那kotlin中如何表达匿名内部类?
这时候对象表达式就登场了:
// 对象表达式: object: 类名或接口名(){ 重写方法 }; // 实例: textView.setOnClickListener(object : View.OnClickListener{ override fun onClick(v: View?) { ... } })
如果父类有构造函数,则必须传递相应的构造函数;
如果有多个父类,则使用逗号分隔,写在冒号后面。
var a = object : A(this), B { override fun testA() { ... } override fun testB() { ... } } abstract class A(ctx: Context) { abstract fun testA() } interface B { fun testB() }
如果只需要一个对象,没有父类的情况。
val o = object { var x = 1 var y = 2 } var result = o.x + o.y
值得注意的是,匿名对象可以用作本地(同一方法里)和私有(private)作用域中。具体原因看链接文档
// 私有函数,其返回类型是匿名对象类型 private fun foo1() = object { val x: String = "x" val y: String = "y" } fun bar(){ // 本地属性 val foo2 = object { val x: String = "x" val y: String = "y" } val x1 = foo1().x val x2 = foo2.y }
1.2、对象声明和伴生对象
由于kotlin移除了static的概念,便引入对象声明。
对象声明由object关键字+名称表示,对象声明不能用在赋值语句的右边,使用场景:
// 1.静态变量 object Constant { /** * baseUrl */ val REQUEST_BASE_URL = "http://gank.io/api/" val ALL = "all" val ANDROID = "Android" ... } // 2、单例模式 object SimpleSington { fun test() {} }
到这里,先回顾下什么是单例?
单例是种设计模式;使用时,单例的对象必须保证只有一个实例存在,不允许自由构造对象。因此单例的构造函数不对外开放,通常为private。
单例模式的分类:
// 1、饿汉式: public class Singleton{ private static Singleton instance = new Singleton(); private Singleton(){} public static Singleton newInstance(){ return instance; } } // 2、懒汉式: public class Singleton{ private static Singleton instance = null; private Singleton(){} public static Singleton newInstance(){ if(null == instance){ instance = new Singleton(); } return instance; } } // 懒汉式:加同步锁解决线程同步问题 public class Singleton{ private static Singleton instance = null; private Singleton(){} public static synchronized Singleton newInstance(){ if(null == instance){ instance = new Singleton(); } return instance; } } // 3、双重校验锁: public class Singleton { private static Singleton instance = null; private Singleton(){} public static Singleton getInstance() { if (instance == null) { synchronized (Singleton.class) { if (instance == null) {//2 instance = new Singleton(); } } } return instance; } } // 双重校验锁:防止指令重排优化 public class Singleton { private static volatile Singleton instance = null; private Singleton(){} public static Singleton getInstance() { if (instance == null) { synchronized (Singleton.class) { if (instance == null) { instance = new Singleton(); } } } return instance; } } // 4、静态内部类 public class Singleton{ private static class SingletonHolder{ public static Singleton instance = new Singleton(); } private Singleton(){} public static Singleton newInstance(){ return SingletonHolder.instance; } } // 5、枚举 public enum Singleton{ instance; public void whateverMethod(){} }
下面依次分析下各模式:
饿汉式:最简单的实现方式,在类加载的时候就会对实例进行创建,实例在整个程序周期都存在,这也是它的缺点:该类只要加载单例就会被创建,即使没用到,所以容易形成了内存浪费。优点是:只在类加载的时候创建一次实例,不会存在多个线程创建多个实例的情况,避免多线程同步的问题。
懒汉式:解决了饿汉式的类加载后单例创建的问题,懒汉式的单例只在需要的时候才创建,如果单例已经创建,再次调用接口不会重新创建新的对象,而是返回之前的创建对象。但是懒汉模式没有考虑线程安全问题,多个线程可能并发调用它的getInstance()方法,导致创建多个实例,这时候可以加上同步锁。
双重校验锁:懒汉式中使用synchronized修饰的同步方法比一般方法要慢很多,如果多次调用单例方法将存在性能问题。双重校验锁调整了synchronized修饰的位置,并在同步代码块外多了一层instance为空的判断。因此,大部分情况下,调用getInstance()都不会执行到同步代码块,从而提高了程序性能。但也不是万无一失的,设立涉及到java中的指令重排优化,最终结果到时候双重校验锁失效,不过jdk1.5版本后新增的volatile关键字可以解决这个尴尬问题。
总之双重校验锁既实现了延迟加载,又解决了线程并发问题,同时还解决了执行效率的问题。
静态内部类:这种加载方式利用了类加载机智保证只创建一个instanc实例。与饿汉模式一样,不存在多线程并发的问题。不一样的是,静态内部类是在内部类里面创建对象实例的,只要应用中不使用内部类,JVM就不会去加载这个单例类,也不会去创建单例对象,从而实现了懒汉式的延迟加载。
枚举:上面的四种单例模式都有两个共同的缺点:
(1)需要额外的工作来实现序列化
(2)可以使用反射强行调用私有构造函数
枚举很好的解决了这两个问题,使用枚举除了线程安全和防止反射调用构造器之外,还提供了自动序列化机制,防止序列化的时候创建新的对象。奇怪的是在实际工作中,很少有人用枚举。
————————————分割线———————————
kotlin声明单例模式,请参考原文
// 常见写法 object SimpleSington { fun test() {} } // 在Kotlin里调用 SimpleSington.test() // 在java里调用 SimpleSington.INSTANCE.test(); // 上面的写法相类似于java中的: public final class SimpleSington { public static final SimpleSington INSTANCE; private SimpleSington() { INSTANCE = (SimpleSington)this; } static { new SimpleSington(); } }
你可能会发现,原来object类型的单例模式,本质上就是饿汉式加载,即在类加载的时候创建单例。
kotlin的懒汉式加载:
先了解下kotlin中伴生对象:类内部的对象声明可以用companion关键字标记,
// 1、伴生对象实例 class MyClass { companion object Factory { fun create(): MyClass = MyClass() } } // 调用方式 val instance = MyClass.create() // 2、可省略伴生对象的名称 class MyClass { companion object { } } // 调用方式 val x = MyClass.Companion // 懒汉式加载方式 class LazySingleton private constructor(){ companion object { val instance: LazySingleton by lazy { LazySingleton() } } }
懒汉式加载特征:
1. 显示声明构造方法为private;
2. companion object用来在class内部声明一个对象;
3. LazySingleton 的实例instance通过lazy来实现懒汉式加载
4. lazy默认情况下线程是安全的,可以避免多个线程同事访问生成多个实例的问题
对于实例初始化花费时间较少,并且内存占用较低的话,应该使用object形式的饿汉式加载。否则使用懒汉式。
相关文章推荐
- Kotlin学习笔记(四)【类和对象】
- Kotlin 学习笔记(八)—— Kotlin类与对象之接口
- Kotlin学习笔记(八)对象
- [Kotlin]Kotlin学习笔记(四):类与对象、泛型详解
- Kotlin学习笔记3-11 类和对象-对象
- Kotlin学习笔记3-3 类和对象-接口
- Kotlin学习笔记3-9 类和对象-嵌套类
- Kotlin学习笔记3-4 类和对象-访问限制
- Kotlin学习笔记3-12 类和对象-委托
- Kotlin 学习笔记(七)—— Kotlin类与对象之属性与字段
- Kotlin学习笔记3-5 类和对象-扩展
- 新手上路,Kotlin学习笔记(三)---类、对象、接口
- 【Java学习笔记】对象的流读写(串行化)
- Hibernate学习笔记 -- day10 OID、对象导航查询、原生SQL
- 学习笔记--面向对象继承
- JavaScript学习笔记之对象
- ajax,json学习笔记(二)XMLHttpRequest对象
- JavaScript学习笔记之JS对象
- Python学习笔记 类和对象
- Scala中隐式对象代码实战详解之Scala学习笔记-54