【Kotlin】自学(三)-类型初步

274 阅读6分钟

类和接口

类的定义

Java

	public class SimpleClass {
}

Kotlin

	class SimpleClass

kotlin中默认是public的,并且如果没有内容{}也是可以省略的

接下来我们看下在类中定义成员 Java

	public class SimpleClass {
    public int x;
    
    public void y(){

    }
}

Kotlin

	class SimpleClass {
    
    var x: Int = 0
    fun y() {}
}

Java中,成员变量是有默认值的,但是在Kotlin中,我们必须要给它初始化设置个默认值

接下来我们看下怎么定义构造方法 Java

	public class SimpleClass{
    public int x;

    public SimpleClass(int x) {
        this.x = x;
    }

    public void y(){

    }
}

Kotlin 第一种:

	class SimpleClass {

    var x: Int

    constructor(x: Int) {
        this.x = x
    }

    fun y() {}
}

Java写法很像,使用constructor修饰,它还可以简化下

	class SimpleClass constructor(x: Int) {

    var x: Int = x


    fun y() {}
}

就是把构造方法挪到类定义那里,kotlin里面有主构造区和副构造器一说,这么定义就是主构造器,上面那种使用constructor定义的就是副构造区,主构造器要求所有的其他构造器都调用它,上面那种写法还可以再简单点,直接把constructor省略

	class SimpleClass(x: Int) {

    var x: Int = x


    fun y() {}
}

既然我们想定义成员属性我们构造器中的一样,我们还可以简化下

	class SimpleClass(var x: Int) {
    

    fun y() {}
}

这就相当于我们在类里面定义了一个x,它等于我们构造器中的x 那怎么实例化类呢? Java

	SimpleClass simpleClass = new SimpleClass(9);
    System.out.println(simpleClass.x);
    simpleClass.y();

Kotlin

	val simpleClass = SimpleClass(9)
    println(simpleClass.x)
    simpleClass.y()

Kotlin中不需要new这个关键字了

接口

接口的定义 Java

	public interface SimpleInf {
    void simpleMethod();
}

Kotlin

	interface SimpleInf {

    fun simpleMethod()
}

接口实现 Java

	public class SimpleClass
        implements SimpleInf {

    @Override
    public void simpleMethod() {

    }

}

Kotlin

	class SimpleClass : SimpleInf {

    override fun simpleMethod() {}

}

Kotlin中使用:代替implements关键字,同时必须使用override修饰要实现的方法

抽象类定义 Java

	public abstract class AbsClass {
    public abstract void absMethod();
    protected void overridable(){ }
    public final void nonOverridable(){ }
}

Kotlin

	abstract class AbsClass {
    abstract fun absMethod()
    open fun overridable(){}
    fun nonOverridable(){}
}

这里要注意:在Java中,我们在抽象类中定义普通方法,子类是可以选择性的进行实现,但是在Kotlin中,如果在抽象类中定义的普通方法前面没有加上open修饰,那么子类就不能进行实现这个方法!

抽象类的实现 Java

	public class SimpleClass
        extends AbsClass
        implements SimpleInf {

    @Override
    public void simpleMethod() {

    }

    @Override
    public void absMethod() {

    }
}

Kotlin

	class SimpleClass
    : AbsClass(), SimpleInf {

    override fun absMethod() {}
    override fun simpleMethod() {}
    fun y() {}
}

Kotlin中一样使用:代替extends,同时要实现的抽象方法必须使用override修饰 这里我们就需要注意上面说的,没有用open修饰的方法是不能实现的 在这里插入图片描述 同样的还有类的继承,比如我们想继承这个SimpleClass,如果它前面不用open修饰,我们是不能继承的 在这里插入图片描述 我们假如在接口里面定义一个属性

	interface SimpleInf {
    val simpleProperty: Int // property

    fun simpleMethod()
}

我们子类实现这个接口后就需要对这个属性提供一个getter方法

	 override val simpleProperty: Int
        get() {
            return 2
        }

Kotlin中,属性就相当于一个值加上对应的get/set方法 我们在举例说明下,假设有一个Person类,有agename两个属性 java

	public class Person {
    private int age; //field
    private String name;

    public Person(int age, String name) {
        this.age = age;
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

Kotlin

	class Person(age: Int, name: String) {
    var age: Int = age //property
    
    var name: String = name
    
}

我们发现没有get/set方法了,我们也可以把它们暴露出来

	class Person(age: Int, name: String) {
    var age: Int = age //property
        get() {
            return field
        }
        set(value) {
            field = value
        }
    var name: String = name
        get() {
            return field // backing field
        }
        set(value) {
            field = value
        }
}

扩展方法

我们在使用某个类的时候经常会想要是这个类有xxx方法就好了对吧!在Java中我们一般是直接新建几个工具类来扩展某个类的方法,在Kotlin中不需要,我们可以直接对某个类进行扩展方法和属性

	class PoorGuy{
    var pocket: Double = 0.0
}

我们想在PoorGuy类中定义一个方法,我们可以直接这么 定义

	fun PoorGuy.noMoney(){

}

使用起来跟普通方法一样

	fun main() {

    var guy = PoorGuy()
    guy.noMoney()
    
}

定义属性和定义方法差不多

	var PoorGuy.moneyLeft: Double
    	get() {
        	return this.pocket
    	}
    	set(value) {
        	pocket = value
    	}

空类型安全

这个在Java中是没有的,我们在Java中声明一个String类型的变量,我们是可以给他赋值为null

	
    public static void main(String[] args) {
        String x = "Hello";
        x = null;
    }

但是在Kotlin中是不允许的,编译器会报错 在这里插入图片描述 那我们既然要兼容Java,想接受一个null怎么办呢?我们可以在类型后面加个?

	var nullable: String? = "Hello"
    nullable=null

如果我们想使用这个变量,我们就需要机型强转,要不然会报错 在这里插入图片描述 怎么强转呢?加!!即可

	var nullable: String? = "Hello"
    val length = nullable!!.length

这种方法比较暴力,我们一开始就知道它不为空,如果我们不知道它知否为空的话我们就需要下面那样

	val length = nullable?.length ?: 0

接下来我们看下空类型继承关系

	var x: String = "Hello"
    var y: String? = "World"

//    x = y // Type mismatch
    y = x // OK

这里也就是说StringString?的子类

智能类型转换

假设有两个类PersonKotliner,PersonKotliner子类,Person中有一个属性name

Java

	 	 Kotliner kotliner = new Person("xiaoming", 20);
        if(kotliner instanceof Person){
            System.out.println(((Person) kotliner).name);
        }

上面是Java代码,我们已经通过instanceof判断了kotliner的类型,使用的时候我们依旧还需要强转下 Kotlin

  	val kotliner: Kotliner = Person("benny", 20)
    if(kotliner is Person){
        println(kotliner.name)
    }

不支持智能转换情况

	var tag: String? = null

	fun main() {

    	if(tag != null){
        	println(tag.length)
    	}
  }

因为我们在调用println(tag.length)的时候,有可能别的线程改变了tag的值

使用Retrofit发起网络请求

首先添加相关依赖

 	implementation "com.squareup.retrofit2:retrofit:2.6.2"
    implementation "com.squareup.retrofit2:converter-gson:2.6.2"
    implementation "com.google.code.gson:gson:2.8.1"

我们请求的地址就是https://api.github.com/repos/JetBrains/Kotlin 它的返回值,这里就不截全了,我们只是演示怎么使用 在这里插入图片描述 接下来就开始写具体代码了(Retrofit基本使用可以百度下) 首先我们要先创建一个Repository

	data class Repository(
    var id: Int,
    var node_id: String,
    var name: String,
    var full_name: String,
    var private: Boolean,
    var owner: Owner,
    var html_url: String,
    var description: String,
    var fork: Boolean,
    var url: String,
    var forks_url: String,
    var keys_url: String,
    var collaborators_url: String,
    var teams_url: String,
    var hooks_url: String,
    var issue_events_url: String,
    var events_url: String,
    var assignees_url: String,
    var branches_url: String,
    var tags_url: String,
    var blobs_url: String,
    var git_tags_url: String,
    var git_refs_url: String,
    var trees_url: String,
    var statuses_url: String,
    var languages_url: String,
    var stargazers_url: String,
    var contributors_url: String,
    var subscribers_url: String,
    var subscription_url: String,
    var commits_url: String,
    var git_commits_url: String,
    var comments_url: String,
    var issue_comment_url: String,
    var contents_url: String,
    var compare_url: String,
    var merges_url: String,
    var archive_url: String,
    var downloads_url: String,
    var issues_url: String,
    var pulls_url: String,
    var milestones_url: String,
    var notifications_url: String,
    var labels_url: String,
    var releases_url: String,
    var deployments_url: String,
    var created_at: String,
    var updated_at: String,
    var pushed_at: String,
    var git_url: String,
    var ssh_url: String,
    var clone_url: String,
    var svn_url: String,
    var homepage: String,
    var size: Int,
    var stargazers_count: Int,
    var watchers_count: Int,
    var language: String,
    var has_issues: Boolean,
    var has_projects: Boolean,
    var has_downloads: Boolean,
    var has_wiki: Boolean,
    var has_pages: Boolean,
    var forks_count: Int,
    var mirror_url: Any,
    var archived: Boolean,
    var disabled: Boolean,
    var open_issues_count: Int,
    var license: Any,
    var forks: Int,
    var open_issues: Int,
    var watchers: Int,
    var default_branch: String,
    var organization: Organization,
    var network_count: Int,
    var subscribers_count: Int
) {
    data class Owner(
        var login: String,
        var id: Int,
        var node_id: String,
        var avatar_url: String,
        var gravatar_id: String,
        var url: String,
        var html_url: String,
        var followers_url: String,
        var following_url: String,
        var gists_url: String,
        var starred_url: String,
        var subscriptions_url: String,
        var organizations_url: String,
        var repos_url: String,
        var events_url: String,
        var received_events_url: String,
        var type: String,
        var site_admin: Boolean
    )

    data class Organization(
        var login: String,
        var id: Int,
        var node_id: String,
        var avatar_url: String,
        var gravatar_id: String,
        var url: String,
        var html_url: String,
        var followers_url: String,
        var following_url: String,
        var gists_url: String,
        var starred_url: String,
        var subscriptions_url: String,
        var organizations_url: String,
        var repos_url: String,
        var events_url: String,
        var received_events_url: String,
        var type: String,
        var site_admin: Boolean
    )
}

这里我们在class前面加上了一个data修饰符,这个后面我们会讲解,表示这个类是数据类 然后我们就要写一个接口类

	interface GitHubApi {
    @GET("/repos/{owner}/{repo}")
    fun getRepository(@Path("owner") owner: String, @Path("repo") repo: String): Call<Repository>
}

然后就是具体的调用了

fun main() {
    val gitHubApi = Retrofit.Builder().baseUrl("https://api.github.com")
        .addConverterFactory(GsonConverterFactory.create())
        .build()
        .create(GitHubApi::class.java)

    val response = gitHubApi.getRepository("JetBrains", "Kotlin").execute()

    val repository = response.body()

    if(repository == null){
        println("Error! ${response.code()} - ${response.message()}")
    } else {
        println(repository.name)
        println(repository.owner.login)
        println(repository.stargazers_count)
        println(repository.forks_count)
        println(repository.html_url)
     
    }
}

使用起来跟Java差不多,相对来说就是简单了一些