当前位置: 首页 > news >正文

网站开发入门习题网址修改

网站开发入门习题,网址修改,wordpress特别卡,国家建设部网站查询特殊类型异常机制 数据类型枚举类型匿名类、单例类和伴生对象匿名类单例类伴生对象 委托模式密封类型异常机制异常的使用异常的处理 数据类型 对于那些只需要保存数据的类型#xff0c;我们常常需要为其重写toString、equals等函数#xff0c;针对于这种情况下#xf… 特殊类型异常机制 数据类型枚举类型匿名类、单例类和伴生对象匿名类单例类伴生对象 委托模式密封类型异常机制异常的使用异常的处理 数据类型 对于那些只需要保存数据的类型我们常常需要为其重写toString、equals等函数针对于这种情况下Kotlin为我们提供了专门的数据类数据类不仅能像普通类一样使用并且自带我们需要的额外成员函数比如打印到输出、比较实例、复制实例等。 声明一个数据类非常简单 //在class前面添加data关键字表示为一个数据类 data class User(val name: String, val age: Int)数据类声明后编译器会根据主构造函数中声明的所有属性自动为其生成以下函数 .equals()/.hashCode().toString()生成的字符串格式类似于User(nameJohn, age42).componentN()与按声明顺序自动生成用于解构的函数.copy()用于对对象进行拷贝 我们可以来试试看 fun main() {val user1 User(小明, 18)val user2 User(小明, 18)println(user1) //打印出来就是格式化的字符串 User(name小明, age18)println(user1 user2) //true因为自动重写了equals函数val (name, age) user1 //自动添加componentN函数因此支持解构操作println(名称: $name, 年龄: $age) }当然为了确保生成代码的一致性和有效性数据类必须满足以下要求 主构造函数中至少有一个参数。主构造函数中的参数必须标记为val或var。数据类不能是抽象的、开放的、密封的或内部的。 此外数据类的成员属性生成遵循有关成员继承的以下规则 如果数据类主体中.equals() .hashCode()或.toString()等函数存在显式手动实现或者在父类中有final实现则不会自动生成这些函数并使用现有的实现。 data class User(val name: String, val age: Int) {//如果已经存在toString的情况下不会自动生成override fun toString(): String 我是自定义的toString }fun main() {val user User(小明, 18)println(user) //结果: 我是自定义的toString }如果超类型具有open .componentN()函数并返回兼容类型则为数据类生成相应的函数并覆盖超类型的函数。如果由于一些关键字导致无法重父类对应的函数会导致直接报错。 abstract class AbstractUser {//此函数必须是open的否则无法被数据类继承open operator fun component1() 卢本伟牛逼 }data class User(val name: String, val age: Int): AbstractUser() //自动覆盖掉父类的component1函数不允许为.componentN()和.copy()函数提供显式实现。 [外链图片转存中…(img-GVONt1pf-1728127119308)] 注意编译器会且只会根据主构造函数中定义的属性生成对应函数如果有些时候我们不希望某些属性被添加到自动生成的函数中我们需要手动将其移出主构造函数 data class Person(val name: String) {var age: Int 0 //age属性不会被处理 }此时生成的所有函数将不会再考虑age属性 fun main() {val person1 Person(John)val person2 Person(John)person1.age 10person2.age 20println(person1 person2: ${person1 person2})// person1 person2: trueprintln(person1 with age ${person1.age}: $person1)// person1 年龄为 10: Person(nameJohn)println(person2 with age ${person2.age}: $person2)// person2 年龄为 20: Person(nameJohn) }数据类自带一个拷贝对象的函数使用.copy()函数复制对象允许您更改其一些属性而其余的保持不变。此函数对上述User类的实现如下 data class User(val name: String, val age: Int)fun main() {val user User(小明, 18)val copyUser user.copy() //使用拷贝函数生成一个内容完全一样的新对象println(user copyUser)println(user copyUser) }在copy函数还可以在拷贝过程中手动指定属性的值 val user User(小明, 18) println(user.copy(age 17)) //结果为 User(name小明, age17)枚举类型 我们知道在Kotlin中有一个Boolean类型它只有两种结果要么为false要么为true这代表它的两种状态真和假。有些时候可能两种状态并不能满足我们的需求比如一个交通信号灯它具有三种状态红灯、黄灯和绿灯。 如果我们想要存储和表示自定义的多种状态使用枚举类型就非常合适 //在类前面添加enum表示这是一个枚举类型 enum class LightState {GREEN, YELLOW, RED //直接在枚举类内部写上所有枚举的名称一般全部用大写字母命名 }枚举类的值只能是我们在类中定义的那些枚举不可以存在其他的结果枚举类型同样也是一个普通的类只是存在值的限制。 要使用一个枚举类的对象可以通过类名直接获取定义好的枚举 fun main() {val state: LightState LightState.RED //直接得到红灯println(state.name) //自带name属性也就是我们编写的枚举名称这里是RED }同样的枚举类也可以具有成员 //同样可以定义成员变量但是不能命名为name因为name拿来返回枚举名称了 enum class LightState(val color: String) {GREEN(绿灯), YELLOW(黄灯), RED(红灯); //枚举在定义时也必须填写参数如果后面还要编写成员函数之类的其他内容还需在末尾添加分号结束fun isGreen() this LightState.GREEN //定义一个函数也是没问题的 }我们可以像普通类那样正常使用枚举类的成员 val state: LightState LightState.RED println(信号灯的颜色是: ${state.color}) println(信号灯是否可以通行: ${state.isGreen()})枚举类型可以用于when表达式进行判断因为它的状态是有限的 val state: LightState LightState.RED val message: String when(state) {LightState.RED - 禁止通行LightState.YELLOW - 减速通行LightState.GREEN - 正常通行 } println(message) //结果为: 禁止通行在枚举类中也可以编写抽象函数抽象函数需要由枚举自行实现 enum class LightState(val color: String) {GREEN(绿灯){override fun test() println(我是绿灯表示可以通过)}, YELLOW(黄灯) {override fun test() println(我是黄灯是让你减速不是让你踩油门加速过去)}, RED(红灯) {override fun test() println(我是红灯禁止通行)};abstract fun test() //抽象函数 }fun main() {val state: LightState LightState.REDstate.test() //调用函数: 我是红灯禁止通行 }如果枚举类实现了某个接口同样可以像这样去实现 interface Message {fun test() }enum class LightState(val color: String) : Message {GREEN(绿灯){override fun test() println(我是绿灯表示可以通过)}, YELLOW(黄灯) {override fun test() println(我是黄灯是让你减速不是让你踩油门加速过去)}, RED(红灯) {override fun test() println(我是红灯禁止通行)}; }enum class LightState(val color: String) : Message {GREEN(绿灯), YELLOW(黄灯), RED(红灯);override fun test() println() }枚举类也为我们准备了很多的函数 val state: LightState LightState.valueOf(RED) //通过valueOf函数以字符串名称的形式转换为对应名称的枚举 val state: LightState enumValueOfLightState(RED) //同上 println(state) println(state.ordinal) //枚举在第几个位置 println(state.name) //枚举名称val entries: EnumEntriesLightState LightState.entries //一键获取全部枚举得到的结果是EnumEntries类型的他是List的子接口因此可以当做List来使用 val values: ArrayLightState enumValuesLightState() //或者像这样以Array形式获取到所有的枚举 println(entries)匿名类、单例类和伴生对象 匿名类 有些时候可能我们并不需要那种通过class关键字定义的对象而是以匿名的形式创建一个临时使用的对象在使用完之后就不再需要了这种情况完全没有必要定义一个完整的类型我们可以使用匿名类的形式去编写。 val obj object { //使用object关键字声明一个匿名类并创建其对象可以直接使用变量接收得到的对象val name: String override fun toString(): String 我是一个匿名类 //匿名类默认继承于Any可以直接重写其toString } println(obj)可以看到匿名类除了没名字之外也可以定义成员只不过这种匿名类不能定义任何构造函数因为它是直接创建的这种写法我们也可以叫做对象表达式。 匿名类不仅可以直接定义也可以作为某个类的子类定义或是某个接口的实现 interface Person {fun chat() }fun main() {val obj: Person object : Person { //直接实现Person接口override fun chat() println(牛逼啊)}obj.chat() //当做Person的实现类使用 }interface Person open class Human(val name: String)fun main() {val obj: Human object : Human(小明), Person { //继承类时同样需要调用其构造函数override fun toString() 我叫$name //因为是子类直接使用父类的属性也是没问题的}println(obj) }可以看到平时我们无法直接实例化的接口或是抽象类可以通过匿名类的形式得到一个实例化对象。 我们再来看下面这种情况 interface KRunnable {fun invoke() //此类型是一个接口且只包含一个函数 }根据我们上面学习的用法如果我们想要使用其匿名类可以像这样编写 fun main() {val runnable object : KRunnable { //使用匿名类的形式编写KRunnable的实现类对象override fun invoke() {println(我是函数invoke的实现)} }runnable.invoke() }特别的对于只存在一个抽象函数的接口称为函数式接口或单一抽象方法SAM接口函数式接口可以有N个非抽象成员但是只能有一个抽象成员。对于函数式接口可以使用我们前面介绍的Lambda表达式来使代码更简洁 fun interface KRunnable { //在接口声明前面添加fun关键字fun invoke() }...fun main() {val runnable KRunnable { //支持使用Lambda替换println(我是函数invoke的实现)}runnable.invoke() }我们再来看下面这种情况 fun interface Printer {fun print() }fun test(printer: Printer) { //需要Printer接口实现对象printer.print() }我们在调用test时也可以写的非常优雅 fun main() {test { //直接Lambda一步到位println(Hello World)} }正是因为有了匿名类所以有些时候我们通过函数得到的结果可能并不是某个具体定义的类型也有可能是直接采用匿名形式创建的匿名类对象 open class Human(val name: String)fun test() object: Human(小明) { //返回的一个匿名类对象val age: Int 10override fun toString() 我叫$name }fun main() {println(test().name)println(test().age) //编译错误因为返回的类型是Human由于其匿名特性只能当做Human使用 }单例类 object关键字除了用于声明匿名类型也可以用于声明单例类。单例类是什么意思呢就像它的名字一样在整个程序中只能存在一个对象也就是单个实例不可以创建其他的对象始终使用的只能是那一个对象。 object Singleton { //声明的一个单例类private var name 你干嘛override fun toString() 我叫$name }fun main() {val singleton Singleton //通过类名直接得到此单例类的对象//不可以通过构造函数的形式创建对象println(singleton) }object Singleton {fun test() println(原神启动) }fun main() {Singleton.test() //单例定义的函数直接使用类名即可调用 }用起来与Java中的静态属性挺像的只不过性质完全不一样。单例类的这种性质在很多情况下都很方便比如我们要编写某些工具操作可以直接使用单例类的形式编写。 伴生对象 现在我们希望一个类既支持单例类那样的直接调用又支持像一个普通class那样使用这时该怎么办呢 我们可以使用伴生对象来完成实际上就是将一个单例类写到某个类的内部 class Student(val name: String, val age: Int) {//使用companion关键字在内部编写一个伴生对象它同样是单例的companion object Tools {//伴生对象定义的函数可以直接通过外部类名调用fun create(name: String, age: Int) Student(name, age)} }fun main() {//现在Student不仅具有对象的函数还可以通过类名直接调用其伴生对象通过的函数val student Student.create(小明, 18)println(student.toString()) }伴生对象在Student类加载的时候就自动创建好了因此我们可以实现直接使用。 委托模式 在有些时候类的继承在属性的扩展上起到了很大的作用通过继承我们可以直接获得某个类的全部属性而不需要再次进行编写不过现在有了一个更好的继承替代方案那就是委托模式在设计模式中也有提及名字虽然听着很高级但是其实很简单比如我们现在有一个接口 interface Base {fun print() }正常情况下我们需要编写一个它的实现类 class BaseImpl(val x: Int) : Base {override fun print() println(x) }现在我们换一个思路我们再来创建一个实现类 class Derived(val base: Base): Base { //将一个Base的实现类作为属性保存到类中同样实现Base接口override fun print() base.print() //真正去实现这个接口的实际上并不是当前类而是被拉进来的那个替身 }这就是一个非常典型的委托模型且大量实践已证明委托模式是实现继承的良好替代方案。 Kotlin对于这种模式同样给予了原生支持 interface Base {fun print() }class BaseImpl(val x: Int) : Base {override fun print() println(x) }class Derived(val b: Base): Base by b //使用by关键字将所有接口待实现操作委托给指定成员这样就可以轻松实现委托模式了。 除了类可以委托给其他对象之外类的成员属性也可以委托给其他对象 import kotlin.reflect.KPropertyclass Example {var p: String by Delegate() //属性也可以使用by关键字委托给其他对象 }// 委托的类 class Delegate { //需要重载属性的获取和设置两个运算operator fun getValue(thisRef: Any?, property: KProperty*): String {return $thisRef, 这里委托了 ${property.name} 属性}operator fun setValue(thisRef: Any?, property: KProperty*, value: String) {println($thisRef 的 ${property.name} 属性赋值为 $value)} }fun main() {println(Example().p) }不过自己去定义一个类来进行委托实在是太麻烦了Kotlin在标准库中也为我们提供了大量的预设函数 class Example {val p: String by lazy { 牛逼啊 } //lazy为我们生成一个委托对象这样在获取属性值的时候就会执行lazy里面的操作了看起来效果就像是延迟执行一样由于只能获取所以说只支持val变量 }fun main() {println(Example().p) }也可以设置观察者实时观察变量的变化 class Example {var p: String by Delegates.observable(我是初始值) {prop, old, new -println(检测到$prop 的值发生变化旧值$old - 新值$new)} }fun main() {Example().p 你干嘛 }属性也可以直接将自己委托给另一个属性 class Example(var a: String) {var p: String by ::a //使用双冒号来委托给其他属性 }fun main() {val example Example(你干嘛)println(example.p) }相信各位应该能猜到这样委托给其他属性当前属性的值修改会直接导致其他属性的值也会修改相反同样它们已经被相互绑定了。 属性也可以被委托给一个Map来进行存储 class User(map: MutableMapString, Any) {var name: String by map //直接委托给外部传入的Map集合var age: Int by map //变量的值从Map中进行存取override fun toString(): String 名称: $name, 年龄: $age }fun main() {val map: MutableMapString, Any mutableMapOf(name to John Doe,age to 25)val user User(map)println(user) //名称: John Doe, 年龄: 25map[age] 10 //映射的值修改会直接影响变量的值println(user) //名称: John Doe, 年龄: 10 }注意在使用不可变的Map时只能给val类型变量进行委托因为不可修改。 密封类型 有些时候我们可能会编写一些类给其他人使用但是我们不希望他们随意继承使用我们提供的类我们只希望在我们提供的框架内部自己进行使用这时我们就可以将类或接口设定为密封的。 密封类的所有直接子类在编译时都是已知的。不得在定义密封类的模块和包之外出现其他子类。例如第三方项目无法在其代码中扩展您的密封类。因此密封类的每个实例都有一个来自预设好的类型且该类型在编译该类时是已知的。 package com.testsealed class A //声明密封类很简单直接添加sealed关键字即可 sealed class B: A() //密封类同一个模块或包中可以随意继承并且子类也可以是密封的当我们在其他包中使用这个密封类在其他包或模块中无法使用 class C: A() //编译错误不在同一个模块fun main() {val b B() //编译错误不可以实例化 }密封类将类的使用严格控制在了模块内部包括密封接口及其实现也是如此一旦编译了具有密封接口的模块就不会出现新的实现类。 从某种意义上说密封类类似于枚举类枚举类型的值数量也受到限制由我们自己定义但每个枚举变量仅作为单个实例存在而密封类的子类可以有多个实例每个实例都有自己的状态。密封类本身也是抽象的它不能直接实例化并且可以具有abstract成员 sealed class A sealed class B: A() {abstract fun test() }密封类继承后也可以使其不继续密封让外部可以正常使用 sealed class A class B: A() class C: A() class D: A() //不添加sealed关键字使其不再密封但是由于类A是密封的因此所有继承自A的类只能是我们自己写的别人无法编写继承A的类除非我们将某个继承A的类设定为open特性允许继承。因此这也进一步证明密封类在一开始就确定了有哪些子类。 由于密封类能够确定所以在使用when进行类型判断时也是有限的 fun main() {val a: A C()when(a) {is B - println(是B)is C - println(是C)is D - println(是D)} }密封类的应用场景其实远不止这些由于篇幅有限这里就不展开讲解了。 异常机制 在理想的情况下我们的程序会按照我们的思路去运行按理说是不会出现问题的但是代码实际编写后并不一定是完美的可能会有我们没有考虑到的情况如果这些情况能够正常得到一个错误的结果还好但是如果直接导致程序运行出现问题了呢 我们来看下面这段代码 fun main() {test(1, 0) //当b为0的时候还能正常运行吗 }private fun test(a: Int, b: Int): Int {return a / b //没有任何的判断而是直接做计算 }1怎么可能去除以0呢数学上有明确规定0不能做除数所以这里得到一个异常 那么这个异常到底是什么样的一种存在呢当程序运行出现我们没有考虑到的情况时就有可能出现异常或是错误它们在默认情况下会强行终止我们的程序。 异常的使用 们在之前其实已经接触过一些异常了比如数组越界异常空指针异常算术异常等他们其实都是异常类型我们的每一个异常也是一个类他们都继承自Throwable类异常类型本质依然类的对象但是异常类型支持在程序运行出现问题时抛出也就是上面出现的红色报错也可以提前声明告知使用者需要处理可能会出现的异常 每个异常对象都包含一条消息、一个堆栈跟踪和一个可选原因。 我们自己也可以抛出异常要抛出异常对象请使用throw出表达式 fun main() {//Exception继承自Throwable类作为普通的异常类型throw Exception(牛逼) }可以看到控制台出现了下面的报错 所以我们平时看到的那些丰富多彩的异常其实大部分都是由程序主动抛出的。 我们也可以依葫芦画瓢自定义我们自己的异常类 class TestException(message: String) : Exception(message)fun main() {throw TestException(自定义异常) }是不是感觉很简单异常的出现就是为了方便我们快速判断程序的错误。我们可以在异常打印出来的栈追踪信息中得到当前程序出现问题的位置 这里指示的很明确是我们的Main.kt文件第四行代码出现了异常。 异常的处理 当程序没有按照我们理想的样子运行而出现异常时JVM平台下默认会交给JVM来处理JVM发现任何异常都会立即终止程序运行并在控制台打印栈追踪信息现在我们希望能够自己处理出现的问题让程序继续运行下去就需要对异常进行捕获比如 val array arrayOf(1, 2, 3) println(array[3]) //数组长度根本没有4很明显这里会出现异常现在我们希望能够手动处理这种情况即使发生异常也要继续下去我们可以使用try-catch语句块来完成 fun main() {try { //使用try-catch语句进行异常捕获val array arrayOf(1, 2, 3)println(array[3])} catch (e: ArrayIndexOutOfBoundsException) {//因为异常本身也是一个对象catch中实际上就是用一个局部变量去接收异常}println(程序继续正常运行) }我们可以将代码编写到try语句块中只要是在这个范围内发生的异常都可以被捕获使用catch关键字对指定的异常进行捕获这里我们捕获的是ArrayIndexOutOfBoundsException数组越界异常 可以看到当我们捕获异常之后程序可以继续正常运行并不会像之前一样直接结束掉。 注意catch中捕获的类型只能是Throwable的子类也就是说要么是抛出的异常要么是错误不能是其他的任何类型。 我们可以在catch语句块中对捕获到的异常进行处理 fun main() {try { //使用try-catch语句进行异常捕获val array arrayOf(1, 2, 3)println(array[3])} catch (e: ArrayIndexOutOfBoundsException) {e.printStackTrace(); //打印栈追踪信息println(异常错误信息e.message); //获取异常的错误信息}println(程序继续正常运行) }当代码可能出现多种类型的异常时我们希望能够分不同情况处理不同类型的异常就可以使用多重异常捕获 try {//.... } catch (e: Exception) { //父类型在前会将子类的也捕获} catch (e: NullPointerException) { //因为NullPointerException是Exception的子类型永远都不会进入这里} catch (e: IndexOutOfBoundsException) { //永远都不会进入这里}最后当我们希望程序运行时无论是否出现异常都会在最后执行任务可以交给finally语句块来处理 try {//.... } catch (e: Exception) {} finally {println(lbwnb) //无论是否出现异常都会在最后执行 }注意try语句块至少要配合catch或finally中的一个。 try也可以当做一个表达式使用这意味着它可以有一个返回值 fun main() {val input readln()val a: Int? try { input.toInt() } catch (e: NumberFormatException) { null }println(a) }针对于空类型我们也可以在判断为空时直接抛出异常 val s person.name ?: throw IllegalArgumentException(Name required)
http://www.w-s-a.com/news/701752/

相关文章:

  • 网站logo提交学网站开发技术
  • 跨境电商平台网站建设广州西安官网seo推广
  • 我和你99谁做的网站小程序制作第三方平台
  • 建设银行网站用户名鹤岗网站seo
  • 做一元夺宝网站需要什么条件西安市做网站的公司
  • 零基础建设网站教程郑州做网站推广价格
  • 平面设计免费素材网站新开三端互通传奇网站
  • ppt模板免费下载 素材医疗seo网站优化推广怎么样
  • 课程网站怎么做wordpress文章改背景色
  • 网络营销从网站建设开始卖汽车配件怎么做网站
  • 手机商城网站制作公司济南想建设网站
  • .net 建网站网站网站做员工犯法吗
  • 电子商务网站建设说课稿棕色网站设计
  • 怎么做律所的官方网站红塔网站制作
  • 装一网装修平台官网惠州seo按天付费
  • 湖南建设监理报名网站东莞模块网站建设方案
  • 网站建设小组个人主页html源码
  • 响应式网站检测工具营销公司业务范围
  • 网站源码如何安装做游戏课程网站
  • 选服务好的网站建设亚洲砖码砖专区2022
  • 网站快速查找wordpress 悬停 图片 文字
  • 网站续费 多久想自己做网站该学些什么
  • 可以自己做网站wordpress英文写作插件
  • 国外可以做会员网站的网站怎么查百度竞价关键词价格
  • 新站网站建设亚马逊关键词
  • 电商网站前端架构设计上海市建设工程安全生产协会网站
  • 东莞企业免费模版网站建设一般网站维护要多久
  • 著名建筑设计网站常州制作网站价格
  • 食品营销型网站广东省广州市白云区
  • 如何做网站哪个站推广描述对于营销型网站建设很重要飘红效果更佳