一位Java工程师对Swift、Kotlin和Java进行了比较

我们在公司内举办了Kotlin学习会,经常会有人提出疑问,如果用Swift或Java的语法来写Kotlin代码会怎样呢?因此,我打算进行调查并实际实现来解答这个问题。
由于这些语言在语法上有所不同,所以可能不会完全一致,请大家谅解。
※我会定期更新。

验证参考转交

Kotlin:只需要一个选项,用中文进行释义

由于在公司的学习会上谈到了在Kotlin中如何实现传递引用,我进行了一些简单的验证。

在Kotlin中,如果不明确声明为可变(mutable),就无法以引用方式使用。而且,如果尝试对参数进行赋值,将会导致编译错误。

fun addArray(array: MutableList<Int>) {
    array.add(9)
    println(array) // [1, 2, 3, 9]
}

fun changeArray(array: MutableList<Int>) {
    array = mutableListOf(1, 2, 3) // 引数に代入はできない。コンパイルエラーになる。
    println(array)
}

fun main(args: Array<String>) {
    val array = mutableListOf(1, 2, 3)
    println(array) // [1, 2, 3]
    addArray(array)
    println(array) // [1, 2, 3, 9]
}

迅速

如果在Swift中使用inout声明为引用传递,似乎就可以实现。由于是引用传递,所以可以在函数内对数组变量进行修改。

func addArray(array : inout [Int])  {
    array.append(9)
    print(array)  // [1, 2, 3, 9]
}

func substituteArray(array : inout [Int])  {
    array = [100, 200, 300]
    print(array)  //  [100, 200, 300]
}

var array = [1, 2, 3]
print(array)    // [1, 2, 3]
addArray(array: &array)
print(array)    // [1, 2, 3, 9]
substituteArray(array: &array)
print(array)    // [100, 200, 300]

Java – 程序设计语言

我在Java中尝试了相同的组合,虽然可以使用数组的方法来进行更改,但是即使在参考方法内新实例化并赋值,原始变量指向的数组仍然没有改变。

import java.util.ArrayList;

class ArrayTest {
    private static void addArray(ArrayList<Integer> array) {
        array.add(9);
        System.out.println(array); // [1, 2, 3, 9]
    }

    private static void substituteArray(ArrayList<Integer> array) {
        array = new ArrayList<Integer>(); // ここで新しいArrayListを代入しても元のスコープに変更はない。
        array.add(100);
        array.add(200);
        array.add(300);
        System.out.println(array); // [100, 200, 300]
    }

    public static void main(String args[]) {
        ArrayList<Integer> array = new ArrayList<Integer>();
        array.add(1);
        array.add(2);
        array.add(3);
        System.out.println(array); // [1, 2, 3]
        addArray(array);
        System.out.println(array); // [1, 2, 3, 9]
        substituteArray(array);
        System.out.println(array); // [1, 2, 3, 9]([100, 200, 300]にはならない)
    }
}

界面

Kotlin 可以。

我本以为Kotlin接口的使用方法与Java没有太大差异,但我认为与Java不同的地方是可以对字段变量进行限制。


interface Lang {
    val name: String
    fun getHelloWorld(target: String) : String
}

class English : Lang {
    override val name = "English" // 宣言しないとコンパイルエラー
    override fun getHelloWorld(target: String) : String {
        return "Hello, $target!"
    }
}

class Japanese : Lang {
    override val name = "日本語"
    override fun getHelloWorld(target: String) : String {
        return "こんにちは、 $target!"
    }
}

fun main(args: Array<String>) {
        val Elang = English()
    println(Elang.getHelloWorld("world")) // Hello, world!
    val Jlang = Japanese()
    println(Jlang.getHelloWorld("world")) // こんにちは、 world!

}

迅速

在Swift中,可以通过协议实现类似于Kotlin接口的功能。

protocol Lang {
    var name : String {get}
    func getHelloWorld(target :String) -> String
}

class English: Lang {

    let name = "English"
    func getHelloWorld(target : String)  -> String {
        return "Hello, \(target)"
    }
}

class Japanese: Lang {

    let name = "Japanese"
    func getHelloWorld(target : String)  -> String {
        return "こんにちは, \(target)"
    }
}

let Elang = English()
print(Elang.getHelloWorld(target: "world")) // Hello, world!
let Jlang = Japanese()
print(Jlang.getHelloWorld(target: "world")) // こんにちは, world

Java – Java

因为我从来没有考虑过这种用法,所以没有注意到,但是Java在接口中定义字段后,不能强制实现类也拥有相同的字段。
(实际上,这些字段会被强制变为public static final,只能当作常量处理。)

interface Lang {
    public static final String name = ""; // インタフェースに定義したフィールドは強制的に public staic final になる。
    public String getHelloWorld(String target);
}
class English implements Lang {
    // public String name; // 宣言しなくてもOK

    @Override
    public String getHelloWorld(String target) {
        return "Hello, %TARGET%!".replace("%TARGET%", target);
    }
}
class Japanese implements Lang {

    @Override
    public String getHelloWorld(String target) {
        return "こんにちわ, %TARGET%!".replace("%TARGET%", target);
    }
}
class InterfaceTest {
    public static void main(String args[]) {
        English Elang = new English();
        System.out.println(Elang.getHelloWorld("world")); // Hello, world!
        Japanese Jlang = new Japanese();
        System.out.println(Jlang.getHelloWorld("world")); // こんにちは, world
    }
}

伴侣对象 lǚ

Kotlin
Kotlin is a programming language.

在Java和其他语言中,称为静态访问(Static)的概念,在Kotlin中可以通过Companion Object实现。

interface Lang {
    val name: String
    fun getHelloWorld(target: String) : String
}

class English : Lang {
    override val name = "English"
    override fun getHelloWorld(target: String) : String {
        return "Hello, $target!"
    }
    companion object Factory { // Companion object
        fun create(): English = English()
    }
}

fun main(args: Array<String>) {
    val Egreeter = English.create() // CreateメソッドでEnglishの実体を生成
    println(Egreeter.getHelloWorld("world"))
}

我尝试了很多方法,但是CompanionObject的操作如下所示。

    • 1クラス内に定義できるCompanionObjectは一つ

 

    • 静的アクセスなので、CompanionObject内から所属クラスのフィールド、メソッドにはアクセスできない。

 

    const を付けて定数を定義できるし、companion object内に変数を宣言することもできる。

class English : Lang {
    override val name = "English"
    override fun getHelloWorld(target: String) : String {
        return "Hello, $target!"
    }
    companion object Factory { // Factoryはあってもなくてもいいけど、javaからcompanion object内にアクセスするのに必要。
        const val COMPANION_NAME = "Companion" // 定数の定義ができる。
        val companionName = "test" // constを付けなくても静的アクセスできるフィールド変数を宣言できる。
        fun create(): English = English()
        fun getNameCom(): String {
            // return name // Companion Object 内から Englishのフィールドにはアクセスできない。
            return companionName  // Companion Object内の変数ならアクセスできる
        }
    }
}

从表面上看,它似乎建议在基本上是常量值,或者在实现类似于create方法的工厂模式时使用。

迅速

在Swift中,可以通过静态声明来实现类似的功能。
相比于记作Companion Object,更容易理解。

protocol Lang {
    var name : String {get}
    func getHelloWorld(target :String) -> String
}

class English: Lang {

    let name = "English"
    func getHelloWorld(target : String)  -> String {
        return "Hello, \(target)"
    }
    static var COMPANION_NAME = "Companion"
    static func create() -> English {
        return English()
    }
    static func getName() -> String {
        return name   // Staticな関数からはメンバ変数にはアクセスできない。
    }

}

let Egreeter = English.create()
print(Egreeter.getHelloWorld(target: "world"))
print(English.COMPANION_NAME) // 定数なのでアクセスできる

Java:

JAVA

Java可以像Swift一样进行编程。

interface Lang {
    public String getHelloWorld(String target);
}
class English implements Lang {
    public String name = "English";

    @Override
    public String getHelloWorld(String target) {
        return "Hello, %TARGET%!".replace("%TARGET%", target);
    }

    public static final String COMPANION_NAME = "Companion";

    public static English create(){
        return new English();
    }
    public static String getName() {
        return name; // staticでない変数 nameをstaticコンテキストから参照することはできません エラーが出る。
    }
}
class StaticTest {
    public static void main(String args[]) {
        English Elang = English.create();
        System.out.println(Elang.getHelloWorld("world"));
        System.out.println(English.COMPANION_NAME);
    }
}

类继承和构造函数。

Kotlin只需要一种选项。

为了调查类的继承和构造方法,我创建了一个名为England的类和它的抽象类Country。它们具有属性:国家名称、语言和人口。
此外,国家可以获取问候语和人口数量,实际处理是委托给Lang接口的实现类。
(说实话,我觉得类的设计不是很好。)

interface Lang {
    val name: String
    fun getHelloWorld(target: String) : String
    fun getPopulation(countryName: String, population : Int) : String
}

class English : Lang {
    override val name = "English"
    override fun getHelloWorld(target: String) : String {
        return "Hello, $target!"
    }
    override fun getPopulation(countryName: String, population : Int) : String {
        return "$countryName has a population of $population people."
    }
}

// 基底クラスに国名、言語、人口の属性を持たせて、必須になるようにする
abstract class Country (_name : String, _lang: Lang, _population: Int) {
    val name : String = _name
    val lang : Lang = _lang
    val population = _population
    fun getPopulation() : String {
        return lang.getPopulation(name, population)
    }
}

class England() : Country("England", English(), 53013000)

fun main(args: Array<String>) {
    val country = England()

    println(country.name)
    println(country.lang.getHelloWorld("world"))
    println(country.getPopulation())

}

迅速

我尝试使用Swift进行了重写,但是Swift没有像抽象类那样的概念,所以我觉得没有太大的必要去实现Country类。
使用协议作为类型也不被推荐(或者说不可行?),所以我还是决定不强制在父类中添加lang属性。

import Foundation

protocol Lang {
    var name : String {get}
    func getHelloWorld(target :String) -> String
    func getPopulation(countryName: String, population : Int) -> String
}

class English: Lang {

    let name = "English"
    func getHelloWorld(target : String)  -> String {
        return "Hello, \(target)"
    }

    func getPopulation(countryName: String, population : Int) -> String {
        return "\(countryName) has a population of \(population) people."
    }
}
class Country {
    var name : String = ""
    var population : Int = 0
    init(_name : String, _population : Int) {
        name = _name
        population = _population
    }
}

class England : Country {
    var lang = English()

     init() {
        super.init(_name: "England", _population: 53013000)
    }

    func getPopulation() -> String {
        return self.lang.getPopulation(countryName: name, population: population)
    }

    func getHelloWorld(target: String) -> String {
        return self.lang.getHelloWorld(target: target)
    }
}

var country = England()

print(country.name)
print(country.getHelloWorld(target: "world"))
print(country.getPopulation())

Java

基本上與Kotlin相同,但是為了符合Java的慣例,將屬性訪問轉換為getter。因此,從代碼上來看,相對於Kotlin而言,它可能會變得更長。

interface Lang {
    public String getHelloWorld(String target);
    public String getPopulation(String countryName, int population);
}
class English implements Lang {

    private String name = "English";

    public String getName() {
         return name;
    }

    @Override
    public String getHelloWorld(String target) {
        return "Hello, %TARGET%!".replace("%TARGET%", target);
    }

    @Override
    public String getPopulation(String countryName, int population) {
    return  "%COUNTRY_NAME% has a population of %POPULATION% people."
        .replace("%COUNTRY_NAME%", countryName)
        .replace("%POPULATION%", Integer.toString(population));
    }

}
public abstract class Country {
    private String name;
    private Lang lang;
    private int population;

    public Country(String _name, Lang _lang, int _population) {
        name = _name;
        lang = _lang;
        population = _population;
    }

    public String getPopulation() {
        return lang.getPopulation(name, population);
    }

    public String getName() {
        return name;
    }

    public Lang getLang() {
        return lang;
    }

}
public class England extends Country {

    public static final String NAME = "England";
    public static final int POPULATION = 53013000;

    public England() {
        super(NAME, new English(), POPULATION);
    }
}

class ConstructorTest {

    public static void main(String args[]) {
        England country = new England();

        System.out.println(country.getName());
        System.out.println(country.getLang().getHelloWorld("world"));
        System.out.println(country.getPopulation());
    }
}

空值安全

我将要写。

广告
将在 10 秒后关闭
bannerAds