Kotlin入门学习(非常详细),从零基础入门到精通,看完这一篇就够了(1)

img
img

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

fun main() {
    val student1 = Student("zjm", 20, "123", 90)
    val student2 = Student("zjm", 20, "123")
    val student3 = Student()
}


无主构造

若类不使用主构造,则后续继承类也不需要使用构造即可去掉继承类的(),次构造可以调用父类构造super进行初始化,但是次构造的参数在其他地方无法引用

class Student : Person {
    constructor(name: String, age: Int, number: String) : super(name, age) {

    }
	fun study() {
        //name,age可使用
        println(name + "is studying")
        //使用number则会报错,若number是主构造的参数则可引用
        //println(number) 报红
    }
}


接口

接口的定义

Java中的接口定义类似

interface Study {
    fun study()
    fun readBooks()
    fun doHomework()
}


接口的继承

继承接口只需在后用","拼接,需实现Study声明的全部函数

class Student(name: String,  age: Int, val number: String, val grade: Int) : Person(name, age), Study{
    
    ...

    override fun study() {
        TODO("Not yet implemented")
    }

    override fun readBooks() {
        TODO("Not yet implemented")
    }

    override fun doHomework() {
        TODO("Not yet implemented")
    }
}


Kotlin支持接口方法的默认实现,JDK1.8以后也支持此功能,方法有默认实现则继承类无需必须实现此方法

interface Study {
    fun study() {
        println("study")
    }
    fun readBooks()
    fun doHomework()
}


权限修饰符

JavaKotlin的不同如下表所示:

修饰符JavaKotlin
public所有类可见所有类可见(默认)
private当前类可见当前类可见
protected当前类,子类,同包下类可见当前类,子类可见
default同包下类可见(默认)
internal同模块下的类可见

Kotlin引入internal,摒弃了default

使用:

类上

public open class Person(val name: String, val age: Int){...}


变量上

private val value = 1


方法上

private fun test() {
    
}


数据类和单例类

数据类

数据类则只处理数据相关,与Java Bean类似,通常需要实现其getsethashCodeequalstoString等方法

下面实现UserBean,包含idnamepwd属性

Java编写入如下:

public class UserBean {
    private String id;
    private String name;
    private String pwd;

    public UserBean() {

    }

    public UserBean(String id, String name, String pwd) {
        this.id = id;
        this.name = name;
        this.pwd = pwd;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        UserBean userBean = (UserBean) o;
        return Objects.equals(id, userBean.id) && Objects.equals(name, userBean.name) && Objects.equals(pwd, userBean.pwd);
    }

    @Override
    public int hashCode() {
        return Objects.hash(id, name, pwd);
    }

    @Override
    public String toString() {
        return "UserBean{" +
                "id='" + id + '\'' +
                ", name='" + name + '\'' +
                ", pwd='" + pwd + '\'' +
                '}';
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

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

    public String getPwd() {
        return pwd;
    }

    public void setPwd(String pwd) {
        this.pwd = pwd;
    }
}


Kotlin编写此类将变得非常简单,新建一个kt文件,选择如下:

一行代码即可搞定,Kotlin会自动实现上述方法。

data class UserBean(val id: String, val name: String, val pwd: String)


若无data关键字,上述方法(hashCodeequalstoString)无法正常运行,去掉data查看Kotlin对应的java文件:

public final class UserBean {
   @NotNull
   private final String id;
   @NotNull
   private final String name;
   @NotNull
   private final String pwd;

   @NotNull
   public final String getId() {
      return this.id;
   }

   @NotNull
   public final String getName() {
      return this.name;
   }

   @NotNull
   public final String getPwd() {
      return this.pwd;
   }

   public UserBean(@NotNull String id, @NotNull String name, @NotNull String pwd) {
      Intrinsics.checkNotNullParameter(id, "id");
      Intrinsics.checkNotNullParameter(name, "name");
      Intrinsics.checkNotNullParameter(pwd, "pwd");
      super();
      this.id = id;
      this.name = name;
      this.pwd = pwd;
   }
}


发现上面代码既无hashCodeequalstoString也无set

加上data且把变量改为var,对应的java文件如下:

public final class UserBean {
   @NotNull
   private String id;
   @NotNull
   private String name;
   @NotNull
   private String pwd;

   @NotNull
   public final String getId() {
      return this.id;
   }

   public final void setId(@NotNull String var1) {
      Intrinsics.checkNotNullParameter(var1, "<set-?>");
      this.id = var1;
   }

   @NotNull
   public final String getName() {
      return this.name;
   }

   public final void setName(@NotNull String var1) {
      Intrinsics.checkNotNullParameter(var1, "<set-?>");
      this.name = var1;
   }

   @NotNull
   public final String getPwd() {
      return this.pwd;
   }

   public final void setPwd(@NotNull String var1) {
      Intrinsics.checkNotNullParameter(var1, "<set-?>");
      this.pwd = var1;
   }

   public UserBean(@NotNull String id, @NotNull String name, @NotNull String pwd) {
      Intrinsics.checkNotNullParameter(id, "id");
      Intrinsics.checkNotNullParameter(name, "name");
      Intrinsics.checkNotNullParameter(pwd, "pwd");
      super();
      this.id = id;
      this.name = name;
      this.pwd = pwd;
   }

   @NotNull
   public final String component1() {
      return this.id;
   }

   @NotNull
   public final String component2() {
      return this.name;
   }

   @NotNull
   public final String component3() {
      return this.pwd;
   }

   @NotNull
   public final UserBean copy(@NotNull String id, @NotNull String name, @NotNull String pwd) {
      Intrinsics.checkNotNullParameter(id, "id");
      Intrinsics.checkNotNullParameter(name, "name");
      Intrinsics.checkNotNullParameter(pwd, "pwd");
      return new UserBean(id, name, pwd);
   }

   // $FF: synthetic method
   public static UserBean copy$default(UserBean var0, String var1, String var2, String var3, int var4, Object var5) {
      if ((var4 & 1) != 0) {
         var1 = var0.id;
      }

      if ((var4 & 2) != 0) {
         var2 = var0.name;
      }

      if ((var4 & 4) != 0) {
         var3 = var0.pwd;
      }

      return var0.copy(var1, var2, var3);
   }

   @NotNull
   public String toString() {
      return "UserBean(id=" + this.id + ", name=" + this.name + ", pwd=" + this.pwd + ")";
   }

   public int hashCode() {
      String var10000 = this.id;
      int var1 = (var10000 != null ? var10000.hashCode() : 0) * 31;
      String var10001 = this.name;
      var1 = (var1 + (var10001 != null ? var10001.hashCode() : 0)) * 31;
      var10001 = this.pwd;
      return var1 + (var10001 != null ? var10001.hashCode() : 0);
   }

   public boolean equals(@Nullable Object var1) {
      if (this != var1) {
         if (var1 instanceof UserBean) {
            UserBean var2 = (UserBean)var1;
            if (Intrinsics.areEqual(this.id, var2.id) && Intrinsics.areEqual(this.name, var2.name) && Intrinsics.areEqual(this.pwd, var2.pwd)) {
               return true;
            }
         }

         return false;
      } else {
         return true;
      }
   }
}


此时则和手动编写的java bean功能一样了,所有方法都可正常运行

单例类

目前Java使用最广的单例模式的实现如下:

public class Singleton {
    private Singleton() {
    }
    
    private static class SingletonHolder {
        private static final Singleton INSTANCE = new Singleton();
    }
    
    public static Singleton getInstance() {
        return SingletonHolder.INSTANCE;
    }
    public void test() {
        ...
    }
}


Kotlin中创建单例类需选择Object

生成代码如下:

object Singleton {
    fun test() {
        ...
    }
}


其对应的java文件如下,和上述使用最多的java单例实现类似

public final class Singleton {
   @NotNull
   public static final Singleton INSTANCE;

   public final void test() {
   }

   private Singleton() {
   }

   static {
      Singleton var0 = new Singleton();
      INSTANCE = var0;
   }
}


使用如下:

fun main() {
    Singleton.test() //对应的java代码为Singleton.INSTANCE.test();
}


Lambda

许多高级语言都支持Lambdajavajdk1.8以后才支持Lamda语法,LamdaKotlin的灵魂所在,此小节对Lambda的基础进行学习,并借助集合练习。

集合的创建和遍历
List
fun main() {
    //常规创建
    val list = ArrayList<Int>()
    list.add(1)
    list.add(2)
    list.add(3)
    
    //listOf不可变,后续不可添加删除,只能查
    val list1 = listOf<Int>(1, 2, 3 ,4 ,5)
    list1.add(6)//报错
    
    //mutableListOf,后续可添加删除
    val list2 = mutableListOf<Int>(1, 2, 3 ,4 ,5)
    list2.add(6)
    
    //循环
    for (value in list2) {
        println(value)
    }
}


Set

set用法与List类似,只是把listOf替换为mapOf

Map
fun main() {
    val map = HashMap<String, String>()
    map.put("1", "zjm")
    map.put("2", "ljn")
    //Kotlin中map支持类似下标的赋值和访问
    map["3"] = "lsb"
    map["4"] = "lyx"
    println(map["2"])
    println(map.get("1"))

    //不可变
    val map1 = mapOf<String, String>("1" to "zjm", "2" to "ljn")
    map1["3"] = "lsb" //报错
    
    //可变
    val map2 = mutableMapOf<String, String>("1" to "zjm", "2" to "ljn")
    map2["3"] = "lsb"
    
    for ((key, value) in map) {
        println(key + "   " + value)
    }
    
}


Lambda的使用

方法在传递参数时都是普通变量,而Lambda可以传递一段代码

Lambda表达式的语法结构

{参数名1: 参数类型, 参数名2:参数类型 -> 函数体}

Kotlinlist提供了maxByOrNull函数,返回当前list中xx最大的元素,XX是我们定义的条件,可能为长度,可能是别的,我们拿长度举例。

若不使用maxBy,实现如下

fun main() {
    val list = listOf<String>("a", "aba", "aabb", "a")
    var maxStr = ""
    for (str in list) {
        if (str.length > maxStr.length) {
            maxStr = str;
        }
    }
    println(maxStr)
}


maxByOrNull是一个普通方法,需要一个Lambda参数,下面结合Lambda使用maxByOrNull

fun main() {
    val list = listOf<String>("a", "aba", "aabb", "a")
    var lambda = {str: String -> str.length}
    var maxStr = list.maxByOrNull(lambda)
    println(maxStr)
}


直接当成参数也可传递

var maxStr = list.maxByOrNull({str: String -> str.length})


Lambda为方法的最后一个参数,则可将{}提到外面

var maxStr = list.maxByOrNull() {str: String -> str.length}


若有且仅有一个参数且是Lambda,则可去掉()

var maxStr = list.maxByOrNull {str: String -> str.length}


Kotlin拥有出色的类型推导机制,Lambda参数过多时可省略参数类型

var maxStr = list.maxByOrNull {str -> str.length}


Lambda只有一个参数,则可用it替代参数名

var maxStr = list.maxByOrNull {it.length}


集合还有许多此类函数

创建list,后续操作都由此list转换

val list = listOf<String>("a", "aba", "aabb", "a")


map 映射,返回新集合,将集合中的元素映射成另一个值

val newList = list.map { it.toUpperCase() }//将集合中的元素都准换成大写


filter过滤,返回新集合,将集合中的元素进行筛选

val newList = list.filter { it.length > 3 }//筛选出长度大于3的元素


any返回Boolean,集合中是否存在元素满足Lambda的条件,有则返回true,无则false

val isAny = list.any {it.length > 10} //返回false


all返回Boolean,集合中元素是否全部满足满足Lambda的条件,有则返回true,无则false

val isAll = list.all {it.length > 0} //返回true


Lambda的简单使用到这就结束了

Java函数式API的使用

Kotlin调用Java方法,若该方法接收一个Java单抽象方法接口参数,则可使用函数式APIJava单抽象方法接口指的是接口只声明一个方法,若有多个方法则无法使用函数式API

Java单抽象方法接口例如Runnable

public interface Runnable {
    void run();
}


Java中启动一个线程如下:

new Thread(new Runnable() {
    @Override
    public void run() {
        System.out.println("test");
    }
}).start();


Kotlin启动线程如下:

Kotlin摒弃了new,若想声明匿名内部类必须使用object

Thread(object : Runnable {
    override fun run() {
        println("test")
    }
}).start()


RunnableJava单抽象方法接口,可对代码进行简化

Thread(Runnable {
        println("test")
    }).start()


Runnable接口只用一个方法,使用Lambda也不会有歧义,Kotlin知道此Lambda一定实现的为run函数,借用Lambda进一步简化:

Thread({
    println("test")
}).start()


又因Thread只需一个参数Runnable参数,则可省略()

Thread {
    println("test")
}.start()


与上类似的,click也使用上述方法

button.setOnClickListener { println("test") }


这种方式可极大缩减代码量

空指针检查机制

国外统计程序出现最多的异常为空指针异常,Kotlin存在编译时检查系统帮助我们发现空指针异常。

查看下面Java代码

public void doStudy(Study study) {
    study.doHomework();
    study.readBooks();
}


上述代码时存在空指针风险的,传入null,则程序崩溃,对其进行改进

public void doStudy(Study study) {
    if (study != null) {
        study.doHomework();
        study.readBooks();
    }
}


对于Kotlin来讲任何参数和变量不能为空

fun study(study: Study) {
    study.doHomework()
    study.readBooks()
}

fun main() {
    study(null) //报错
    study(Student()) //正确
}


Kotlin把空指针异常的检查提前到了编译期,若空指针则编译期就会崩溃,避免在运行期出现问题

若我们有特殊的需求可能需要传递null参数,参数则按照下面声明

fun study(study: Study?) {
    study.doHomework() //报错
    study.readBooks()	//报错
}


?的意思则是当前参数可为空,如果可为空的话,则此对象调用的方法必须要保证对象不为空,上面代码没有保证,则报错,修改如下

fun study(study: Study?) {
    if (study != null) {
        study.doHomework()
        study.readBooks()
    }
}


也可借助判空辅助工具

判空辅助工具
?.

其含义是前面对象不为空才执行.后面的方法

fun study(study: Study?) {
    study?.doHomework()
    study?.readBooks()
}


?:

其含义是前不为空则返回问号前的值,为空则返回后的值

比如

val c = if (a !=null ) {
    a
} else {
    b
}


借助?:则可简化为

val c = a ?: b


再比如

fun getTextLength(text: String?): Int {
    if (text != null) {
        return text.length
    }
    return 0
}


借助?: 则可简化为

fun getTextLength(text: String?) = text?.length ?: 0


!!

有些时候我们想要强行通过编译,就需要依靠!!,这时就是程序员来保证安全

fun study(study: Study?) {
    //假设此时为空抛出异常,则和java一样
    study!!.doHomework()
    study!!.readBooks()
}


let函数

let不是关键字,而是一个函数,提供了函数式API的编程接口,会将调用者作为参数传递到Lambda表达式,调用之后会立马执行Lambda表达式的逻辑

obj.let { it -> //it就是obj
    //编写操作
}


比如上面函数

fun study(study: Study?) {
    study.doHomework()  //报错
    study.readBooks()	//报错
}


借助let则可改为

fun study(study: Study?) {
    //此时靠?.则保证了study肯定不为空,才会执行let函数
    study?.let {
        //it为study
        it.doHomework()
        it.readBooks()
    }
}


全局判空注意事项
//全局变量
var study: Study? = null
fun study() {
    //报错
    if (study != null) {
        study.readBooks()
        study.doHomework()
    }
}


因全局变量随时有可能被其他线程修改,即使判空处理也不能保证其没有空指针风险,而let则可规避上述问题

var study: Study? = null
fun study() {
    study?.let {
        it.doHomework()
        it.readBooks()
    }
}


内嵌表达式

之前我们拼接字符串都是下面这样

var name = "zjm"
var age = 20
println("My name is " + name + ". I am " + age + ".")
//打印结果
//My name is zjm. I am 20.


现在靠着Kotlin提供的内嵌表达式则不需要拼接,只需要下面这样则可实现

var name = "zjm"
var age = 20
println("My name is $name. I am $age." )
//打印结果
//My name is zjm. I am 20.


内嵌表达式还支持复杂的操作

${程序员想要的操作}

var name = "zjm"
var age = 20
println("My name is ${if (1 < 2) "zjm" else "ljn"}. I am $age." )
//打印结果
//My name is zjm. I am 20.


函数的参数默认值

Kotlin支持函数存在默认值,使用如下

fun main() {
    myPrint(1)
    myPrint(1, "lalala")
}

fun myPrint(value: Int, str: String = "hello") {
    println("num is $value, str is $str")
}

//结果如下
//num is 1, str is hello
//num is 1, str is lalala


value想为默认值,则会报错,因为在使用时传入的第一个参数他认为是int的,传入字符串会类型不匹配

fun main() {
    myPrint("zjm")//报错
}

fun myPrint(value: Int = 100, str: String) {
    println("num is $value, str is $str")
}


Kotlin提供了一种键值对传参来解决上述问题

fun main() {
    myPrint(str = "zjm") //正确调用
}

fun myPrint(value: Int = 100, str: String) {
    println("num is $value, str is $str")
}


回顾之前的主次构造,Student如下

class Student(name: String,  age: Int, val number: String, val grade: Int) : Person(name, age){
    constructor(name: String, age: Int, number: String) : this(name, age, number, 0) {

    }
    ...
}


上述的此构造借助参数默认值技巧是可以不写的,将第四个参数默认值为0 即可

class Student(name: String,  age: Int, val number: String, val grade: Int = 0) : Person(name, age){
	...
}


上述关于Kotlin的使用,已经够日常开发需要,后续笔者会更新一些进阶使用

黑客&网络安全如何学习

今天只要你给我的文章点赞,我私藏的网安学习资料一样免费共享给你们,来看看有哪些东西。

1.学习路线图

攻击和防守要学的东西也不少,具体要学的东西我都写在了上面的路线图,如果你能学完它们,你去就业和接私活完全没有问题。

2.视频教程

网上虽然也有很多的学习资源,但基本上都残缺不全的,这是我自己录的网安视频教程,上面路线图的每一个知识点,我都有配套的视频讲解。

内容涵盖了网络安全法学习、网络安全运营等保测评、渗透测试基础、漏洞详解、计算机基础知识等,都是网络安全入门必知必会的学习内容。

(都打包成一块的了,不能一一展开,总共300多集)

因篇幅有限,仅展示部分资料,需要点击下方链接即可前往获取

优快云大礼包:《黑客&网络安全入门&进阶学习资源包》免费分享

3.技术文档和电子书

技术文档也是我自己整理的,包括我参加大型网安行动、CTF和挖SRC漏洞的经验和技术要点,电子书也有200多本,由于内容的敏感性,我就不一一展示了。

因篇幅有限,仅展示部分资料,需要点击下方链接即可前往获取

img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Go语言开发知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以戳这里获取

g.cn/img_convert/f6d7a70326a6c0071cc4dc6b3eeb8f95.png)

攻击和防守要学的东西也不少,具体要学的东西我都写在了上面的路线图,如果你能学完它们,你去就业和接私活完全没有问题。

2.视频教程

网上虽然也有很多的学习资源,但基本上都残缺不全的,这是我自己录的网安视频教程,上面路线图的每一个知识点,我都有配套的视频讲解。

内容涵盖了网络安全法学习、网络安全运营等保测评、渗透测试基础、漏洞详解、计算机基础知识等,都是网络安全入门必知必会的学习内容。

(都打包成一块的了,不能一一展开,总共300多集)

因篇幅有限,仅展示部分资料,需要点击下方链接即可前往获取

优快云大礼包:《黑客&网络安全入门&进阶学习资源包》免费分享

3.技术文档和电子书

技术文档也是我自己整理的,包括我参加大型网安行动、CTF和挖SRC漏洞的经验和技术要点,电子书也有200多本,由于内容的敏感性,我就不一一展示了。

因篇幅有限,仅展示部分资料,需要点击下方链接即可前往获取

[外链图片转存中…(img-algIliI0-1715904691753)]
[外链图片转存中…(img-ptllsUET-1715904691753)]
[外链图片转存中…(img-nzAPKaq0-1715904691753)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Go语言开发知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以戳这里获取

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值