您的位置:首页 > 移动开发 > Android开发

我的kotlin学习笔记(一)——对象

2018-03-07 19:02 621 查看
正儿八经上班第一天,刚刚想写的什么的时候,发现同事在项目里面使用了kotlin。真不知道是该高兴奈还是该高兴奈,总有人推着你前进。那我也开始吧。半年前看过一点,现在忘得差不多了,写的比较乱,都是边开发边学习。

————————-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形式的饿汉式加载。否则使用懒汉式。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  android kotlin