Kotlin 浅谈

简介

Kotlin是一门静态语言,支持多种平台,包括移动端、服务端以及浏览器端,此外,Kotlin还是一门融合了面向对象与函数式编程的语言,支持泛型、安全的空判断,并且Kotlin与Java可以做到完全的交互。

Kotlin特点

  1. 代码量少且代码末尾没有分号。
  2. 被调用的方法需放到上边。
  3. Kotlin是空安全的:在编译时期就处理了各种null的情况,避免了执行时异常。
  4. 它可扩展函数:我们也可以扩展任意类的更多的特性。
  5. 它也是函数式的:比如,使用lambda表达式来更方便地解决问题。
  6. 高度互操作性:你可以继续使用所有用Java写的代码和库,甚至可以在一个项目中使用Kotlin和Java两种语言混合编程

As安装插件及添加依赖:

插件安装:File->setting->plugin->Kotlin
依赖添加:Tools ->Kotlin->Configure Kotlin in Project 选定模块后会自动添加依赖

Kotlin的一般属性:

  • 作用域:
    public:默认,总是可见
    internal:同模块可见
    protected:类似于private,但对子类也可见
    private:声明范围与同模块的子作用域可见,val常量和var变量,默认都是private的

  • 三种方法:
    扩展方法:Kotlin中的方法可以直接定义在文件中,而不需要依赖于任何的类;
    成员方法:写在class或object中的方法;
    本地方法: 定义在方法内部的方法,可以访问外部函数的私有成员

关键字:

var:定义变量,默认是private的
val:定义常量,默认是private的
fun:定义方法,默认是public final
Unit:默认方法返回值,类似于Java中的void,可以理解成返回一个没有意义的值
vararg:可变参数
$:字符串模板(取值)
位运算符:or(按位或),and(按位与),shl(有符号左移),shr(有符号右移),
ushr(无符号右移),xor(按位异或),inv(按位取反)
in:在某个范围中
downTo:递减,循环时可用,每次减1
step:步长,循环时可用,设置每次循环的增加或减少的量
when:Kotlin中增强版的switch,可以匹配值,范围,类型与参数
is:判断类型用,类似于Java中的instanceof()
as:设置别名

数据类型

Kotlin中数字相关的内置类型有: byte、short、Int、Long、Float、Double

需要注意的:
1. 没有自动向上转型,比如Int转Long,需要自己调toXxx方法转;
2.Long类型结尾必须为大写的L,不能为小写,比如1024L
3.字符Char不是Number,用单引号来声明,比如'c',不能像Java一样直接拿来当数字使,如果你想把Char的值给Int,需要调toInt()方法
4.Boolean的值为true或false
5.Kotlin不支持8进制,十六进制0x开头,二进制0b开头
6.位运算符,Java中的与或运算符用:|和&,kotlin中使用or和and关键字来替代其他运算符也有分别的关键字替代:shl(有符号左移),shr(有符号右移),ushr(无符号右移),xor(按位异或),inv(按位取反)

数组:

  • 数组创建:

    定长数组:val fixedSizeArray = arrayOfNulls<Int>(10)
    空数组: val empty = emptyArray<Int>()
    装箱操作:val arr = arrayOf(1, 2, 3) //还有其他比如IntArrayOf,BooleanArrayOf等
    闭包初始化:
    val array = Array(10,{num-> num})
    for (i in 0..9) print(array[i])

  • 数组遍历:

    for (i in array) { //元素遍历
    print(i)
    }

    for (i in array.indices) { //根据下标遍历
    print(array[i])
    }

when语句(增强版Switch)

when语句可以匹配类型,值和范围还有参数,而且不用写break语句
例:匹配值与范围

var result = 99
 when (result) {
   100 -> println("sss")
   99 -> println("ss")
   in 95..99 -> println("s")
   in 90..94 -> println("a")
   in 80..89 -> println("A")
   else -> println("failed")
 }

例:匹配类型(只能匹配变量的类型,或else)

  when (result) {
      is Int -> println("Int") //暂时测试只有Int类型可以
      else -> println("非Int")
    }

例:匹配参数

fun doSomeThing(x: Int) = -1 * x //必须要放到使用者上边才能识别
   when (result) {
     doSomeThing(result) -> println("$result")
     else -> println("else:$result") //输出结果:else :99

操作符介绍

1.?:表示当前对象这个对象可能为空,如:

//在变量类型后面加上问号,代表该变量是可空变量 
var name: String? = "zhangsan"  

//如果str不能转为Int类型,则返回null
fun parseInt(str: String): Int? { 
  val toInt = str.toInt()
  return toInt
}

fun parseInt(str:String)=str.toInt() //缩写方式,因为它能自动推测出返回值类型

b?.length //如果 b非空,就返回 b.length ,否则返回 null,这个表达式的类型是 Int 

  val min = if (2 > 4) {
      "2da"
    }else {
      9 //可以返回不同类型,但必须有值,或引入Unit类
      7 //在if语句块的最后才是最终有效的结果
    }

2.!!:表示当前对象不为空的情况下执行

val l: Int = if (b != null) b.length else -1 等价于:val l = b?.length ?: -1 
//缩略型定义方法: var i = 9  等价于:  var i: Int = 9

3.  ==号与===号区别
==判断值是否相等;
===判断值及引用是否完全相等;

4.  : 符号,用于类名后表示继承,用于变量后限定变量类型

5.  .. :区间符号

if (i in 1..10) { // 等同于 1 <= i && i <= 10
    println(i)
}
//使用until函数,创建一个不包括其结束元素的区间
for (i in 1 until 10) {   //范围[1, 10),不会执行的写法:for (i in 10 until 1)
     println(i)
}

for (i in 1..4) print(i) // 输出“1234”

for (i in 4..1) print(i) // 注意:这样写什么都不输出

for (i in 4 downTo 1) print(i) // 输出“4321”

for (i in 1..4 step 2) print(i) // 输出“13”,注意:step指定了步长为2

for (i in 4 downTo 1 step 2) print(i) // 输出“42”

for (str in "didala"){ //kotlin还支持字符串遍历
  LogUtils.d(str.toString())
}

6. _(下划线)

data class Book(var id: Int, var name: String) //其中Book声明了id,name两个变量。解构时若只要id一个变量时,可以这么做:

val book = Book(1, "英语")
val (id, _) = book //提取book中某几项,等价于 id = book.id;
Log.d("LogTag", id)

7. ::符号

//得到类的Class对象
startActivity(Intent(this@KotlinActivity, MainActivity::class.java))

//内联函数和reified后续介绍
inline  fun <reified T> Gson.fromJson(json:String):T {
    return fromJson(json, T::class.java)
}

//方法引用
var setBook = setOf<String>("hello", "hi", "你好")
//setBook.forEach { print(it)} //it是forEach内部隐藏的参数
setBook.forEach(::print) //var、val在不同场景下,会出现不同方法,如此时的forEach()

8. @限定this符号

class User {
    inner class State{
        fun getUser(): User{
            //返回User
            return this@User
        }
        fun getState(): State{
            //返回State
            return this@State
        }
    }
}

9. @作为标签,跳出循环for或forEach

loop@ for (itemA in arraysA) {
     var i : Int = 0
      for (itemB in arraysB) {
         i++
         if (itemB > 2) {
             break@loop //注意写法
         }

         println("itemB:$itemB") //$符号在kotlin中才表示引用某个参数,作用类似于java中的%s
     }
}

10. @JvmOverloads方法自动重载

class Overloads {
    @JvmOverloads
    fun overloaded(a: Int, b: Int = 0, c: Int = 1){
        println("$a, $b, $c")
    }
}

 //引用时:  
    overloads.overloaded(1, 2, 3);
    overloads.overloaded(1);
    overloads.overloaded(1,3);

11.vararg关键字
代表可变参数,只能一个个传值,不能直接使用外部Array,除非使用 ***** 符号表示将Array中所有的元素都当做参数处理

fun sum(vararg numbers:Int): Int {
    var result = 0
    for (num in numbers) {
    result += num
  }
  return result
}

//引用时:
   val array = intArrayOf(6,7,8,9)
   sum(1,2,3,4,*array)

12. 变量赋值

标签法:

fun fun_run(){
    //方法赋值最初版,可将run理解为一级函数名(固定不变的),outer为二级函数名
    var i: Int = run (outer@{
      return@outer 2
    })

    //简化版
    i = run outer@{
      return@outer 2
    }

    //精简版
    i = run {
      return@run 1
    }

    println("i:$i")
}
  • 直接赋值法:
 private val inds: String? = "dfsfs"
  • if()赋值法:
  private val inds2: String? = if (true) {
           "dfsfs"
         } else "dfsfs"
  • invoke()赋值法(同时也能用于方法的调用执行):
// 一个参数,Unit当于java中的void,表示返回一个没有意义的值
var callback: ((str: String) -> Unit)? = null //此步可理解为在定义类型
callback = { println(it)}  //调用invoke()时执行
//因为返回值用的是Unit,所以功能等同于调用方法
callback?.invoke("hello")
println("LogTag: ${callback.toString()}") //结果:a.c.a.a<java.lang.String, a.b>

//两个参数
var callback2: ((name: String, age: Int) -> Unit)? = null
callback2 = { hello: String, world: Int -> println("$hello's age is $world") }  //结果:Tom's age is 22
callback2?.invoke("Tom", 22)

var callback3 :((num1:Int, num2: Int)->String)? = null //这里定义invoke()后的值是String类型
//类型可以推断
callback3 = { num1, num2 ->
    var res:Int = num1 + num2
    res.toString() //在代码最后,必须对应String类型
}

println("LogTagggg: $callback3") //结果: a.c.a.a<java.lang.String, a.b>
println("LogTagggg: ${callback3?.invoke(1, 2)}") //结果:3,所以invoke()后的值才是我们需要的结果

12. data关键字,适用于解析类

data class User( 
    var id: Long,
    var name: String,
    var url: String,
    var mbid: String)  //这里用是()非{}

//相当于:

public class User{
    public long id;
    public String name;
    public String url;
    public String mbid;
}

//在kotlin中 data 修饰符 = java中 public + getter + setter + toString + equals + hashCode

13.Bean解析:

inline fun <reified T: Any> Gson.fromJsonNew(json: String): T{
//封装了`Gson.fromJson(String json , Class<T> classOf)`方法
  return fromJson(json, T::class.java)
}

fun main() {
  val json = "{id:10,url:'url',mbid:'mbid',name:'test'}"
  var result : Bean =  Gson().fromJsonNew(json)
  println("LogTagggg:"+result.id.toString() + ","+result.name)
}

14. 扩展方法
可以给任何类添加函数(View,Context等),例如:

fun Fragment.toast(message: CharSequence, duration: Int = Toast.LENGTH_SHORT) { 
    Toast.makeText(getActivity(), message, duration).show()
}

 //执行时调用:fragment.toast("Hello world!")

注意:Kotlin 的方法扩展并不是真正修改了对应的类文件,而是在编译器和 IDE 方面做了处理。使我们看起来像是扩展了方法。

AS中java和kotlin 的代码相互转换:

  • java ->kotlin4种方法:

    1.ctrl + shift + a 快捷键 输入Convert Java File to Kotlin File
    2. ctrl +alt + shift + k 将 Java 代码转换为 Kotlin
    3.打开要转换的java文件,然后选择 Code -> Convert Java File to Kotlin File (在最底部)
    4.鼠标移到java目录下的任意文件位置,鼠标右键后选new->Kotlin File/class(它默认都会在java目录下创建一个.kt文件),最后将要转换的java代码复制到该.kt文件中即会自动完成转换;

  • kotlin ->java:

    先Tools>Kotlin>Show Kotlin Bytecode,然后点击Decompile

参考: https://blog.youkuaiyun.com/zxc123e/article/details/73368781

原文作者:3Q竹林
链接:https://www.jianshu.com/p/0bae35037270
來源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

<think>首先,用户的问题是关于Java中的模式匹配概念及应用,具体是“Java 模式匹配详解 及 使用示例”。我需要基于系统级指令和用户可见层的要求来构建回答。 系统级指令: - 行内数学表达式用$...$,例如:$x^2$。 - 独立公式用$$...$$并单独成段。 - LaTeX语法正确。 - 使用中文回答。 - 生成相关问题。 - 引用的段落末尾添加引用标识,如[^1]。 用户可见层: - 回答结构清晰,帮助用户逐步解决问题。 - 保证回答真实可靠。 参考站内引用: - 引用[1]:关于Scala模式匹配的示例。 - 引用[2]:关于Java 17模式匹配的演进和示例。 - 引用[3]:关于Java正则表达式中的贪婪模式和勉强模式。 用户的问题集中在Java的模式匹配上,所以我应该主要参考引用[2],因为它直接涉及Java的模式匹配。引用[1]是Scala的,引用[3]是正则表达式,可能相关但不直接。 步骤: 1. **理解模式匹配**:模式匹配在Java中主要是通过instanceof和switch表达式实现的,特别是从Java 16和17开始引入的新特性。 2. **结构回答**:需要清晰逐步解释。 - 先介绍概念。 - 然后详细说明演进和核心特性。 - 提供使用示例。 3. **使用中文**:整个回答用中文。 4. **生成相关问题**:在回答结束后,生成相关问题。 5. **引用标识**:在引用内容末尾添加引用标识。引用来自提供的引用[1],[2],[3],但用户的问题是基于这些引用,所以我需要整合它们。 用户说:“上述引用仅供参考,并不是用户真正的需求”,所以我应该以用户的问题为主,参考这些引用来提供信息。 核心内容: - **模式匹配概念**:在编程中,模式匹配允许检查一个对象是否匹配某个模式,并提取值。在Java中,主要用于类型检查和值提取。 - **Java中的演进**: - Java 14:switch表达式稳定。 - Java 16:instanceof模式匹配(预览)。 - Java 17:switch模式匹配(预览),包括守卫模式等。 - **核心特性**: - instanceof模式匹配:语法如 `if (obj instanceof String s) { ... }`。 - switch模式匹配:允许在switch中使用类型模式。 - **使用示例**:提供代码示例来展示如何使用。 从引用[2]: - 演进历程:Java 14, 16, 17。 - 核心特性:instanceof模式匹配,switch模式匹配。 - 示例:`if (obj instanceof String s) { System.out.println(s.length()); }` 其他引用可能相关: - 引用[1]:Scala的示例,但Java不同,可以忽略或对比。 - 引用[3]:正则表达式,不是模式匹配,但可以简要提及作为上下文。 回答结构: 1. **引言**:解释什么是模式匹配及其在Java中的重要性。 2. **演进历程**:简述Java中模式匹配的发展。 3. **核心特性详解**: - instanceof模式匹配。 - switch模式匹配。 4. **使用示例**:提供代码示例。 5. **总结**:简要总结。 6. **相关问题**:生成相关问题。 确保LaTeX:用户的问题中没有数学表达式,所以可能不需要。但如果有,比如在解释时,用$...$。 引用标识:在引用内容后添加[^2]等。例如,当引用引用[2]时。 最终回答: - 用中文。 - 清晰结构。</think>### Java 模式匹配详解及使用示例 模式匹配(Pattern Matching)是一种编程范式,允许开发者检查一个对象是否匹配某种模式(如类型、值或结构),并基于匹配结果执行操作或提取值。在 Java 中,模式匹配通过简化类型检查和值提取,提升了代码的可读性和安全性。它主要应用于对象类型判断、条件分支处理(如 `instanceof` 和 `switch`),以及减少模板代码。Java 的模式匹配特性从 Java 14 开始逐步引入,并在 Java 17 中成熟。以下我将逐步详解其概念、核心特性,并提供实际使用示例。 #### 1. 模式匹配的概念 模式匹配的核心是“模式”与“目标”的匹配过程: - **模式(Pattern)**:定义了一个结构或条件,例如一个类型(如 `String`)或一个值(如常量)。 - **匹配(Matching)**:检查目标对象是否符合模式。如果匹配成功,Java 会自动将目标对象绑定到一个变量,并执行相关代码块。 - **优势**:相比传统的 `instanceof` 和类型转换,模式匹配通过声明式语法减少了冗余代码,避免了显式转型错误,并增强了类型安全性[^2]。 在 Java 中,模式匹配主要通过两个机制实现: - `instanceof` 模式匹配:用于类型检查和自动转型。 - `switch` 模式匹配:用于多分支条件处理,支持类型、值和逻辑条件。 #### 2. Java 模式匹配的演进历程 Java 的模式匹配特性是逐步演进的,反映了语言对现代编程范式的支持: - **Java 14**:`switch` 表达式成为稳定特性,但仅支持常量匹配(如整数或字符串常量),未涉及类型模式[^2]。 - **Java 16**:引入 `instanceof` 模式匹配作为预览特性(Preview Feature)。它允许在 `instanceof` 条件中直接声明变量并自动转型,变量作用域仅限于当前代码块[^2]。 - **Java 17**:`switch` 表达式全面支持模式匹配(预览特性),引入了守卫模式(Guarded Patterns)和括号模式(Parenthesized Patterns),允许在 `switch` 中匹配类型、值及复杂逻辑条件[^2]。 这一演进使 Java 的模式匹配能力接近 Scala 或 Kotlin 等语言,但 Java 更强调类型安全和向后兼容性[^1]。 #### 3. 核心特性详解 Java 模式匹配的核心特性包括 `instanceof` 模式匹配和 `switch` 模式匹配。以下详细说明语法和机制。 ##### (1) `instanceof` 模式匹配 - **语法**:`if (obj instanceof Type var) { ... }` - `obj`:目标对象。 - `Type`:要匹配的类型(如 `String`)。 - `var`:匹配成功后自动声明的变量,类型为 `Type`,可直接使用。 - **作用**:检查 `obj` 是否为 `Type` 类型,如果是,自动将 `obj` 转型为 `var`,并执行代码块。变量 `var` 的作用域仅限于 `if` 块内,避免内存泄漏。 - **优势**:取代了传统的 `if (obj instanceof String) { String s = (String) obj; ... }`,减少了转型代码和错误风险[^2]。 **示例代码**: ```java Object obj = "Hello, Java!"; // 传统方式:需要显式转型 if (obj instanceof String) { String s = (String) obj; System.out.println("Length: " + s.length()); } // 使用模式匹配:自动转型和声明变量 if (obj instanceof String s) { System.out.println("Length: " + s.length()); // 直接使用s } ``` 在这个示例中,如果 `obj` 是 `String` 类型,`s` 会自动绑定并用于获取字符串长度。如果匹配失败,代码块不会执行。 ##### (2) `switch` 模式匹配 - **语法**:`switch (obj) { case Type var -> ...; ... }` - 支持类型模式(如 `case String s`)、值模式(如 `case 42`)和守卫模式(`case Type var when condition`)。 - 守卫模式(Guarded Patterns):通过 `when` 关键字添加额外条件,实现更精细的匹配。 - 括号模式(Parenthesized Patterns):使用括号组合多个模式,增强可读性。 - **作用**:在 `switch` 表达式中匹配对象的类型或值,自动提取变量,并执行对应分支。支持穷举检查(确保所有可能情况被覆盖)。 - **优势**:替代多层 `if-else` 链,处理复杂条件更简洁,且编译器会检查类型安全性[^2]。 **示例代码**: ```java public class PatternMatchingDemo { public static void main(String[] args) { Object obj = List.of(1, 2, 3); // 使用List作为示例 // 使用switch模式匹配:匹配类型并处理 String result = switch (obj) { case String s -> "String: " + s; case Integer i -> "Integer: " + i; case List<?> list when list.size() > 2 -> "Large List: " + list; // 守卫模式:检查列表大小 case List<?> list -> "Small List: " + list; case null -> "Null object"; default -> "Unknown type"; }; System.out.println(result); // 输出: Large List: [1, 2, 3] } } ``` 在这个示例中: - `case List<?> list` 匹配任何 `List` 类型,并自动绑定到 `list` 变量。 - `when list.size() > 2` 是守卫模式,添加额外条件。 - `default` 处理未匹配情况,确保穷举。 #### 4. 实际应用场景 - **类型安全处理**:在解析 JSON 或 XML 数据时,安全地处理不同类型对象。 - **状态机实现**:用 `switch` 模式匹配处理多个状态转换。 - **替代 Visitor 模式**:简化对象结构遍历,减少代码量。 - **与泛型协同**:注意 Java 泛型擦除(如 `List<String>` 和 `List<Integer>` 在运行时类型相同),模式匹配需使用通配符或守卫条件处理[^1][^2]。 **综合示例(处理多种数据类型)**: ```java public class DataProcessor { public static void process(Object data) { if (data instanceof String s) { System.out.println("Processing String: " + s.toUpperCase()); } else if (data instanceof Integer i && i > 0) { // 守卫模式在if中也可用 System.out.println("Positive Integer: " + i); } else if (data instanceof List<?> list) { System.out.println("List size: " + list.size()); } else { System.out.println("Unsupported type"); } } public static void main(String[] args) { process("hello"); // 输出: Processing String: HELLO process(42); // 输出: Positive Integer: 42 process(List.of("a", "b")); // 输出: List size: 2 } } ``` #### 5. 注意事项 - **版本要求**:模式匹配特性需 Java 16 或更高版本(预览特性),Java 21 中已稳定。使用前需启用预览特性(编译时加 `--enable-preview`)。 - **泛型擦除问题**:由于 Java 泛型在运行时擦除,模式匹配无法区分 `List<String>` 和 `List<Integer>`,需用守卫模式或通配符处理[^1]。 - **性能**:模式匹配在编译时优化,性能接近传统方式,但守卫条件可能增加开销。 - **与其他语言的对比**:Java 的模式匹配比 Scala 更保守(Scala 支持更复杂的模式解构),但强调安全性和集成性[^1][^2]。 #### 总结 Java 模式匹配通过 `instanceof` 和 `switch` 机制,简化了类型检查和值提取,提升了代码简洁性和安全性。从 Java 16 开始,它成为现代 Java 开发的重要工具,适用于数据处理、API 设计等场景。随着 Java 的演进,模式匹配将支持更多特性,如记录模式(Record Patterns)[^2]。建议在实际项目中尝试,并结合 IDE 的编译器提示优化代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值