? ! ! 可选值
Kotlin是类型安全语言: 变量声明的时候必须赋初值
可选类型 可能有值 可能没值null
特点 在变量声明中使用问号
使用可选类型的变量时,变量后面加一个?,功能:当这个变量有值有数据,那么就访问这个变量的对应方法,如果没有值,那么不会访问该变量对应的方法,也不会报错
!!:如果在使用可选类型的变量时,能够确定该变量有值 使用!!(如果没有值用这个会报错)
eg: var name:String? =null
print("name has ${name?.length} char")
输出结果:name has null char
if-else
1.条件必须是true或false
2.if-else表达式 如果有if要执行的操作有多个语句那分支的最后一行就是计算结果
eg:val age =16
var result:String? =null
if (age >=18){
result ="我已成年"
}else{
result ="我未成年"
}
print(result)
when:when的条件可以是任意类型
eg://区间
val salary =8000;
var income =0
var tax =0
when(salary){
in 0..5000 -> tax =0
in 5001..10000 -> tax = (salary *0.1).toInt()
else -> tax = (salary *0.2).toInt()
}
//单个值
val rank =1
when(rank){
1 -> income =10000
2 -> income =20000
3 -> income =30000
else -> income =50000
}
//多个值
val a =10
when(a){
1,2 -> {}
3,4,5,6 -> {}
else -> {}
}
c语言
int add(int a, int b){
return a + b
}
函数就是一个代码块:封装某一个功能
Kotlin: fun 函数名(参数){功能} 不用先声明后实现 声明完的类/函数可以给同工程的其他文件使用(无需导入全局适用)
eg://没有参数 没有返回值(非要写参数 就写:Unit)
fun doSomething(){
//功能
print("没有参数 没有返回值")
}
//有1个或多个参数,没有返回值
fun test1(age:Int){
print("My age is $age")
}
//重载函数
fun test1(age:Int,score:Float){
print("My age is $age")
}
//有2个参数,有返回值
fun add(p1:Int,p2:Int):Int{
return p1 + p2
}
这里还有一个很强大的功能,就是在你声明函数时可以给函数默认初始值,比如:
fun minus(p1:Int=2,p2:Int= 0):Int{
return p1 - p2
}
fun main() {
result =minus()
println("---$result")
}
运算结果如下:
---2
还有另外一种用法,只给一个参数初始值,另一个暂时不给,比如:
fun minus(p1:Int=2,p2:Int):Int{
return p1 - p2
}
fun main() {
result =minus(p2 = 1) //注意,此时如果不给p2传值,系统会报错,必须在调用函数的时候给另一个尚未被赋予初始值的参数传值
println("---$result")
}
运算结果如下:
---1
for循环可以加标签 比如在外层循环加标签abc@ 这样当内层循环想直接跳出外层循环时,break@abc可以直接跳出外层循环。标签不只可以加一个,当有多个循环可以加多个,跳出你指定的循环。
类和对象
面向对象和面向过程的区别
封装:将属性和行为(方法、功能)封装成一个按整体
可以提供给外部交互的接口(属性、方法) 方法通常为动词
类:对一类事物的高度抽象 比如人类 “没有内存空间”(不是真的没有内存空间只是帮助理解)
对象 实际存在的具体事物 “需要内存空间”
举例
类class:人类Person 属性:性别sex 姓名name 家乡hometown
方法: 使用工具 useTool 睡觉sleep 学习study
对象object: 男 张三 日本
类class:车 Car 属性:品牌brand 车牌号number 颜色color
方法:启动start 载人take
0000(奥迪): 奥迪A4L 渝D88888 黑色
//类的声明(无继承,该类就是鼻祖)
class Person{
}
*类的名称首字母大写
*尽量一个文件中编写一个类 文件的名称和类名保持一致(新建一个file 名字为该类的名称)
fun main() {
//创建类的一个对象
//类的实例化(专业表示)
//Kotlin默认不用导入任何文件,该文件可以全局访问其他文件里的方法
val ls:Person = Person()//Kotlin与Java的区别:独有的定义变量方法val/var;无需指定变量类型(需要指定也可以);不用new
val zs = Person()//可以在同一个类里定义多个不同对象,此处没有指定变量类型
}
那么我们来看看Java里面是如何实现对象的定义的:
public class MyClass {
public static void main(String[] args) {
//实例化对象
Person ppp =new Person();//第一个Person是变量类型,ppp是变量名,第二个Person是指调用Person这个类,创建一个新的对象 //其实这里用的Person是我们上面在Kotlin里定义的,但java一直没报错,说明java和kotlin是互通的
}
}
这里来解释一下为什么上面说的类不占内存这种说法是错的
/**
* 类的加载流程
* 定义——没有内存
* 使用这个类 —— 将这个类加载到内存里面(以类对象的形式在内存中加载)
* 创建这个类的一个对象 —— 使用类对象来创建一个对象
* 为这个对象分配内存空间
* -----------
* 分配遗产 (回收这个对象拥有的其他资源)
* ---
* say goodbye(收回这个对象的内存 == 销毁对象)
*
*/
举个具体例子:
**
Person、Car等类储存在硬盘中(此时为定义完的状态),当你需要使用这几个类来新建对象时,
Person、Car等类进入内存,此时是类对象的形式,类对象的类型为Class,此时按照类对象Person
的方法属性构造一个具体对象,并分配一片内存空间给他(0x100),指针变量xw存储该内存空间的地址;
这个具体对象0x100里有很多属性,比如name,是一个指针变量,分配一片内存空间存储name的具体数值
xiaowang,xiaowang的地址存储在name里;如果不想要这个具体对象了,要先回收该对象拥有的资源,
比如名字xiaowang,释放完毕之后再释放该具体对象的内存空间
*
*
*
*/
/**
对象是怎么创建的?创建一个对象所需要的经历的过程:
1.通过构造函数(noun.)来创建这个对象——访问类对象里这个类对应的构造函数
不显示声明,就使用默认构造函数(类似上面的class Person)
2.Kotlin的默认构造函数class Person(){ }(即在类名后面加上一个圆括号)
这里的圆括号是灰色的 意思是构造函数里是空的 可以移去
如果非要写东西可以写成:class Person constructor(){ } 这样就是最标准的写法
类名+ constructor() 叫做类的主构造函数,顾名思义,在类的头部就写了一个构造函数就叫主构造函数
别人调用这个方法的时候就是通过这个主构造函数来调用的;默认情况下没有参数就可以不写constructor()
3. 既然构造函数可写可不写,为什么需要构造函数?
当你在创建一个对象的时候,你想在创建的时候给它一些数据,而构造函数又是这个类的对象被创建的第一步,
也就是对象被创建时第一时间调用的就是构造函数,如果有一些数据你希望是在这个对象被创建的第一时间就
赋予它的,就应该跟着构造函数来,一旦构造函数被调用,这个对象就被创建完了。
4.怎么实现创建对象时就给他一些数据?
在构造函数里传给它我想要的数据,它就会去构造,构造好了之后它就会把这些数据赋值给这些对象
5.言简意赅,构造函数的功能:在创建一个对象的时候传给它一些值(不会错过最佳时机)
Java里的构造函数:
public class MyPerson {
//Java提供的默认构造函数——函数名和类名相同(和C++一样,没区别)
public MyPerson(){
}
}
Java里怎么传值给构造函数?
//类的圆括号里是来接受外部传的值的,只需要告诉它你传的值是什么类型
public MyPerson(String name){
}
public static void main(String[] args) {
//实例化对象
MyPerson ppp =new MyPerson("xiaowang");//此时就可以开始调用xiaowang的各种方法了
}
Kotlin里怎么传值给构造函数?
class Person constructor(name:String){
}
此时我们把主构造函数给改变了,注意这里的和java的区别,名字在前类型在后,这个时候我们之前定义的val ls:Person = Person() 就会开始报错,因为在Kotlin里主构造函数被改变了默认的构造函数就没有了,而在java里主构造函数改变后默认构造函数还是在的
Kotlin里的次构造函数:除了主构造函数之外的构造函数都是次构造函数
构造的顺序:如果调用主构造函数来创建,直接调用
如果使用次构造函数,而且主构造函数有参数,次构造函数必须先调用主构造函数
class Person{
constructor(name:String){
}
比较高级的次构造函数:
class Carconstructor(brand:String){
constructor(brand: String,color:String):this(brand){//this里默认提供一个brand了该行的constructor后就不加brand,冒号是继承的意思
}
}
val benz = Car("奔驰","黑色")
次构造函数的作用,当主构造函数提供的一个参数不足以满足使用者需要时可用