以下是我的kotlin系列文章
kotlin基础知识—基本语法(一)
前言
我个人使用的工具是Android Studio
写这篇文章呢,主要是熟悉了解kotlin
kotlin教程:http://www.runoob.com/kotlin
不讲基本使用
-
查看kotlin字节码和转成java
类
- 基本使用
class A{
}
转成对应的Java代码
public final class A {
}
因此我们可以看到默认kotlin的类是final类,不可被继承,如果想要可被继承我们需要在类的前面加上open
类的属性
- 属性的定义和使用
class A {
var name: String = "test"
}
fun main() {
val a = A()
print(a.name)
}
转成Java代码
public final class A {
@NotNull
private String name = "test";
@NotNull
public final String getName() {
return this.name;
}
public final void setName(@NotNull String var1) {
Intrinsics.checkParameterIsNotNull(var1, "<set-?>");
this.name = var1;
}
}
public static final void main() {
A a = new A();
String var1 = a.getName();
boolean var2 = false;
System.out.print(var1);
}
所以a.name实际调用的是a.getName方法
- 构造器
Koltin 中的类可以有一个 主构造器,以及一个或多个次构造器,主构造器是类头部的一部分,位于类名称之后:
class Person constructor(firstName: String) {}
如果主构造器没有任何注解,也没有任何可见度修饰符,那么constructor关键字可以省略。
class Person(firstName: String) {
}
转成Java代码
public final class Person {
public Person(@NotNull String firstName) {
Intrinsics.checkParameterIsNotNull(firstName, "firstName");
super();
}
}
主构造器中不能包含任何代码,初始化代码可以放在初始化代码段中,初始化代码段使用 init 关键字作为前缀。
- 次构造函数
类也可以有二级构造函数,需要加前缀 constructor:
class Person {
constructor(parent: Person) {
parent.children.add(this)
}
}
如果类有主构造函数,每个次构造函数都要,或直接或间接通过另一个次构造函数代理主构造函数。在同一个类中代理另一个构造函数使用 this 关键字:
class Person (firstName: String,age:Int) {
constructor(firstName: String):this(firstName,0){
}
}
转成对应Java代码
public final class Person {
public Person(@NotNull String firstName, int age) {
Intrinsics.checkParameterIsNotNull(firstName, "firstName");
super();
}
public Person(@NotNull String firstName) {
Intrinsics.checkParameterIsNotNull(firstName, "firstName");
this(firstName, 0);
}
}
私有的默认构造方法
class Person private constructor(){
}
转成对应Java代码
public final class Person {
private Person() {
}
}
内部类
- 内部类使用 inner 关键字来表示。
- 内部类会带有一个对外部类的对象的引用,所以内部类可以访问外部类成员属性和成员函数。
class Person {
private val age = "23"
inner class B {
var b = age
}
}
转成对应Java代码
public final class Person {
private final String age = "23";
public final class B {
@NotNull
private String b;
@NotNull
public final String getB() {
return this.b;
}
public final void setB(@NotNull String var1) {
Intrinsics.checkParameterIsNotNull(var1, "<set-?>");
this.b = var1;
}
public B() {
this.b = Person.this.age;
}
}
}
第二种获取外部类属性
class Person {
private val age = "23"
inner class B {
fun test(){
var a = this@Person
var b=a.age
}
}
}
转成对应Java代码
public final class Person {
private final String age = "23";
public final class B {
public final void test() {
Person a = Person.this;
String b = a.age;
}
}
}
两种方式主要区别在于一个是B的函数的内部属性,一个是外部属性
- 匿名内部类
class Test {
var v = "成员属性"
fun setInterFace(test: TestInterFace) {
test.test()
}
}
/**
* 定义接口
*/
interface TestInterFace {
fun test()
}
转成Java代码
public interface TestInterFace {
void test();
}
public final class Test {
@NotNull
private String v = "成员属性";
@NotNull
public final String getV() {
return this.v;
}
public final void setV(@NotNull String var1) {
Intrinsics.checkParameterIsNotNull(var1, "<set-?>");
this.v = var1;
}
public final void setInterFace(@NotNull TestInterFace test) {
Intrinsics.checkParameterIsNotNull(test, "test");
test.test();
}
}
kotlin继承
构造函数
- 子类有主构造函数
如果子类有主构造函数, 则基类必须在主构造函数中立即初始化。
open class Person(var name : String, var age : Int){// 基类
}
class Student(name : String, age : Int, var no : String, var score : Int) : Person(name, age) {
}
转成对应Java代码
public class Person {
@NotNull
private String name;
private int age;
//set和get方法省略
public Person(@NotNull String name, int age) {
Intrinsics.checkParameterIsNotNull(name, "name");
super();
this.name = name;
this.age = age;
}
}
public final class Student extends Person {
@NotNull
private String no;
private int score;
//set和get方法省略
public Student(@NotNull String name, int age, @NotNull String no, int score) {
Intrinsics.checkParameterIsNotNull(name, "name");
Intrinsics.checkParameterIsNotNull(no, "no");
super(name, age);
this.no = no;
this.score = score;
}
}
- 子类没有主构造函数
如果子类没有主构造函数,则必须在每一个二级构造函数中用 super 关键字初始化基类,或者在代理另一个构造函数。初始化基类时,可以调用基类的不同构造方法。
open class Person(context: Context, attrs: AttributeSet?) {
// 基类
constructor(context: Context) : this(context, null) {
}
}
class Student : Person {
constructor(ctx: Context) : super(ctx) {
}
constructor(ctx: Context, attrs: AttributeSet) : super(ctx, attrs) {
}
}
扩展
- 扩展函数
扩展函数可以在已有类中添加新的方法,对被扩展的类代码本身不会造成任何影响
fun MutableList<Int>.swap(index1: Int, index2: Int) {
val tmp = this[index1] // this 对应该列表
this[index1] = this[index2]
this[index2] = tmp
}
转成对应Java代码
public static final void swap(@NotNull List list, int index1, int index2) {
Intrinsics.checkParameterIsNotNull(list, "$this$swap");
int tmp = ((Number)list.get(index1)).intValue();
list.set(index1, list.get(index2));
list.set(index2, tmp);
}
- 扩展一个空对象
fun Any?.toString(): String {
if (this == null) return "null"
// 空检测之后,“this”会自动转换为非空类型,所以下面的 toString()
// 解析为 Any 类的成员函数
return toString()
}
转成对应的Java代码
public static final String toString(@Nullable Object $this$toString) {
return $this$toString == null ? "null" : $this$toString.toString();
}
伴生对象的扩展
如果一个类定义有一个伴生对象 ,你也可以为伴生对象定义扩展函数和属性。
伴生对象通过"类名."形式调用伴生对象,伴生对象声明的扩展函数,通过用类名限定符来调用:
- 伴生对象
Kotlin 中是没有静态方法的,解决的办法有两种,一种方法就是使用 @JvmStatic 注解去注释它,第二种方法就是使用伴生对象的方式创建
class MyClass {
companion object {
val age=30
} // 将被称为 "Companion"
}
val MyClass.Companion.no: Int
get() = 10
fun main() {
println("no:${MyClass.no}")
}
转成Java代码
public final class MyClass {
private static final int age = 30;
public static final MyClass.Companion Companion = new MyClass.Companion((DefaultConstructorMarker)null);
public static final class Companion {
public final int getAge() {
return MyClass.age;
}
private Companion() {
}
// $FF: synthetic method
public Companion(DefaultConstructorMarker $constructor_marker) {
this();
}
}
}
// KotlinKt.java
package com.peakmain.leetcode;
public final class KotlinKt {
public static final int getNo(@NotNull MyClass.Companion $this$no) {
Intrinsics.checkParameterIsNotNull($this$no, "$this$no");
return 10;
}
public static final void main() {
String var0 = "no:" + getNo(MyClass.Companion);
boolean var1 = false;
System.out.println(var0);
}
// $FF: synthetic method
public static void main(String[] var0) {
main();
}
}
数据类与密闭类
- 数据类
Kotlin 可以创建一个只包含数据的类,关键字为 data:
data class User(val name: String, val age: Int)
转成Java代码
public final class User {
@NotNull
private final String name;
private final int age;
@NotNull
public final String getName() {
return this.name;
}
public final int getAge() {
return this.age;
}
public User(@NotNull String name, int age) {
Intrinsics.checkParameterIsNotNull(name, "name");
super();
this.name = name;
this.age = age;
}
@NotNull
public final String component1() {
return this.name;
}
public final int component2() {
return this.age;
}
@NotNull
public final User copy(@NotNull String name, int age) {
Intrinsics.checkParameterIsNotNull(name, "name");
return new User(name, age);
}
@NotNull
public String toString() {
return "User(name=" + this.name + ", age=" + this.age + ")";
}
public int hashCode() {
String var10000 = this.name;
return (var10000 != null ? var10000.hashCode() : 0) * 31 + this.age;
}
public boolean equals(@Nullable Object var1) {
if (this != var1) {
if (var1 instanceof User) {
User var2 = (User)var1;
if (Intrinsics.areEqual(this.name, var2.name) && this.age == var2.age) {
return true;
}
}
return false;
} else {
return true;
}
}
}
我们会发现kotlin默认会帮我们生成hashCode和equalus,而且这个类是final,也就是说这个类是不可被继承 (但是可以实现接口)的,copy实际上就是new一个新的实体类,每一个属性都会有一个component。
密闭类
- 密封类用来表示受限的类继承结构:当一个值为有限几种的类型, 而不能有任何其他类型时。在某种意义上,他们是枚举类的扩展:枚举类型的值集合 也是受限的,但每个枚举常量只存在一个实例,而密封类 的一个子类可以有可包含状态的多个实例。
- 声明一个密封类,使用 sealed 修饰类,密封类可以有子类,但是所有的子类都必须要内嵌在密封类中。
sealed 不能修饰 interface ,abstract class(会报 warning,但是不会出现编译错误)
sealed class Expr{
open class A: Expr() {
}
class B:Expr(){
}
}
fun exec(expr: Expr)=when(expr){
is Expr.A->{
}
is Expr.B->{
}
}
转成对应Java代码
public abstract class Expr {
private Expr() {
}
// $FF: synthetic method
public Expr(DefaultConstructorMarker $constructor_marker) {
this();
}
public static class A extends Expr {
public A() {
super((DefaultConstructorMarker)null);
}
}
public static final class B extends Expr {
public B() {
super((DefaultConstructorMarker)null);
}
}
}
我们可以从转后的Java可以看到,外部类是无法去继承Expr的,因为构造方法是私有的,但是可以继承A,因为B是final所以也是不可以被继承的