Kotlin的进阶学习
1基础的函数使用
1kotlin语言有具名函数参数,就是调用函数时不需要按照参数的顺序去填充参数,可以不按照参数声明顺序去调用
fun functionTest(name:String,age:Int){
println("name=${
name},age=$age")
val num1=1000_000_000
val num2=100
println(num1+num2)
}
2kotlin语言的Unit返回类型可以省略,和java的区别是,void是关键字,而Unit是类
3kotlin中的反引号作用:将java中的普通名称但是在kotlin中又是关键字的函数名,加上单反引号后就可视为一个普通的名称
package com.njupt.base
/**
*Creat with IntelliJ IDEA
*@Auther:倔强的加瓦
*@Date:2022/10/07/10:33
*@Description:
*/
fun main(){
你是谁()
}
private fun `你是谁`(){
println("我是你爹")
YinhaoTest.`in`()
}
4匿名函数
package com.njupt.base
/**
*Creat with IntelliJ IDEA
*@Auther:倔强的加瓦
*@Date:2022/10/07/10:33
*@Description:匿名函数的编写步骤
*/
fun main(){
//第一步:声明函数的函数名输入和输出类型以及返回值类型等
val function1 :()->String
//第二步:编写函数的具体实现细节
function1 ={
var name:String="你是我的小艾小苹果"
val length=name.count{
it == '我'
}
//最后一行就是返回值,不需要写return语句
name
}
//第三步:调用即可
println(function1())
}
有参数的匿名函数的编写
package com.njupt.base
/**
*Creat with IntelliJ IDEA
*@Auther:倔强的加瓦
*@Date:2022/10/07/10:33
*@Description:匿名函数的编写步骤
*/
fun main(){
//第一步:声明函数的函数名输入和输出类型以及返回值类型等,编写函数的具体实现细节
val function1 :(Int,String)->String={
num1,num2 ->
"返回的值为参数1:$num1,参数2:$num2"
}
//第三步:调用即可
println(function1(1,"啊啊啊"))
}
5当函数只有一个参数时,可以隐式的获取参数名为it,见方法三
package com.njupt.base
/**
*Creat with IntelliJ IDEA
*@Auther:倔强的加瓦
*@Date:2022/10/07/10:33
*@Description:匿名函数的编写步骤
*/
fun main(){
//第一步:声明函数的函数名输入和输出类型以及返回值类型等,编写函数的具体实现细节
val function1 :(Int,String)->String={
num1,num2 ->
"返回的值为参数1:$num1,参数2:$num2"
}
//第三步:调用即可
println(function1(1,"啊啊啊"))
val function2 :(String,Int)->String={
name1,num2->
"$name1,$num2"
}
println(function2("哈哈",12))
//对于只有一个参数的函数,会有一个默认的参数it
val function3:(Int) -> Int={
it*it
}
println(function3(3))
}
6kotlin中匿名函数的写法
package com.njupt.base
/**
*Creat with IntelliJ IDEA
*@Auther:倔强的加瓦
*@Date:2022/10/07/16:55
*@Description:
*/
fun main(){
//自定义判断返回参数类型,不需要指定函数的返回值,这就是匿名函数
val name={
a:Int,b:Int,c:Int->
val d=a*b
d*c
}
val week = {
a: Int ->
//参数是Int类型,但是返回值是Any类型
when (a) {
1 -> "星期一"
2 -> "星期2"
3 -> "星期3"
4 -> "星期4"
else -> -1
}
}
println(week(-1))
println(name(2,2,2))
}
7函数作为另一个函数的参数的使用
7.1java的写法
package com.njupt.base;
/**
* Creat with IntelliJ IDEA
*
* @Auther:倔强的加瓦
* @Date:2022/10/07/10:37
* @Description:
*/
interface ResultJson{
void code(String mess,int code);
}
public class YinhaoTest {
public static void main(String[] args) {
login("123", "123", new ResultJson() {
@Override
public void code(String mess, int code) {
System.out.println("信息是:"+mess+":状态码是:"+code);
}
});
}
public static void login(String name,String psw,ResultJson resultJson){
if(name.equals("abc")&&psw.equals("123")){
resultJson.code("登录成功",200);
}else{
resultJson.code("登录失败",444);
}
}
}
7.2.使用kotlin的写法,可以省略接口的写法。
package com.njupt.base
/**
*Creat with IntelliJ IDEA
*@Auther:倔强的加瓦
*@Date:2022/10/07/16:55
*@Description:
*/
fun main() {
//虽然有三个参数,但是第三个参数是函数,需要写在外面
login("abc","123"){
mess:String,code:Int->
println("信息是:$mess,状态码是:$code")
}
}
//登录密码的验证,从而返回响应包,将函数作为第三个参数
fun login(name:String,pwd:String,responseCode:(String,Int)->Unit){
if(name=="abc"&&pwd=="123"){
responseCode("登录成功",200)
}else{
responseCode("登录失败",444)
}
}
内联函数的引入:在当函数作为另一个函数的参数时,从字节码的角度看就是要创建对象去调用作为参数的方法,但是引入内敛函数后可以避免创建对象相互调用带来的消耗
情况1,不引入内敛函数上面代码反编译的情况:
package com.njupt.base;
import kotlin.Metadata;
import kotlin.jvm.functions.Function2;
import kotlin.jvm.internal.Intrinsics;
import org.jetbrains.annotations.NotNull;
@Metadata(
mv = {
1, 1, 18},
bv = {
1, 0, 3},
k = 2,
d1 = {
"\u0000\u001c\n\u0000\n\u0002\u0010\u0002\n\u0000\n\u0002\u0010\u000e\n\u0002\b\u0002\n\u0002\u0018\u0002\n\u0002\u0010\b\n\u0002\b\u0002\u001a0\u0010\u0000\u001a\u00020\u00012\u0006\u0010\u0002\u001a\u00020\u00032\u0006\u0010\u0004\u001a\u00020\u00032\u0018\u0010\u0005\u001a\u0014\u0012\u0004\u0012\u00020\u0003\u0012\u0004\u0012\u00020\u0007\u0012\u0004\u0012\u00020\u00010\u0006\u001a\u0006\u0010\b\u001a\u00020\u0001¨\u0006\t"},
d2 = {
"login", "", "name", "", "pwd", "responseCode", "Lkotlin/Function2;", "", "main", "kotlin_base"}
)
public final class SoutTest2Kt {
public static final void main() {
login("abc", "123", (Function2)null.INSTANCE);
}
// $FF: synthetic method
public static void main(String[] var0) {
main();
}
public static final void login(@NotNull String name, @NotNull String pwd, @NotNull Function2 responseCode) {
Intrinsics.checkParameterIsNotNull(name, "name");
Intrinsics.checkParameterIsNotNull(pwd, "pwd");
Intrinsics.checkParameterIsNotNull(responseCode, "responseCode");
if (Intrinsics.areEqual(name, "abc") && Intrinsics.areEqual(pwd, "123")) {
responseCode.invoke("登录成功", 200);
} else {
responseCode.invoke("登录失败", 444);
}
}
}
情况2引入内联函数的情况
package com.njupt.base;
import kotlin.Metadata;
import kotlin.jvm.functions.Function2;
import kotlin.jvm.internal.Intrinsics;
import org.jetbrains.annotations.NotNull;
@Metadata(
mv = {
1, 1, 18},
bv = {
1, 0, 3},
k = 2,
d1 = {
"\u0000\u001c\n\u0000\n\u0002\u0010\u0002\n\u0000\n\u0002\u0010\u000e\n\u0002\b\u0002\n\u0002\u0018\u0002\n\u0002\u0010\b\n\u0002\b\u0002\u001a3\u0010\u0000\u001a\u00020\u00012\u0006\u0010\u0002\u001a\u00020\u00032\u0006\u0010\u0004\u001a\u00020\u00032\u0018\u0010\u0005\u001a\u0014\u0012\u0004\u0012\u00020\u0003\u0012\u0004\u0012\u00020\u0007\u0012\u0004\u0012\u00020\u00010\u0006H\u0086\b\u001a\u0006\u0010\b\u001a\u00020\u0001¨\u0006\t"},
d2 = {
"login", "", "name", "", "pwd", "responseCode", "Lkotlin/Function2;", "", "main", "kotlin_base"}
)
public final class SoutTest2Kt {
public static final void main() {
String name$iv = "abc";
String pwd$iv = "123";
int $i$f$login = false;
short code;
String mess;
boolean var5;
String var6;
boolean var7;
if (Intrinsics.areEqual(name$iv, "abc") && Intrinsics.areEqual(pwd$iv, "123")) {
code = 200;
mess = "登录成功";
var5 = false;
var6 = "信息是:" + mess + ",状态码是:" + code;
var7 = false;
System.out.println(var6);
} else {
code = 444;
mess = "登录失败";
var5 = false;
var6 = "信息是:" + mess + ",状态码是:" + code;
var7 = false;
System.out.println(var6);
}
}
// $FF: synthetic method
public static void main(String[] var0) {
main();
}
public static final void login(@NotNull String name, @NotNull String pwd, @NotNull Function2 responseCode) {
int $i$f$login = 0;
Intrinsics.checkParameterIsNotNull(name, "name");
Intrinsics.checkParameterIsNotNull(pwd, "pwd");
Intrinsics.checkParameterIsNotNull(responseCode, "responseCode");
if (Intrinsics.areEqual(name, "abc") && Intrinsics.areEqual(pwd, "123")) {
responseCode.invoke("登录成功", 200);
} else {
responseCode.invoke("登录失败", 444);
}
}
}
2let apply also run 内置函数的使用
1.let的学习
//let函数的特点:
//1调用者在方法体内有一个代替者it
//当需要返回值时,大括号的最后一行就是返回值,并且不需要写return语句
package com.njupt.second
/**
*Creat with IntelliJ IDEA
*@Auther:倔强的加瓦
*@Date:2022/10/09/15:26
*@Description:
*/
fun main() {
//let函数的特点:
//1调用者在方法体内有一个代替者it
//当需要返回值时,大括号的最后一行就是返回值,并且不需要写return语句
//例如
println(checkNull(null))
println(checkNull2(null))
var name="1231231231"
name.let {
it.length>5
}.let {
if(it) "长度大于5" else "长度小于5"
}.let {
"$it"
}.let(::print)
}
//常规的判空
fun checkNull(name:String?):String{
if(name==null){
return "你在搞什么飞机,姓名不能为null"
}else{
return "欢迎你$name!"
}
}
//使用let函数进行判空
fun checkNull2(name :String?):String{
return name?.let{
"欢迎你$it"
} ?: "你在搞什么飞机,姓名不能为null"
}
2.apply
//apply内置函数的特点:
//1谁调用返回值就是谁
//2相比于let的单参数时it,apply的是this,可以隐藏
//3可以链式的调用
package com.njupt.second
/**
*Creat with IntelliJ IDEA
*@Auther:倔强的加瓦
*@Date:2022/10/09/15:04
*@Description:
*
*/
fun main() {
//apply内置函数的特点:
//1谁调用返回值就是谁
//2相比于let的单参数时it,apply的是this,可以隐藏
//3可以链式的调用
var str:String="Abcd Efg Hijk"
//调用的返回值类型就是调用者
var strNew=str.apply {
//使用this对象代替
println(this.toUpperCase())
}.apply {
//使用this对象代替
println(this.length)
}.apply {
//省略this的调用者
println(indexOf('A'))
}
println(strNew)
}
3,run
//run内置函数的特点
//1最后一行就是返回值
//2使用this来表示调用的结果,返回结果是什么类型,下一次调用this时就是什么类型
//3可以链式的调用具名函数和匿名函数
package com.njupt.second
/**
*Creat with IntelliJ IDEA
*@Auther:倔强的加瓦
*@Date:2022/10/09/16:51
*@Description:
*/
fun main() {
//run内置函数的特点
//1最后一行就是返回值
//2使用this来表示调用的结果,返回结果是什么类型,下一次调用this时就是什么类型
//3可以链式的调用具名函数和匿名函数
var name:String="asddasda"
//1使用匿名函数进行链式调用
var result=name.run{
this.length>5
//第一次调用,this表示String类型,返回的是boolean类型
}.run {
//第二次调用this表示的是上次一返回的boolean类型,返回的是String类型
if(this) "字符串大于5合格" else "不合格"
}.run {
//当前this是字符串类型,返回的也是字符串类型
"[$this]"
}
println(result)
//2使用具名函数进行调用
name
.run(::isLength)
.run(::isLegal)
.run (::println )
}
fun isLength(name:String):Boolean{
return name.length>5
}
fun isLegal(length:Boolean):String{
return if(length) "长度大于5" else "长度不合法"
}
4also方法
//also的特点:
//1谁调用also,返回值就是谁,元对象是不会变的,==apply
//2使用it来代替调用元素
package com.njupt.second
/**
*Creat with IntelliJ IDEA
*@Auther:倔强的加瓦
*@Date:2022/10/09/18:02
*@Description:
*/
fun main() {
//also的特点:
//1谁调用also,返回值就是谁,元对象是不会变的,==apply
//2使用it来代替调用元素
var name:String = "aedwsas"
var newStr=name.also{
println(it.length)
}.also {
println(it)
}
println(newStr)
}
四种内置函数的总结。
最后一行就是返回值 | 谁调用就返回谁 | |
---|---|---|
it | let | also |
this | run | apply |
3可变集合和不可变集合的学习
1Array数组的使用
package com.njupt.third
import java.io.File
/**
*Creat with IntelliJ IDEA
*@Auther:倔强的加瓦
*@Date:2022/10/10/20:23
*@Description:
*/
fun main() {
var arr:IntArray = intArrayOf(1,2,3,4,2)
println(arr[0])
//遍历
arr.forEach {
println(it)}
//注意这个空返回值只能返回Int类型的数
println(arr.elementAtOrElse(10) {
-1})
println(arr.elementAtOrNull(20) ?:"越界啦")
//将数组转成集合
val charArray= listOf('A','B','C').toCharArray()
println(charArray)
//还有一个针对存储对象的数组
var objArray= arrayOf(File("路径1"),File("路径2"),File("路径3"))
}
2List链表的使用
package com.njupt.third
/**
*Creat with IntelliJ IDEA
*@Auther:倔强的加瓦
*@Date:2022/10/09/20:54
*@Description:
*/
fun main() {
//不可变的list集合
var list= listOf<Int>(1,2,3,4)
println(list.getOrNull(4) ?: "你越界了哈!")
//将一个不可变的集合变成一个可变的集合
var list3=list.toMutableList()
//可变的list集合
var listM= mutableListOf<Int>(1,2,3,4,5,6)
listM.add(8)
listM.remove(2)
for(i in listM){
println(i)
}
println(listM)
//将可变的集合变成一个不可变的集合
var list4=listM.toList()
}
3Set集合的使用
package com.njupt.third
/**
*Creat with IntelliJ IDEA
*@Auther:倔强的加瓦
*@Date:2022/10/10/19:48
*@Description:
*/
fun main() {
//set集合
var set:Set<String> = setOf("as","abandon","if")
//可变的set集合
var mutableSet:Set<String> = mutableSetOf("as","sasd","asda","as")
mutableSet+="asdaasda"
//处理可能的越界问题
println(set.elementAt(0))
println(set.elementAtOrElse(11){
"越界"})
println(set.elementAtOrNull(10) ?: "越界")
//将list集合变成一个set集合
var list = mutableListOf<String>("1","1","2","3","4","4")
//变成一个不可重复的set
var listToSet=list.toSet()
println(listToSet)
//在变回来list
var result:MutableList<String> =listToSet.toMutableList()
println(result)
}
4map集合
package com.njupt.third
/**
*Creat with IntelliJ IDEA
*@Auther:倔强的加瓦
*@Date:2022/10/10/20:46
*@Description:
*/
fun main() {
//两种方式来定义
var map:Map<String,String> = mapOf("a" to "a","b" to "b")
var map1= mapOf(Pair("a","a"), Pair("b","b"))
//三种方式来进行获取
println(map["a"])
//如果没有当前key,会返回 null
println(map["c"])
println(map.getOrDefault("b","不存在当前key"))
println(map.getOrElse("a"){
"不存在当前"})
//三种方式来进行遍历
//println(map)
map.forEach{
println(it.key+it.value)
}
map.forEach{
key,value->
println(key+value)
}
for(i in map){
println(i.key+i.value)
}
//可变map集合的添加和删除
val muMap:MutableMap<Int,Int> = mutableMapOf(Pair(1,1), Pair(2,2), Pair(3,3))
muMap += 4 to 4
muMap -= 1
muMap.forEach {
println("${
it.key}+${
it.value}")
}
muMap.put(5,5)
//返回值,如果key存在就返回,如果不存在则插入并返回
var r =muMap.getOrPut(6){
6}
}
3kotlin中类字段field属性的使用
1省略set方法和get方法的field关键字的使用,以及对于空对象的防范竞态处理
package com.njupt.fourth
/**
*Creat with IntelliJ IDEA
*@Auther:倔强的加瓦
*@Date:2022/10/23/12:39
*@Description:关于field关键字的使用
*/
class FieldString{
var name="小河"
//这个就是java中的set和get方法
get()=field
set(value){
field=value
}
/*get方法
public String getName(){
return this.name;
}
*/
/*
set方法
public void setName(String value){
this.name=value
}
*/
var letter="dc"
//重载这个get方法
get()=field.toUpperCase()
set(value){
//控制返回的结果格式
field = value
}
//使用val代表不可变,其中不可变的解决方案就是没有set方法
val age=18
//在一些可空的对象,需要对其进行判空处理,叫做防范竞态条件
val psw:String ? =null
fun getShowPsw():String{
return psw?.let{
if(it.isEmpty()){
"当前值为空字符串"
}else{
"$it"
}
} ?:"当前返回值为null"
}
}
fun main() {
var fieldString=FieldString()
println(fieldString.name)
fieldString.name="asdasd啊实打实的"
println(fieldString.name)
println(fieldString.letter)
fieldString.letter="asdasd"
println(fieldString.letter)
//针对val修饰的变量只能进行获取,不能修改
println(fieldString.age)
//测试防范竞态条件,就是需要对可空的值进行可空处理
println(fieldString.getShowPsw())
}
4Kotlin中的面向对象学习
1主构造方法和次构造方法的使用
package com.njupt.fourth
import com.njupt.base.add
/**
*Creat with IntelliJ IDEA
*@Auther:倔强的加瓦
*@Date:2022/10/23/17:15
*@Description:
*/
//变量和主次构造函数的学习
//主构造方法和次构造方法,其中次构造方法一定要调用主构造方法,用于主构造统一管理,可以更好的初始化
class Teacher(name:String){
//init初始代码块,当主构造方法执行时,一定会执行这个代码块里的内容,一般用来进行初始化和判空处理
init{
//注意require方法是判断如果为空则会怎么样,反着来的!如果为false则通过异常的方式结束程序
require(name.isNotEmpty()){
"你的name初始化的值为空"
}
}
constructor(name:String,age:Int):this(name){
println("使用第一个构造方法")
}
constructor(name:String,age:Int,address:String):this(name){
println("使用了第二个构造方法")
}
}
fun main(){
var teacher=Teacher("张")
Teacher("zjamh",18)
Teacher("sda",12,"安徽省")
}
2主构造方法,此构造方法,初始化方法吗,属性赋值的执行顺序
package com.njupt.fourth
/**
*Creat with IntelliJ IDEA
*@Auther:倔强的加瓦
*@Date:2022/10/23/20:00
*@Description:
*/
//1先执行val age:Int
class People(_name:String,val age:Int){
//2在生成name
val name=_name
//3执行初始化方法
init{
var nameInit=_name
println("执行初始化方法")
}
//5调用次构造方法
constructor(name:String,age: Int,address:String):this(name,age){
println("次构造方法执行")
}
//4再次执行类的属性赋值
val lang="asdas"
}
fun main() {
//当执行次构造方法时执行顺序
var people=People("hai",12,"安徽")
}
3懒加载机制
package com.njupt.fourth
/**
*Creat with IntelliJ IDEA
*@Auther:倔强的加瓦
*@Date:2022/10/23/20:14
*@Description:
*/
//lateinit var 和by Lazy的使用
//1 lateinit var是指定属性可以在先不进行初始化,只需要在使用时在进行初始化即可
//2by lazy是通过懒加载的方式实现调用
class LateInitTest{
//在使用时是手动去加载,还有一种是自动惰性的加载即by lazy
lateinit var name:String
fun initName(){
name="爱说大话"
}
fun useName(){
println(name)
}
//当初始化时就会执行方法进行初始化,还没用到就进行了查询数据库操作
//var result=readDatabase()
//使用自动的方式去加载,懒汉模式,用到时才会去进行调用方法
val result2 by lazy {
readDatabase() }
fun readDatabase():String{
println("连接数据库")
println("查询数据库")
println("处理查询结果集")
println("返回结果")
return "数据库返回的结果是!!!!!"
}
}
fun main(){
//主线程中去调用,此时会初始化里面的变量,就会执行赋值的方法
var iniLazy=LateInitTest()
//主线程睡眠5秒
Thread.sleep(5000)
println(iniLazy.result2)
}
4open关键字
在kotlin中,所有的方法和类如果不加修饰,都是默认为final的,也就是不能被继承和重写,使用open关键字可以解决继承和重写的问题。
package com.njupt.fourth
/**
*Creat with IntelliJ IDEA
*@Auther:倔强的加瓦
*@Date:2022/10/24/11:39
*@Description:
*/
open class Country{
//私有方法不能被重写
private fun getPlace(){
println("我是父类,中国!")
}
open fun getName(){
println("我是父类的方法")
}
}
class Province: Country() {
override fun getName() {
println("我是子类重写的方法")
}
}
fun main() {
//父类的引用指向子类的对象
var p:Country=Province()
p.getName()
}
5is 和 as关键字来判断对象的类型,然后进行处理,并且有一个只能类型,就是只要转过类型一次,下面都是已经进行转行的。
package com.njupt.fourth
/**
*Creat with IntelliJ IDEA
*@Auther:倔强的加瓦
*@Date:2022/10/24/11:39
*@Description:
*/
open class Country{
//私有方法不能被重写
fun getPlace(){
println("我是父类,中国!")
}
open fun getName(){
println("我是父类的方法")
}
}
class Province: Country() {
override fun getName() {
println("我是子类重写的方法")
}
fun getPlace1(){
println("我是子类,省")
}
}
fun main() {
//父类的引用指向子类的对象
var p:Country=Province()
p.getName()
//使用is 进行强转,然后调用父类的方法
if(p is Country){
p as Country
p.getPlace()
}
p.getPlace()
}
6kotlin中的超类Any,类似于java中的Object,在其中只有标准,没有具体的实现类,目的是为了进行跨平台,不同的平台实现类不同
7Kotlin中单例类的实现方式:使用Object 代替class去修饰类即可成为一个单例的类。
8kotlin中的匿名对象
package com.njupt.fourth
/**
*Creat with IntelliJ IDEA
*@Auther:倔强的加瓦
*@Date:2022/10/24/11:53
*@Description:
*/
open class NominusObject{
open fun method1()= println("方法1")
open fun method2()=print("方法2")
}
//使用匿名函数去调用和实现两个方法
fun main() {
//使用匿名对象去重写方法
var no=object :NominusObject(){
override fun method1()=println("子类方法匿名对象去实现和调用了那个方法")
override fun method2() {
println("匿名对象去重写方法")
}
}
no.method1()
no.method2()
//等价于使用具名对象去调用
var sun=Sun()
sun.method1()
sun.method2()
//3还可以使用匿名对象去实现接口中的方法
var t1=object :Runnable{
override fun run() {
println("run方法执行。。。。。")
}
}
t1.run()
}
//使用不匿名的方式就是
class Sun:NominusObject(){
override fun method1()=println("子类方法具名对象去实现和调用了那个方法")
override fun method2() {
println("具名对象去重写方法")
}
}
9伴生对象类,就是companion object,类似于java中的static静态类
package com.njupt.fourth
/**
*Creat with IntelliJ IDEA
*@Auther:倔强的加瓦
*@Date:2022/10/24/12:31
*@Description:
*/
class Student{
companion object{
var name="小光"
fun getAge():Int{
return 18
}
}
}
fun main() {
//对于半生类可以使用类名直接调用
println(Student.name)
println(Student.getAge())
}
10内部类inner
当类进行嵌套时,外部类可以访问内部类,但是内部类不能访问外部类信息,外部类想要读取内部类吗,内部类想要获取外部类的信息,需要使用inner 关键字来修饰内部类。
package com.njupt.fourth
/**
*Creat with IntelliJ IDEA
*@Auther:倔强的加瓦
*@Date:2022/10/24/12:31
*@Description:
*/
class Student{
var name1="夏普"
companion object{
var name="小光"
fun getAge():Int{
return 18
}
}
inner class head{
var qiguan="头部"
//内部类去访问外部类
fun getName()=println(name1)
}
fun getQiguan(){
//外部类去访问内部类
println(head().qiguan)
}
}
fun main() {
//对于半生类可以使用类名直接调用
println(Student.name)
println(Student.getAge())
var student=Student()
student.head().getName()
student.getQiguan()
}