前言
本文主要讲解类型,主要包括类和接口、扩展方法、空类型安全、智能类型转换、案例:使用Retrofit发送网络请求
Kotlin文章列表
Kotlin文章列表: 点击此处跳转查看
目录
(一)类和接口
(1)kotlin与java类定义,使用(实例化)
java:
public class SimpleClass {
public int x;
public SimpleClass(int x) {
this.x = x;
}
}
使用:
SimpleClass simpleClass = new SimpleClass(9);
System.out.println(simpleClass.x);
kotlin:
class SimpleClass(var x: Int, val y: String) {
}
使用:
val simpleClass = SimpleClass(9, "Hello")
println(simpleClass.x)
(2)kotlin与java接口的定义,实现
java:
public interface SimpleInf {
void simpleMethod();
}
实现:
public class SimpleClass implements SimpleInf {
@Override
public void simpleMethod() {
}
}
kotlin:
interface SimpleInf {
val simpleProperty: Int // 定义一个变量
fun simpleMethod()
}
实现:
class SimpleClass(var x: Int, val y: String) : SimpleInf {
override val simpleProperty: Int
get() {
return 2 // 每次调用都会返回2
}
override fun simpleMethod() {
}
}
调用:
fun main() {
val simpleClass = SimpleClass(9, "Hello")
println(simpleClass.simpleProperty) // 输出的就是2
}
(3)kotlin与java抽象类的定义,实现
java:
public abstract class AbsClass {
public abstract void absMethod();
protected void overridable(){ }
public final void nonOverridable(){ }
}
使用:
public class SimpleClass extends AbsClass {
public int x;
public SimpleClass(int x) {
this.x = x;
}
@Override
public void absMethod() {
}
}
kotlin:
abstract class AbsClass {
abstract fun absMethod()
open fun overridable(){}
fun nonOverridable(){}
}
使用:
class SimpleClass(var x: Int, val y: String) : AbsClass() {
override fun absMethod() {}
final override fun overridable() {
}
}
补充:
SimpleClass加上open后,SimpleClass2也能继承SimpleClass
overridable()前面加上了final,SimpleClass2就不能重写overridable()
open class SimpleClass(var x: Int, val y: String) : AbsClass() {
override fun absMethod() {}
final override fun overridable() {
}
}
class SimpleClass2(x: Int, y: String): SimpleClass(x, y) {
}
(4)kotlin与java属性的定义,使用
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) {
System.out.println("setAge: " + 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
get() {
return field
}
set(value) {
println("setAge: $value")
field = value
}
var name: String = name
get() {
return field // backing field
}
set(value) {
}
}
fun main() {
val ageRef = Person::age
val person = Person(18, "Bennyhuo")
val nameRef = person::name
ageRef.set(person, 20) // ageRef未绑定Receiver
nameRef.set("Andyhuo")// nameRef绑定Receiver
}
(二)扩展方法
扩展函数可以在已有类中添加新的方法,不会对原类做修改,扩展函数定义形式:
fun receiverType.functionName(params) {
body
}
receiverType:表示函数的接收者,也就是函数扩展的对象
functionName:扩展函数的名称
params:扩展函数的参数,可以为NULL
fun String.padding(count: Int, char: Char = ' '): String {
val padding = (1..count).joinToString("") { char.toString() }
return "${padding}${this}${padding}"
}
fun String.isEmail(): Boolean {
return matches(Regex("(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|\"(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x21\\x23-\\x5b\\x5d-\\x7f]|\\\\[\\x01-\\x09\\x0b\\x0c\\x0e-\\x7f])*\")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-z0-9-]*[a-z0-9]:(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x21-\\x5a\\x53-\\x7f]|\\\\[\\x01-\\x09\\x0b\\x0c\\x0e-\\x7f])+)\\])"))
}
fun String.times(count: Int): String {
return (1..count).joinToString("") { this }
}
fun main() {
"admin@bennyhuo.com".isEmail()
println("Hello".padding(1))
println("*".times(10))
// 获取扩展方法的引用
val stringTimes = String::times
val stringTimesBound = "*"::times
}
(三)空类型安全
(1)空类型安全的概念
kotlin中,一个常规的String类型变量是不可以设置为 null的
var a: String = "abc"
a = null // Error: Null can not be a value of a non-null type String
为了允许为null,我们可以将变量声明为可空String类型,写作:String?
var b:String? = "abc"
b = null // that's OK
对于Kotlin的其它类型而言,也是只需要在类型后面加上?,即可表示为该类型可空。(尽量不使用,除非必须)
现在我们看一下空引用的属性和方法,很显然,这是不安全,编译器会报错:
var nullObj:String? = null
length = nullObj.length // error: 因为 nullObj 是一个null
补充:? ?. ?:的区别
?为可空操作符,声明可空类型,避免抛出NPE,例如var b:String? = “abc” b就可以为空
?.为安全调用操作符,为空返回null,避免抛出NPE,例如nullable?.length,如果为空,返回null,不为空,则返回nullable.length的值
?:为Elvis操作符, val t = b?.length ?: -1,如果 ?: 左侧表达式(b?.length)非空,elvis 操作符就返回其左侧表达式,否则返回右侧表达式(-1)
(2)强转为不可空类型
!!的使用
var nullable: String? = "Hello"
val length = nullable!!.length
(3)安全调用(?.)
我们可以通过使用安全调用操作符(?.)来实现
var nullable: String? ="Hello"
nullable = null
val length: Int = nullable ?. length ?: 0
nullable == null, length =0
nullable != null, length = nullable!!.length
(四)智能类型转换
(1)智能类型转换案例
public class Person implements Kotliner {
public final String name;
public final int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
}
java:
public class JavaCasts {
public static void main(String... args) {
Kotliner kotliner = new Person("benny", 20);
if (kotliner instanceof Person) {
System.out.println(((Person) kotliner).name);
}
}
}
kotlin:
val kotliner: Kotliner = Person("benny",20)
if (kotliner is Person) {
println(kotliner.name) // 自动转换为person
}
(2)智能类型转换的作用范围
var value: String? = null // value: String?
value ="benny
if (value = null) { // 通过智能转换把value从String?类型转换为String类型
println(value.length)// value: String
}
// value: String?
(3)不支持智能转换的情况
var tag: String? = null
fun main() {
if (tag != null) { // 虽然判断不为空,但其他线程可能对它做修改
println(tag.length)
}
}
(4)类型的安全转换
val kotliner: Kotliner = Person("benny",20)
if (kotliner is Person) {
println((kotliner as? Person)?.name) // 自动转换为person
}
as? 安全转换,失败返回null
(5)编码建议
尽可能使用val来声明不可变引用,让程序的含义更加清晰确定
尽可能减少函数对外部变量的访问,也为函数式编程提供基础
必要时创建局部变量指向外部变量,避免因它变化引起程序错误
(五)案例:使用Retrofit发送网络请求
(1)添加依赖
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"
(2)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
)
}
(3)kotlin
import com.google.gson.GsonBuilder
import retrofit2.Call
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import retrofit2.http.GET
import retrofit2.http.Path
import java.io.File
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)
File("Kotlin.html").writeText(
"""
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>${repository.owner.login} - ${repository.name}</title>
</head>
<body>
<h1><a href='${repository.html_url}'>${repository.owner.login} - ${repository.name}</a></h1>
<p>${repository.description}</p>
<p>Stars: ${repository.stargazers_count}</p>
<p>Forks: ${repository.forks_count}</p>
</body>
</html>
""".trimIndent()
)
}
}
(4)java
import retrofit2.Response;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
public class GitHuber {
public static void main(String... args) throws IOException {
GitHubApi gitHubApi = new Retrofit.Builder().baseUrl("https://api.github.com")
.addConverterFactory(GsonConverterFactory.create())
.build().create(GitHubApi.class);
Response<Repository> response = gitHubApi.getRepository("JetBrains", "Kotlin").execute();
Repository repository = response.body();
if (repository == null) {
System.out.println("Error! " + response.code() + " " + response.message());
} else {
System.out.println(repository.getName());
System.out.println(repository.getOwner().getLogin());
System.out.println(repository.getStargazers_count());
System.out.println(repository.getForks_count());
System.out.println(repository.getHtml_url());
File htmlFile = new File("Kotlin.html");
BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(htmlFile));
bufferedWriter.write("<!DOCTYPE html>\n" +
"<html lang=\"en\">\n" +
"<head>\n" +
" <meta charset=\"UTF-8\">\n" +
" <title>" + repository.getOwner().getLogin() + " - " + repository.getName() + "</title>\n" +
"</head>\n" +
"<body>\n" +
"<h1><a href='" + repository.getHtml_url() + "'>" + repository.getOwner().getLogin() + " - " + repository.getName() + "</a></h1>\n" +
"<p>" + repository.getDescription() + "</p>\n" +
"<p>Stars: " + repository.getStargazers_count() + "</p>\n" +
"<p>Forks: " + repository.getForks_count() + "</p>\n" +
"</body>\n" +
"</html>");
bufferedWriter.close();
}
}
}
注意:
不要忘记加网络权限