最近在学习kotlin,随便总结一下知识点。有兴趣的同学可以好好看看哦,每一段都有代码示例!!!
一、基础知识
1、声明变量
fun main(){
//变量
var a:Int = 1;
//常量
val b:Int = 2;
}
这里a、b表示变量的名字,冒号后面表示变量的类型。用val表示常量。
fun main(){
//不可为空的类型
var str1:String = "aaa";
//可以为空的类型
var str2:String? = null;
str1 = str2
str2 = str1
}
用?表示这个变量可以为null,如果不加表示不可为空,编译会报错。str1 = str2这个是无法通过编译的。
2、函数相关
fun printLen(str:String):String{
printLn("$str")
return str;
}
Kotlin中的函数可以不放在类里面,单独提出来。实际上编译后的字节码文件依然是放在一个类里面。printLn("$str")这个$符号,表示这个变量可以放在字符串里,我们就减少了字符串的拼接。
3、与java中的不同
(1)内部类
class Main{
object Test {
fun sayMessage(msg: String) {
println(msg)
}
}
fun main(){
println(Test.sayMessage("aaa"))
}
}
Test是一个匿名内部类,在java中,匿名内部类会被单独编译成一个class文件,在外部类的内部有一个单例的对象。
java:
Test.INSTANCE.sayMessage("aaa")
kotlin:
Test.sayMessage("aaa")
这其实也是kotlin创造单例对象的方法。
(2)字节码对象
class Main{
object Test {
fun sayMessage(msg: String) {
println(msg)
}
}
fun main(){
getName(JavaBean::class.java)
getName(KotlinBean::class)
}
fun getName(clazz:Class<JavaBean>){
println(clazz.simpleName)
}
fun getName(clazz:KClass<KotlinBean>){
println(clazz.simpleName)
}
}
public class JavaBean {
}
class KotlinBean
在kotlin中获得java的字节码xx::class.java,对于kotlin本身的对象类型是KClass传入的是xx::class。
(3)解决关键字冲突
public class JavaBean {
public static int in = 1;
}
class Main{
fun main(){
println(JavaBean.`in`)
}
}
in 在java中声明为了变量,但是在Kotlin中确是关键字,所以呢,要用``来处理。同时``可以将不合法字符变成合法的,比如:fun `123`{}。
4、kotlin与java互调产生的问题
kotlin 没有封装类,调用java方法,只会执行基本数据类型方法
public interface TestInterface {
void putNum(int num);
void putNum(Integer num);
}
public class Impl implements TestInterface{
public static TestInterface test = new Impl();
@Override
public void putNum(int num) {
System.out.println("int");
}
@Override
public void putNum(Integer num) {
System.out.println("Integer");
}
}
fun main() {
Impl.test.putNum(123);
}
打印输出的是int。这就是由于kotlin中没有Integer,所以把两个方法并为一个方法了,如果kotlin中实现接口,那么只需要重写一个方法就可以了。
kotlin 类型空值敏感
当kotlin调用java方法的时候,课程会返回一个null,如果我们不处理程序会有安全问题。
public class Temp {
public static String format(String str){
return str.isEmpty() ? null : str;
}
}
fun main() {
function("")
}
fun function(str:String){
val fmt1 = Temp.format(str);
println(fmt1)
val fmt2:String = Temp.format(str);
val fmt3:String? = Temp.format(str);
println(fmt3?.length)
}
fmt2会直接在运行的时候报错,因为format方法返回的就是null值,fmt1是null。fmt3才是安全的所以要用?设置成可控类型的,这样才是安全的。
kotlin 中没有静态变量和静态方法
在java中调用kotlin方法
class StaticDemo{
object Test{
fun sayMessage(msg:String){
println(msg)
}
}
}
public class Main1 {
public static void main(String[] args) {
StaticDemo.Test.INSTANCE.sayMessage("aaa");
}
}
那我们能不能在java中像调用静态方法一样方便呢?就是把INSTANCE去掉?答案是可以的
class StaticDemo{
object Test{
@JvmStatic
fun sayMessage(msg:String){
println(msg)
}
}
}
public class Main1 {
public static void main(String[] args) {
StaticDemo.Test.sayMessage("aaa");
}
}
5、判断相等
kotlin java
a == b a.equals(b)
a === b a == b
二、函数和Lambda闭包
1、函数的特性语法
//标准写法
fun echo(name:String){
println("name:$name")
}
//携带默认参数
fun echo(name:String = "xiaoming"){
println("name:$name")
}
//简易写法,函数中只有一个语句可以搞
fun echo(name:String) = println("name:$name")
默认参数,在java中调用也需要传参数,在kotlin中不用
2、嵌套函数
fun main() {
function()
}
fun function(){
var str ="hello world"
fun say(count:Int = 10){
println(str)
if(count > 0){
say(count - 1)
}
}
say()
}
用途:(1)在某些条件下,触发递归函数(2)不希望被外部函数访问的函数
!!!不推荐使用
3、扩展函数
class Main{
}
fun Main.aaa() = print("aaa")
fun main() {
Main().aaa();
}
对一个类的方法进行扩展,类名+ . +方法名。在编译的时候会编译到类里面。
扩展函数是静态的,不具备运行时的多态!
一般应用于第三方的sdk或者系统类。
4、Lambda闭包语法
lambda:
//java8中
public static void main(String[] args) {
Thread thread = new Thread(() -> System.out.println("aaa"));
}
//kotlin中
fun main() {
var thread = Thread({ -> println("aaaa")})
thread.start()
}
如果lambda是没有参数的可以更加简化一点:
var thread1 = Thread({ })
var thread2 = Thread(){}
var thread3 = Thread{}
闭包语法:
//lambda闭包
var print = {
name:String -> println("name:$name")
}
fun main() {
print("aaa")
}
最多传入22个参数
5、高阶函数
将函数作为参数传递给另一个函数...。
fun onlyIf(isDebug:Boolean,block:() -> Unit){
if(isDebug) block();
}
fun main() {
onlyIf(true){
println("打印日志")
}
}
fun onlyIf(isDebug:Boolean,block:() -> Unit){
if(isDebug) block();
}
fun main() {
val runnable:Runnable = Runnable {
print("runnable::run")
}
var funn:() -> Unit
funn = runnable::run
onlyIf(true,funn)
}
这里面首先创建了一个对象Runnable。然后有一个lambda函数声明,利用::将对象中方法拿出来,赋值给funn,然后再调用。
6、内联函数
inline fun onlyIf(isDebug:Boolean,block:() -> Unit){
if(isDebug) block();
}
fun main() {
val runnable:Runnable = Runnable {
print("runnable::run")
}
var funn:() -> Unit
funn = runnable::run
onlyIf(true,funn)
}
kotlin的Lambda是一个匿名对象。可以使用inline修饰方法,在编译的时候会拆解方法的调用为语句调用,进而减少创建不必要的对象。
三、类和对象
1、构造函数
open class Father{
}
class Son:Father(){
}
kotlin类中默认有public final修饰符,默认不允许继承,如果想要继承,必须要用open修饰。继承用:,可以继承一个父类或者多个接口。
open class Father(var num:Int){
init {
print("father")
}
open fun printClass():Unit{
println("printClass")
}
}
open interface FatherInterface{
fun printInterface()
}
class Son(var a:Int):Father(a),FatherInterface{
override fun printInterface() {
}
override fun printClass(){
}
}
这里面类名后面的()就是构造函数。如果想要在构造函数中执行某些逻辑就写在init方法。override表示重写方法。
多级构造函数
class Test(str:String){
var str:String = str;
var num:Int = 0;
var doub:Double = 0.0;
constructor(str:String,num:Int):this(str){
this.num = num;
}
constructor(str:String,num:Int,doub:Double):this(str,num){
this.doub = doub;
}
}
利用constructor声明多级构造函数,this()表示调用主构造函数。次级构造函数必须调用主构造函数。
2、访问修饰符
//前三个跟java的一样
private
protected
public
//这个指在模块内能够访问,例如module
internal
3、伴生对象
class StringUtils{
companion object {
fun isEmpty(str:String):Boolean{
return "" == str
}
}
}
fun main() {
println(StringUtils.isEmpty(""))
println(StringUtils.isEmpty("aa"))
}
有点像java静态方法,跟我们上面说的@JvmStatic注解有点像,在编译的时候为我们创建了一个静态内部对象。
4、单例类
class Single constructor(){
companion object {
fun get():Single{
return Holder.instance
}
}
private object Holder{
var instance = Single();
}
}
5、类的动态代理
interface Animal{
fun bark();
}
class Dog:Animal{
override fun bark() {
println("wang")
}
}
class Zoo(animal: Animal):Animal by animal
fun main() {
Zoo(Dog()).bark()
}
输出wang,如果重写了bark方法,就不会代理了。kotlin中编译的时候用的是静态代理,要比java中的效率高。
6、kotlin特有的类
数据类:
data class User(var id:Long,var name:String)
自动提供toString、equal、hashcode、getter、setter方法。并且类是final。
枚举类:
enum class Command{
A,B,C,D
}
//下面相当于switch去匹配
fun exec(command: Command) = when (command){
Command.A -> {}
Command.B -> {}
Command.C -> {}
Command.D -> {}
}
超级枚举:密闭类:
sealed class SuperCommand{
object A:SuperCommand()
object B:SuperCommand()
object C:SuperCommand()
object D:SuperCommand()
}
fun exec(command: SuperCommand) = when (command){
SuperCommand.A -> {}
SuperCommand.B -> {}
SuperCommand.C -> {}
SuperCommand.D -> {}
}