精华内容
下载资源
问答
  • From Java To Kotlin c[From Java To Kotlin](https://github.com/MindorksOpenSource/from-java-to-kotlin/blob/master/README-ZH.md)打印日志常量与变量null声明空判断字符串拼接换行三元表达式操作符类型判断和...

    From Java To Kotlin

    打印日志

    • Java
    System.out.print("Amit Shekhar");
    System.out.println("Amit Shekhar");
    
    • Kotlin
    print("Amit Shekhar")
    println("Amit Shekhar")
    

    常量与变量

    • Java
    String name = "Amit Shekhar";
    final String name = "Amit Shekhar";
    
    • Kotlin
    var name = "Amit Shekhar"
    val name = "Amit Shekhar"
    

    null声明

    • Java
    String otherName;
    otherName = null;
    
    • Kotlin
    var otherName : String?
    otherName = null
    

    空判断

    • Java
    if (text != null) {
        int length = text.length();
    }
    
    • Kotlin
    text?.let {
        val length = text.length
    }
    // or simply
    val length = text?.length
    

    字符串拼接

    • Java
    String firstName = "Amit";
    String lastName = "Shekhar";
    String message = "My name is: " + firstName + " " + lastName;
    
    • Kotlin
    val firstName = "Amit"
    val lastName = "Shekhar"
    val message = "My name is: $firstName $lastName"
    

    换行

    • Java
    String text = "First Line\n" +
                  "Second Line\n" +
                  "Third Line";
    
    • Kotlin
    val text = """
            |First Line
            |Second Line
            |Third Line
            """.trimMargin()
    

    三元表达式

    • Java
    String text = x > 5 ? "x > 5" : "x <= 5";
    
    • Kotlin
    val text = if (x > 5)
                  "x > 5"
               else "x <= 5"
    

    操作符

    • java
    final int andResult  = a & b;
    final int orResult   = a | b;
    final int xorResult  = a ^ b;
    final int rightShift = a >> 2;
    final int leftShift  = a << 2;
    final int unsignedRightShift = a >>> 2;
    
    • Kotlin
    val andResult  = a and b
    val orResult   = a or b
    val xorResult  = a xor b
    val rightShift = a shr 2
    val leftShift  = a shl 2
    val unsignedRightShift = a ushr 2
    

    类型判断和转换 (声明式)

    • Java
    if (object instanceof Car) {
    }
    Car car = (Car) object;
    
    • Kotlin
    if (object is Car) {
    }
    var car = object as Car
    

    类型判断和转换 (隐式)

    • Java
    if (object instanceof Car) {
       Car car = (Car) object;
    }
    
    • Kotlin
    if (object is Car) {
       var car = object // 聪明的转换
    }
    

    多重条件

    • Java
    if (score >= 0 && score <= 300) { }
    
    • Kotlin
    if (score in 0..300) { }
    

    更灵活的case语句

    • Java
    int score = // some score;
    String grade;
    switch (score) {
        case 10:
        case 9:
            grade = "Excellent";
            break;
        case 8:
        case 7:
        case 6:
            grade = "Good";
            break;
        case 5:
        case 4:
            grade = "OK";
            break;
        case 3:
        case 2:
        case 1:
            grade = "Fail";
            break;
        default:
            grade = "Fail";
    }
    
    • Kotlin
    var score = // some score
    var grade = when (score) {
        9, 10 -> "Excellent"
        in 6..8 -> "Good"
        4, 5 -> "OK"
        in 1..3 -> "Fail"
        else -> "Fail"
    }
    

    for循环

    • Java
    for (int i = 1; i <= 10 ; i++) { }
    
    for (int i = 1; i < 10 ; i++) { }
    
    for (int i = 10; i >= 0 ; i--) { }
    
    for (int i = 1; i <= 10 ; i+=2) { }
    
    for (int i = 10; i >= 0 ; i-=2) { }
    
    for (String item : collection) { }
    
    for (Map.Entry<String, String> entry: map.entrySet()) { }
    
    • Kotlin
    for (i in 1..10) { }
    
    for (i in 1 until 10) { }
    
    for (i in 10 downTo 0) { }
    
    for (i in 1..10 step 2) { }
    
    for (i in 10 downTo 0 step 2) { }
    
    for (item in collection) { }
    
    for ((key, value) in map) { }
    

    更方便的集合操作

    • Java
    final List<Integer> listOfNumber = Arrays.asList(1, 2, 3, 4);
    
    final Map<Integer, String> keyValue = new HashMap<Integer, String>();
    map.put(1, "Amit");
    map.put(2, "Ali");
    map.put(3, "Mindorks");
    
    // Java 9
    final List<Integer> listOfNumber = List.of(1, 2, 3, 4);
    
    final Map<Integer, String> keyValue = Map.of(1, "Amit",
                                                 2, "Ali",
                                                 3, "Mindorks");
    
    • Kotlin
    val listOfNumber = listOf(1, 2, 3, 4)
    val keyValue = mapOf(1 to "Amit",
                         2 to "Ali",
                         3 to "Mindorks")
    

    遍历

    • Java
    // Java 7 and below
    for (Car car : cars) {
      System.out.println(car.speed);
    }
    
    // Java 8+
    cars.forEach(car -> System.out.println(car.speed));
    
    // Java 7 and below
    for (Car car : cars) {
      if (car.speed > 100) {
        System.out.println(car.speed);
      }
    }
    
    // Java 8+
    cars.stream().filter(car -> car.speed > 100).forEach(car -> System.out.println(car.speed));
    
    • Kotlin
    cars.forEach {
        println(it.speed)
    }
    
    cars.filter { it.speed > 100 }
          .forEach { println(it.speed)}
    

    方法定义

    • Java
    void doSomething() {
       // logic here
    }
    
    void doSomething(int... numbers) {
       // logic here
    }
    
    • Kotlin
    fun doSomething() {
       // logic here
    }
    
    fun doSomething(vararg numbers: Int) {
       // logic here
    }
    

    带返回值的方法

    • Java
    int getScore() {
       // logic here
       return score;
    }
    
    • Kotlin
    fun getScore(): Int {
       // logic here
       return score
    }
    
    // as a single-expression function
    
    fun getScore(): Int = score
    

    无结束符号

    • Java
    int getScore(int value) {
        // logic here
        return 2 * value;
    }
    
    • Kotlin
    fun getScore(value: Int): Int {
       // logic here
       return 2 * value
    }
    
    // as a single-expression function
    
    fun getScore(value: Int): Int = 2 * value
    

    constructor 构造器

    • Java
    public class Utils {
    
        private Utils() { 
          // This utility class is not publicly instantiable 
        }
        
        public static int getScore(int value) {
            return 2 * value;
        }
        
    }
    
    • Kotlin
    class Utils private constructor() {
    
        companion object {
        
            fun getScore(value: Int): Int {
                return 2 * value
            }
            
        }
    }
    
    // another way
    
    object Utils {
    
        fun getScore(value: Int): Int {
            return 2 * value
        }
    
    }
    

    Get Set 构造器

    • Java
    public class Developer {
    
        private String name;
        private int age;
    
        public Developer(String name, int age) {
            this.name = name;
            this.age = age;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    
        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
    
            Developer developer = (Developer) o;
    
            if (age != developer.age) return false;
            return name != null ? name.equals(developer.name) : developer.name == null;
    
        }
    
        @Override
        public int hashCode() {
            int result = name != null ? name.hashCode() : 0;
            result = 31 * result + age;
            return result;
        }
    
        @Override
        public String toString() {
            return "Developer{" +
                    "name='" + name + '\'' +
                    ", age=" + age +
                    '}';
        }
    }
    
    • Kotlin
    data class Developer(val name: String, val age: Int)
    

    原型扩展

    • Java
    public class Utils {
    
        private Utils() { 
          // This utility class is not publicly instantiable 
        }
        
        public static int triple(int value) {
            return 3 * value;
        }
        
    }
    
    int result = Utils.triple(3);
    
    • Kotlin
    fun Int.triple(): Int {
      return this * 3
    }
    
    var result = 3.triple()
    
    • Java
    public enum Direction {
            NORTH(1),
            SOUTH(2),
            WEST(3),
            EAST(4);
    
            int direction;
    
            Direction(int direction) {
                this.direction = direction;
            }
    
            public int getDirection() {
                return direction;
            }
        }
    
    • Kotlin
    enum class Direction(val direction: Int) {
        NORTH(1),
        SOUTH(2),
        WEST(3),
        EAST(4);
    }
    
    展开全文
  • 实际上,通过本项目精心设计的场景和精简的代码,你可以Swift了解到在约会了Jetpack的项目中“到底写了什么” ,以及Kotlin相较Java写法的差异之所在, 在简单感受一下项目源码后,如你开始对“具体该怎么写”,“为...
  • Kotlin概述与Java比较 我为什么放弃java学习Kotlin
    展开全文
  • 比较javakotlin

    千次阅读 2018-07-19 13:47:23
    在2018年的冬天,每天与Kotlin相伴的几个月后,我们总结出了正反两面。这有几个原因: 名称遮蔽 类型推断 编译时空指针安全 类文字 反向类型声明 伴侣对象 集合文字 也许? ...

    在2018年的冬天,每天与Kotlin相伴的几个月后,我们总结出了正反两面。这有几个原因:

     

    名称遮掩

    这是Kotlin让我感到最大惊喜的地方。看看这个函数:

    fun inc(num : Int) {
        val num = 2
        if (num > 0) {
            val num = 3
        }
        println ("num: " + num)
    }

    当你调用inc(1)的时候会输出什么呢?在Kotlin中方法参数是一个值,所以你不能改变num参数。这是好的语言设计,因为你不应该改变方法的参数。但是你可以用相同的名称定义另一个变量,并按照你想要的方式初始化。现在,在这个方法级别的范围中你拥有两个叫做num的变量。当然,同一时间你只能访问其中一个num,所以num的值会改变。将军,无解了。

    在if主体中,你可以添加另一个num,这并不令人震惊(新的块级别作用域)。

    好的,在Kotlin中,inc(1)输出2。但是在Java中,等效代码将无法通过编译。

    void inc(int num) {
        int num = 2; //error: variable 'num' is already defined in the scope
        if (num > 0) {
            int num = 3; //error: variable 'num' is already defined in the scope
        }
        System.out.println ("num: " + num);
    }

    名称遮蔽不是Kotlin发明的。这在编程语言中着很常见。在Java中,我们习惯用方法参数来遮蔽类中的字段。

    public class Shadow {
        int val;
    
        public Shadow(int val) {
            this.val = val;
        }
    }

    在Kotlin中,遮蔽有点过分了。当然,这是Kotlin团队的一个设计缺陷。IDEA团队试图把每一个遮蔽变量都通过简洁的警告来向你展示,以此修复这个问题:Name shadowed。两个团队都在同一家公司工作,所以或许他们可以相互交流并在遮蔽问题上达成一致共识?我感觉——IDEA是对的。我无法想象存在这种遮蔽了方法参数的有效用例。

     

    类型推断

    在Kotlin中,当你申明一个var或者val时,你通常让编译器从右边的表达式类型中猜测变量类型。我们将其称做局部变量类型推断,这对程序员来说是一个很大的改进。它允许我们在不影响静态类型检查的情况下简化代码。

    例如,这段Kotlin代码:

    var a = "10"

    将由Kotlin编译器翻译成:

    var a : String = "10"

    它曾经是胜过Java的真正优点。我故意说曾经是,因为——有个好消息——Java10 已经有这个功能了,并且Java10现在已经可以使用了。

    Java10 中的类型涂端:

    var a = "10";

    公平的说,我需要补充一点,Kotlin在这个领域仍然略胜一筹。你也可以在其他上下文中使用类型推断,例如,单行方法。

    更多关于Java10 中的局部变量类型推断

    编译时空值安全

    Null-safe类型是Kotlin的杀手级特征。这个想法很好。在Kotlin,类型是默认的非空值。如果您需要一个可空类型,您需要添加?符号,例如:

    val a: String? = null      // ok
    
    val b: String = null       // 编译错误

     

    如果您在没有空检查的情况下使用可空变量,那么Kotlin将无法编译,例如:

    println (a.length)          // compilation error
    println (a?.length)         // fine, prints null
    println (a?.length ?: 0)    // fine, prints 0

     

    一旦你有了这两种类型,non-nullable T 和nullable T?,您可以忘记Java中最常见的异常——NullPointerException。真的吗?不幸的是,事情并不是那么简单。

    当您的Kotlin代码必须与Java代码一起使用时,事情就变得很糟糕了(库是用Java编写的,所以我猜它经常发生)。然后,第三种类型就跳出来了——T!它被称为平台类型,它的意思是T或T?,或者如果我们想要精确,T!意味着具有未定义空值的T类型。这种奇怪的类型不能用Kotlin来表示,它只能从Java类型推断出来。T!会误导你,因为它放松了对空的限制,并禁用了Kotlin的空值安全限制。

    看看下面的Java方法:

    public class Utils {
        static String format(String text) {
            return text.isEmpty() ? null : text;
        }
    }

     

    现在,您想要从Kotlin调用format(string)。您应该使用哪种类型来使用这个Java方法的结果?好吧,你有三个选择。

    第一种方法。你可以使用字符串,代码看起来很安全,但是会抛出空指针异常。

    fun doSth(text: String) {
        val f: String = Utils.format(text)       // compiles but assignment can throw NPE at runtime
        println ("f.len : " + f.length)
    }

     

    你需要用增加判断来解决这个问题:

    fun doSth(text: String) {
        val f: String = Utils.format(text) ?: ""  // 
        println ("f.len : " + f.length)
    }

     

    第二种方法。您可以使用String?,然后你的程序就是空值安全的了。

    fun doSth(text: String) {
        val f: String? = Utils.format(text)   // safe
        println ("f.len : " + f.length)       // compilation error, fine
        println ("f.len : " + f?.length)      // null-safe with ? operator
    }

     

    第三种方法。如果你让Kotlin做了令人难以置信的局部变量类型推断呢?

    fun doSth(text: String) {
        val f = Utils.format(text)            // f type inferred as String!
        println ("f.len : " + f.length)       // compiles but can throw NPE at runtime
    }

     

    坏主意。这个Kotlin的代码看起来很安全,也可以编译通过,但是允许空值在你的代码中不受约束的游走,就像在Java中一样。

    还有一个窍门,!!操作符。使用它来强制推断f类型为String类型:

    fun doSth(text: String) {
        val f = Utils.format(text)!!          // throws NPE when format() returns null
        println ("f.len : " + f.length)
    }

     

    在我看来,Kotlin的类型系统中所有这些类似scala的东西!,?和!!,实在是太复杂了。为什么Kotlin从Java的T类型推断到T!而不是T?呢?似乎Java互操作性破坏了Kotlin的杀手特性——类型推断。看起来您应该显式地声明类型(如T?),以满足由Java方法填充的所有Kotlin变量。

     

    类字面量

    在使用Log4j或Gson之类的Java库时,类字面量是很常见的。

    Java中,我们用.class后缀来写类名:

    Gson gson = new GsonBuilder().registerTypeAdapter(LocalDate.class, new LocalDateAdapter()).create();

     

    Groovy中,类字面量被简化为本质。你可以省略.class,不管它是Groovy还是Java类都没关系。

    def gson = new GsonBuilder().registerTypeAdapter(LocalDate, new LocalDateAdapter()).create()

     

    Kotlin区分了Kotlin和Java类,并为其准备了不同的语法形式:

    val kotlinClass : KClass<LocalDate> = LocalDate::class
    val javaClass : Class<LocalDate> = LocalDate::class.java

     

    所以在Kotlin,你不得不写:

    val gson = GsonBuilder().registerTypeAdapter(LocalDate::class.java, LocalDateAdapter()).create()

     

    这真是丑爆了。

     

    相反顺序的类型声明

    在C系列编程语言中,有一个标准的声明类型的方式。即先写出类型,再写出声明为该类型的东西(变量、字段、方法等)。

    Java中如下表示:

    int inc(int i) {
        return i + 1;
    }

     

    Kotlin中则是相反顺序的表示:

    fun inc(i: Int): Int {
        return i + 1
    }

     

    这让人觉得恼火,因为:

    首先,你得书写或者阅读介于名称和类型之间那个讨厌的冒号。这个多余的字母到底起什么作用?为什么要把名称和类型分隔开?我不知道。不过我知道这会加大使用Kotlin的难度。

    第二个问题。在阅读一个方法声明的时候,你最先想知道的应该是方法的名称和返回类型,然后才会去了解参数。

    在 Kotlin 中,方法的返回类型远在行末,所以可能需要滚动屏幕来阅读:

    private fun getMetricValue(kafkaTemplate : KafkaTemplate<String, ByteArray>, metricName : String) : Double {
        ...
    }

     

    另一种情况,如果参数是按分行的格式写出来的,你还得去寻找返回类型。要在下面这个方法定义中找到返回类型,你需要花多少时间?

    @Bean
    fun kafkaTemplate(
            @Value("\${interactions.kafka.bootstrap-servers-dc1}") bootstrapServersDc1: String,
            @Value("\${interactions.kafka.bootstrap-servers-dc2}") bootstrapServersDc2: String,
            cloudMetadata: CloudMetadata,
            @Value("\${interactions.kafka.batch-size}") batchSize: Int,
            @Value("\${interactions.kafka.linger-ms}") lingerMs: Int,
            metricRegistry : MetricRegistry
    ): KafkaTemplate<String, ByteArray> {
    
        val bootstrapServer = if (cloudMetadata.datacenter == "dc1") {
            bootstrapServersDc1
        }
        ...
    }

     

    关于相反顺序的第三个问题是限制了IDE的自动完成功能。在标准顺序中,因为是从类型开始,所以很容易找到类型。一旦确定了类型,IDE 就可以根据类型给出一些与之相关的变量名称作为建议。这样就可以快速输入变量名,不像这样:

    MongoExperimentsRepository repository

     

    即时在 Intellij 这么优秀的 IDE 中为 Kotlin 输入这样的变量名也十分不易。如果代码中存在很多 Repository,就很难在自动完成列表中找到匹配的那一个。换句话说,你得手工输入完整的变量名。

    repository : MongoExperimentsRepository

    伴生对象

    一个 Java 程序员来到 Kotlin 阵营。

    “嗨,Kotlin。我是新来的,有静态成员可用吗?”他问。
    “没有。我是面向对象的,而静态成员不是面向对象的,” Kotlin回答。
    “好吧,但我需要用于 MyClass 日志记录器,该怎么办?”
    “没问题,可以使用伴生对象。” 
    “伴生对象是什么鬼?”
    “它是与类绑定的一个单例对象。你可以把日志记录器放在伴生对象中,” Kotlin 如此解释。
    “明白了。是这样吗?”

    class MyClass {
        companion object {
            val logger = LoggerFactory.getLogger(MyClass::class.java)
        }
    }

     

    “对!“
    “好麻烦的语法,”这个程序看起来有些疑惑,“不过还好,现在我可以像这样——MyClass.logger——调用日志记录了吗?就像在 Java 中使用静态成员那样?”
    “嗯……是的,但是它不是静态成员!它只是一个对象。可以想像那是一个匿名内部类的单例实现。而实际上,这个类并不是匿名的,它的名字是 Companion,你可以省略这个名称。明白吗?这很简单。”

    我很喜欢对象声明的概念——单例是种很有用的模式。从从语言中去掉静态成员就不太现实了。我们在Java中已经使用了若干年的静态日志记录器,这是非常经典的模式。因为它只是一个日志记录器,所以我们并不关心它是否是纯粹的面向对象。只要它起作用,而且不会造成损害就好。

    有时候,我们必须使用静态成员。古老而友好的 public static void main() 仍然是启动 Java 应用的唯一方式。在没有Google的帮助下尝试着写出这个伴生对象。

    class AppRunner {
        companion object {
            @JvmStatic fun main(args: Array<String>) {
                SpringApplication.run(AppRunner::class.java, *args)
            }
        }
    }

    集合字面量

    在 Java 中初始化列表需要大量的模板代码:

    import java.util.Arrays;
    ...
    
    List<String> strings = Arrays.asList("Saab", "Volvo");

     

    初始化 Map 更加繁琐,所以不少人使用 Guava

    import com.google.common.collect.ImmutableMap;
    ...
    
    Map<String, String> string = ImmutableMap.of("firstName", "John", "lastName", "Doe");

     

    我们仍然在等待 Java 产生新语法来简化集合和映射表的字面表达。这样的语法在很多语言中都自然而便捷。

    JavaScript:

    const list = ['Saab', 'Volvo']
    const map = {'firstName': 'John', 'lastName' : 'Doe'}

     

    Python:

    list = ['Saab', 'Volvo']
    map = {'firstName': 'John', 'lastName': 'Doe'}

     

    Groovy:

    def list = ['Saab', 'Volvo']
    def map = ['firstName': 'John', 'lastName': 'Doe']

     

    简单来说,简洁的集合字面量语法在现代编程语言中倍受期待,尤其是初始化集合的时候。Kotlin 提供了一系列的内建函数来代替集合字面量:listOf()、mutableListOf()、mapOf()、hashMapOf(),等等。

    Kotlin:

    val list = listOf("Saab", "Volvo")
    val map = mapOf("firstName" to "John", "lastName" to "Doe")

     

    映射表中的键和值通过 to 运算符关联在一起,这很好,但是为什么不使用大家都熟悉的冒号(:)?真是令人失望!

     

     

    Maybe?不

    函数式编程语言(比如 Haskell)没有空(null)。它们提供 Maybe Monad(如果你不清楚 Monad,请阅读这篇由 Tomasz Nurkiewicz 撰写文章)。

    在很久以前,Scala 就将 Maybe 作为 Option 引入 JVM 世界,然后在 Java 8 中被采用,成为 Optional。现在 Optional 广泛应用于 API 边界,用于处理可能含空值的返回类型。

    Kotlin 中并没有与 Optional 等价的东西。看起来你应该使用 Kotlin 的可空类型封装。我们来研究一下这个问题。

    通常,在使用 Optional 时,你会先进行一系列空安全的转换,最后来处理空值。

    比如在 Java 中:

    public int parseAndInc(String number) {
        return Optional.ofNullable(number)
                       .map(Integer::parseInt)
                       .map(it -> it + 1)
                       .orElse(0);
    }

     

    在 Kotlin 中也没问题,使用 let 功能:

    fun parseAndInc(number: String?): Int {
        return number.let { Integer.parseInt(it) }
                     .let { it -> it + 1 } ?: 0
    }

     

    可以吗?是的,但并不是这么简单。上面的代码可能会出错,从 parseInt() 中抛出 NPE。只有值存在的时候才能执行 Monad 风格的 map(),否则,null 只会简单的传递下去。这就是 map() 方便的原因。然后不幸的是,Kotlin 的 let 并不是这样工作的。它只是从左往右简单地执行调用,不在乎是否是空。

    因此,要让这段代码对空安全,你必须在 let 前添加 ?:

    fun parseAndInc(number: String?): Int {
        return number?.let { Integer.parseInt(it) }
                     ?.let { it -> it + 1 } ?: 0
    }

     

    现在,比如 Java 和 Kotlin 两个版本的可读性,你更喜欢哪一个?

    展开全文
  • JavaKotlin的单例模式比较概念引入1.懒汉式1.1 线程不安全的懒汉式Java下的实现Kotlin下的实现1.1 线程安全的懒汉式Java下的实现kotlin下的实现2.饿汉式Java下的实现Kotlin下的实现3. DCLJava下的实现Kotlin下的...

    概念引入

    Java中最简单的设计模式之一,这种模式保证创建自身类的对象只有一个,可以直接访问其中方法自动创建并获得自身对象,不需要直接实例化。因此,单例模式也是创建者模式的一种。
    我感觉我的描述不够准确,但是这篇文字主要是比较Kotlin与Java单例模式的代码比较。详细概念请参考:菜鸟教程
    言归正传,我们主要从单例模式的类型开始一一比较

    1.懒汉式

    懒汉式其实分俩种,线程安全的和线程不安全的,区别就是synchronized是否存在。为什么叫懒汉式,因为首次创建时候才去创建对象,所以他是懒方法,懒加载概念就出来了,lazy loading~

    1.1 线程不安全的懒汉式

    作为最基本的实现方式之一,因为synchronized的锁关键字,所以不能在多线程下工作,线程不安全

    Java下的实现

    没必要多说了,直接看代码实现和注释。

    public class SingletonLazy1 {
        private static SingletonLazy1 instance; //单例静态变量
        private SingletonLazy1 (){} //构造私有化
    
        public static SingletonLazy1 getInstance() {
            if (instance == null) {//不存在就创建
                instance = new SingletonLazy1();
            }
            return instance;
        }
    }
    

    Kotlin下的实现

    原谅我是直接代码在android studio翻译过去的,流程入下图。
    Java转kotlin
    首先我们注意Kotlin其中几个有意思的特性。

    1. 变量会自动创建并隐藏get/set方法,这里巧妙运用了这点,在get方法中判断对象是否存在并获取。
    2. Kt中,object 关键字声明,其内部不允许声明构造方法,使用有点类似匿名内部类的使用,所以大家一般也是用object来声明单例。
    3. Object声明的类,无法创建空的构造函数,所以我们也无法private修饰
    object SingletonLazy1 {
    
        var instance //单例静态变量
                : SingletonLazy1? = null
            get() {
                if (field == null) { //不存在就创建
                    field = SingletonLazy1
                }
                return field
            }
            private set
    }
    

    暂且看一看具体到class里面的实现是什么样子的。通过编译器直接查看class字节码,Tools→Kotlin→Show Kotlin ByteCodes→新窗口中的Decompile
    1
    2
    得到字节码如下:

    public final class SingletonLazy1 {
       @Nullable
       private static SingletonLazy1 instance;
       public static final SingletonLazy1 INSTANCE;
    
       @Nullable
       public final SingletonLazy1 getInstance() {
          if (instance == null) {
             instance = INSTANCE;
          }
    
          return instance;
       }
    
       private SingletonLazy1() {
       }
    
       static {
          SingletonLazy1 var0 = new SingletonLazy1();
          INSTANCE = var0;
       }
    }
    

    我们会发现会有俩个单例变量,为什么呢?这就是由于object关键字声明类似匿名内部类,本身可以作为单例模式(饿汉模式)。如果仅仅只是实现非线程安全的单例模式,我们仅仅需要Object关键字创建类即可。
    既然说到懒汉式,我们就暂时抛开object,修改下代码,改成非线程安全的懒汉模式。代码如下,注意get()方法命名为getInstance()时候报错,我猜是隐藏了同名函数。

    class SingletonLazy1 private constructor(){
        companion object {
            private var instance: SingletonLazy1? = null
                get() {
                    if (field == null) {
                        field = SingletonLazy1()
                    }
                    return field
                }
    
            fun get(): SingletonLazy1 {//起名为getInstance报错,估计内部隐藏了同名函数
                return instance!!
            }
        }
    }
    

    比葫芦画瓢,看下字节码。删掉@Metadata等印象阅读的部分。

    public final class SingletonLazy1 {
       private static SingletonLazy1 instance;
       public static final SingletonLazy1.Companion Companion = new SingletonLazy1.Companion((DefaultConstructorMarker)null);
    
       private SingletonLazy1() {
       }
    
       // $FF: synthetic method
       public SingletonLazy1(DefaultConstructorMarker $constructor_marker) {
          this();
       }
    
       public static final class Companion {
          private final SingletonLazy1 getInstance() {
             if (SingletonLazy1.instance == null) {
                SingletonLazy1.instance = new SingletonLazy1((DefaultConstructorMarker)null);
             }
             return SingletonLazy1.instance;
          }
    
          private final void setInstance(SingletonLazy1 var1) {
             SingletonLazy1.instance = var1;
          }
          
          @NotNull
          public final SingletonLazy1 get() {
             SingletonLazy1 var10000 = ((SingletonLazy1.Companion)this).getInstance();
             if (var10000 == null) {
                Intrinsics.throwNpe();
             }
             return var10000;
          }
    
          private Companion() {
          }
          // $FF: synthetic method
          public Companion(DefaultConstructorMarker $constructor_marker) {
             this();
          }
       }
    }
    

    看到后发现果真有getInstance()的方法。这时候我们可以注意下Kotlin的companion关键字,他所修饰的object为伴生对象,伴生对象在类中只能存在一个,我们可以暂时理解为companion类似于static修饰。既然我们多写了等于getInstance()get()方法,虽然无伤大雅,但是凭着精益求精的原则,我们试着干掉他。理下思路:

    1. 既然我们的get()是多余的,我们就干掉他。
    2. 字节码中getInstance()方法的修饰为private,外界肯定调用不到,修改为public
    class SingletonLazy1 private constructor(){
        companion object {
            var instance: SingletonLazy1? = null	//Kotlin中public可以隐藏
                get() {
                    if (field == null) {
                        field = SingletonLazy1()
                    }
                    return field
                }
        }
    }
    

    如上代码所示,就是一个完整简洁的Kotlin实现。大家也可以再去查看下字节码比对一下。由于companion关键字静态修饰的绝妙,调用也很简单:SingletonLazy1.Companion.getInstance();

    1.1 线程安全的懒汉式

    对比线程不安全,仅仅就是在获取单例的public方法加了synchronized关键字锁住。

    Java下的实现

    public class Single {
        private static Single instance;单例静态变量
    
        private Single() { }
    
        public static synchronized Single getInstance() {//synchronized锁
            if (instance == null) {//不存在创建
                instance = new Single();
            }
            return instance;
        }
    }
    
    

    kotlin下的实现

    同样的转换为Kotlin仍然会转换为object,算了还是自己手写吧。其实很简单,Kotlin中有@Synchronized等同于synchronized关键字,可以用来修饰方法。也可以指定@get:Synchronized,
    俩种作用一样的,任选其一。

    class SingletonLazy1 private constructor(){
    
        companion object {
            @get:Synchronized
            var instance: SingletonLazy1? = null
                //@Synchronized
                get() {
                    if (field == null) {
                        field = SingletonLazy1()
                    }
                    return field
                }
        }
    }
    

    查看下字节码比对一下,准确无误。抬走,下一个。

    2.饿汉式

    缺点:类加载时就初始化,浪费内存。

    它通过类加载时就初始化,机制避免了多线程的同步问题(无锁,执行效率高),同样的instance 在类装载时就实例化,没有达到 lazy loading 的效果。同时,无论你用或者不用,他就是已经完成初始化了,浪费资源
    我们在1.1 线程不安全的懒汉式中已经提到object关键字和懒汉式了,这里就不在文字叙述了,注意object关键字,官方文档看下资料就可以了,直接上代码。

    Java下的实现

    public class Single2 {
        private static Single2 instance = new Single2(); 	//变量私有
        private Single2 (){} 	//构造方法私有
        public static Single2 getInstance() {
            return instance;
        }
    }
    

    Kotlin下的实现

    object Single2{
        fun test(): Unit {}
    }
    

    调用也非常简单Single2.test()

    3. DCL

    即 double-checked locking,也叫双检锁/双重校验锁俩个关键点:

    1. volatile关键字。简单说某个线程改变了其所修饰的变量,立马在内存中刷新,其他线程同步可知。
    2. synchronized 锁在其中的机制,锁的是这个类的操作。

    Java下的实现

    public class SingleDouble {
        private volatile static SingleDouble singleton;	//	volatile修饰 线程同步
    
        private SingleDouble() {}//	私有不可访问
    
        public static SingleDouble getSingleton() {
            if (singleton == null) {
                synchronized (SingleDouble.class) {// synchronized
                    if (singleton == null) {
                        singleton = new SingleDouble();
                    }
                }
            }
            return singleton;
        }
    }
    

    Kotlin下的实现

    直接转换为Kotlin,修改object为class加上私有构造器,代码如下:

    class SingleDouble private constructor(){
        // synchronized
        @Volatile
        var singleton //	volatile修饰 线程同步
                : SingleDouble? = null
            get() {
                if (field == null) {
                    synchronized(SingleDouble::class.java) {
                        if (field == null) {
                            field = SingleDouble()
                        }
                    }
                }
                return field
            }
            private set
    
    }
    

    乍眼一看,没啥问题,其实也没啥问题,但是如果这样写,就真的太low了,我们引入Kotlin中独特的懒加载,Lazy关键字。他属于代理的一种模式,用于生命周期类中延迟初始化一些对象。比如我们现在需要第一次调用时候才实例,本身就属于一个懒加载。

    class SingleDouble private constructor(){
        companion object {
            val instance: SingleDouble by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) {
                SingleDouble() }
        }
    }
    

    这种方式是网上公推的,其实我也看得迷迷糊糊的,点到LazyThreadSafetyMode.SYNCHRONIZED里面,其实说的很直白:锁用于确保只有一个线程可以初始化[Lazy]实例。这句话基本上就概括了DCL中我们所想要的,有锁,确保单个线程对实例的操作,延迟加载。

    4. 静态内部类

    主要用它跟饿汉式对比,饿汉式只要类被加载,instance就会被实例化,而这种方式加载的时候instance 不一定被初始化。只有调用 getInstance 方法时,才会显式装载 SingletonHolder 类,从而实例化 instance。

    Java下实现

    public class Single3 {
        private static class SingletonHolder {
            private static final Single3 INSTANCE = new Single3();
        }
    
        private Single3() {}
    
        public static final Single3 getInstance() {
            return SingletonHolder.INSTANCE;
        }
    }
    

    Kotlin下实现

    这个差异性就不大了,大家看代码基本就能看个七七八八了。

    class Single3 private constructor(){
    
        companion object {
            val instance = SingletonHolder.holder
        }
    
        private object SingletonHolder {
            val holder= Single3()
        }
    
    }
    

    5. 枚举

    我懒得写,懂我的人一定知道我为什么懒得写,因为个人喜好,我特别讨厌枚举,除了看着爽一点(我看着也不爽),其实对性能没有提升(甚至有一定的降低),当然这些都无关痛痒,主要原因就是我不喜欢。

    2020年5月31日23:58:25 又到了这个点,明天就是 六一儿童节,过节过节~~~

    展开全文
  • 安卓、JavaKotlin历史简介。KotlinJava比较
  • 转载自 https://github.com/MindorksOpenSource/from-java-to-kotlin 打印日志 Java System.out.print("Amit Shekhar"); System.out.println("Amit Shekhar"); Kotlin print("Amit Shekhar") println("Amit ...
  • 本文也只是简单比较kotlinjava的不同之处,实际学习kotlin还是去官网学习比较好。我个人学习的一个网站贴出来:Kotlin中文网 打印日志 Java System.out.print("Amit Shekhar"); System.out.println("Amit ...
  • 随着对 Kotlin 越来越深入的了解,我发现市面上关于 Kotlin 方面,比较深入的资料几乎是 0,所以我决定,将 Kotlin 各个方面的研究作为我的研究生课题,而性能问题往往是程序员最佳关注的内容,所以第一篇,我决定先...
  • From Java to kotlin

    2018-01-08 22:36:00
    推荐一个比较好的快速入门的kotlin总结:javakotlin差异 转载于:https://my.oschina.net/u/1041633/blog/1604236...
  • 作者丨Jakub Anio a译者丨姜雨生策划丨田晓旭随着对 Kotlin 越来越深入的了解,我发现市面上关于 Kotlin 方面,比较深入的资料几乎是 0,所以我决定,将 Kotlin 各个方面的研究作为我的研究生课题,而性能问题往往是...
  • 在安卓开发中,经常会需要进行一些限制操作,对一些事件进行监听,我们自己写起来可能会比较麻烦,Jake Wharton大神为我们写了一套更加方便的框RxBinding,在javakotlin中使用有所区别,之前都是用Java写的,现在...
  • 原文:Basic Spring web application in Java, Kotlin and Scala - comparison 作者:Radosław Skupnik 翻译:Vincent 译者注:现在可以用来开发web应用的语言五花八门,每种语言都各有千秋,本文作者挑选了...
  • 前言Kotlin作为JVM系的语言,起源于Java又不同于Java。通过在语言层面比较两者的区别,可以使得开发者能够快速学习,融会贯通。枚举使用场景使用枚举的场景非常明确,即只要一个类的对象是有限且固定的,就可以使用...
  • 您是否曾经想过用另一种语言替换Java编程语言? 好吧, Kotlin(Kotlin)是一个备受争议的选择 。 尽管编程语言能否在应用程序开发人员中克服Java尚待观察... 当您比较KotlinJava之间的功能时,对我来说很明显,Ko...
  • javaKotlin语法比较,更快的入门kotlin

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 714
精华内容 285
关键字:

java比較kotlin

java 订阅