Kotlin中字段是私有的,会自动生成get、set方法。
fun main(args: Array<String>) {
val person=Person()
//表面看是直接访问了属性,其实是通过get方法
println(person.name)
println(person.age)
}
class Person{
var name:String="haha"
var age:Int=23
}
class Person{
var name:String="haha"
var age:Int=23
//需求:school字段不能外部修改
var school:String="hehe"
private set//私有了set方法
}
java中我们可以在set方法里处理一些逻辑,Kotlin中set方法是自动生成的,那我们如果想在里面处理逻辑,就要修改访问器了。
class Person{
var name:String="haha"
var age:Int=23
set(value) {
if(value<100){
//this.age=value //这种造成递归
field=value
}
}
//需求:school字段不能外部修改
var school:String="hehe"
private set//私有了set方法
}
需求:创建的时候就需要修改里面的name和age,也就是需要类似java中构造函数。
class Person(name:String,age:Int){
var name:String=""
var age:Int=0
//构造函数中写的代码可以放到init中执行
init {
this.name=name
this.age=age
}
}
我们需要用变量保存构建函数的参数值,如上,写起来比java还麻烦,不过Kotlin中有简单的方案,就是用var和val来修饰构建函数参数。
class Person(var name:String,var age:Int){
}
//相当于java中这么写
class Person{
public String name;
public int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
}
那么,用var和val修饰的区别是什么?val修饰后,外部不可修改(不可赋值)。
class Person(var name:String,var age:Int){
var phone:String=""
//次构函数
constructor(name:String,age:Int,phone:String):this(name,age){
this.phone=phone
}
}
Kotlin的类都是final的,不能被继承,需要加open
open class Father{
open var name="百里屠苏"
open fun smoke(){
println("父亲喜欢抽烟")
}
}
class Son:Father() {
//继承属性
override var name="百里少侠"
//继承方法
override fun smoke() {
//super.smoke()
println("百里少侠喜欢看书")
}
}
//抽象类不用open关键字
abstract class Human{
//肤色
abstract var color:String
//语言
abstract var language:String
//吃饭
abstract fun eat()
fun sleep(){
}
}
class CNHuman:Human(){
override var color: String="黄色"
override var language: String="中文"
override fun eat() {
println("使用筷子吃饭")
}
}
Kotlin跟java一样,是单继承多实现。
Kotlin中接口字段不能初始化,只能定义。可以有实现了的方法。
interface RideBike{
fun ride()
}
interface DriveCar{
var license:String
fun drive()
fun haha(){
println("haha")
}
}
class XiaoMing:CNHuman(),RideBike,DriveCar{
override var license: String="12345"
override fun drive() {
println("学会了开车")
}
override fun ride() {
println("学会了骑自行车")
}
//接口中已经实现,这里可以实现也可以不实现
override fun haha() {
println("hahhahahah")
}
}
abstract class Person
class XL:Person(){
fun sleep(){
println("躺着睡觉")
}
}
class XM:Person(){
fun sleep(){
println("站着睡觉")
}
}
val xm1=XM()
xm1.sleep()
val xm2:Person=XM()
if(xm2 is XM){
//java中的思路是判断后还要强转
//val newXM=xm2 as XM
//newXM.sleep()
//Kotlin中判断后就可以使用了
xm2.sleep()
}
//嵌套类
class OutClass{
var name="haha"
class InnerClass{
//无法访问name
}
}
//内部类
class OutClass{
var name="haha"
inner class InnerClass{
//可以访问name
}
}
//嵌套类创建
val innerClass=OutClass.InnerClass()
//内部类创建
val innerClass=OutClass().InnerClass()
class OutClass{
var name="haha"
inner class InnerClass{
var name="hehe"
fun sayHello(){
//访问的是自己的name
println(name)
//访问外部类name
println(this@OutClass.name)
}
}
}
open class Box<T>(thing:T){
}
//继承的时候知道具体类型
class FruitBox(thing: Fruit):Box<Fruit>(thing){
}
//继承的时候不知道具体类型
class SonBox<T>(thing: T):Box<T>(thing){
}
abstract class Fruit{
}
class Apple:Fruit(){
}
//定义对象的时候使用泛型
val box=Box("haha")
fun parseType(thing: T){
when(thing){
is Int-> println("Int类型")
else-> println("不知道")
}
}
parseType(10)
parseType("百里屠苏")
泛型上限:泛型只能是X类或者X类的子类。限制存放的类型。
//java里面必须通过反射获取泛型类型
val box1=Box("haha")
val box2=Box(10)
//class类型
val clz1=box1.javaClass.name
val clz2=box2.javaClass.name
//上面我们声明了Box泛型类,并实例化了两种类型的实例:String、Int,但是获取类名时却得到了相同的结果cn.gxh.day01.Box,这是因为在编译器擦除了泛型类型声明。
//解决泛型擦除方案:
//第一步:泛型前加reified
//第二步:方法前加上inline关键字
inline fun parseType(thing: T){
val name=T::class.java.name
println(name)
}
fun setFruitList(list:ArrayList<Fruit>){//接收的是Fruit的集合
println(list.size)
}
//下面我们创建Apple的集合传进去,发现不可以(Apple是Fruit的子类)
val list=ArrayList<Apple>()
setFruitList(list)//此处不可以
//out相当于java中的? extends
fun setFruitList(list:ArrayList<out Fruit>){//接收的是Fruit或者其子类的集合
println(list.size)
}
//out解决了我们遇到的问题,但是我们想传Fruit或者其父类的集合又怎么办呢?
//in相当于java中的? super
fun setFruitList(list:ArrayList<in Fruit>){//接收的是Fruit或者其父类的集合
println(list.size)
}
//如果我的ArrayList想接收任何类型的数据,可以使用泛型T,不过Kotlin提供了一个简单的方案,就是星号投射。
fun <T> setList(list:ArrayList<T>){
}
fun setList2(list:ArrayList<*>){
}