在对于仓颉有了初步了解之后,我们自然会想在我们之前所学习,编写的简单代码上添加一些其他的功能,今天我们就来讲几个重要的小功能
封装
为了提高数据访问的安全性,我们可以使用访问修饰符private。那么我们应该通过什么方法提高呢,我们有两种方法:1.通过方法 2.通过属性设计器。
参考如下代码
package cjchapter4.chapter1
public class User {
private var a1: Int64 = 0
public func getA1(): Int64 {
this.a1
}
public func setA1(a1: Int64): Unit {
this.a1 = a1
}
public mut prop propA1:Int64{
get(){
this.a1
}
set(a1)
{
if(a1>0)
{
this.a1 =a1
}
else{
println("传递的数据:${a1},不能够设置值")
}
}
}
}
当然啦,在使用上述代码的时候,记得在main,cj里面把主体函数写好哦
继承
很多同学在第一次学完仓颉,并尝试自己去蜀绣额属于自己的第一个代码的时候,通常都会遇到一个问题,就是在编写的过程中代码里面会出现好多好多的重复的变量,方法以及属性设计器。所以大多数同学的代码会看上去杂乱不堪。这个时候呢,我们就需要用到仓颉语言中的继承方法啦。
首先我们要了解仓颉的继承关键字是什么。仓颉的继承的关键字:<:
那么继承的作用是什么呢?减少子类中冗余重复的变量和方法、属性设计器
特别要注意同名变量的继承问题,参照如下代码
package cjchapter4.chapter2
(1)
public open class Base{
private var a1 : Int64 =10
public func getA1():Int64{
this.a1
}
}
public class Son <: Base{
(2)
var a1 : Int64 =100
}
public func exec1()
{
var son :Son = Son()
println("${son.a1}")
var base :Base =Base()
println("base.a1的值为:${base.getA1()}")
}
上述代码中有两处需要解释一下:
(1)仓颉中类要被继承,要显示的使用关键字open
(2)子类中不能够声明和父类同名的变量。加了private访问修饰符,所谓的同名变量是可以通过编译的,但是父类的同名变量,没有被子类继承
那么有同学会问,我们一个怎么书写减少子类重复的代码呢
我们可以看看下面的代码
package cjchapter4.chapter3
public open class Emp{
var name : String = ""
var age :Int16 = 0
public func showInfo()
{
println("群友的姓名是:${name},年龄是:${age}")
}
}
public class Manager <:Emp{
}
public class Worker <:Emp{
}
public func exec2()
{
var m : Manager = Manager()
m.name = "蓝星悼"
m.age =20
m.showInfo()
}
同样的我们对以上代码做一些注释:
(1)private-default-protected-public 访问修饰符的大小
接下来我们要学习本次的重要内容,也就是多态。
多态
首先我们要了解多态的定义:同一个方法名,不同的实现的结果。
多态呢,有两个具体的体现:1.方法重载 2.方法重写
那么我们就先来讲讲方法重载:
相同的方法名,不同的参数列表(参数的个数或参数的类型),与返回值类型无关,与static关键字无关。决定调用哪个重载的方法,是由参数决定的,所以我们把方法重载也叫做编译时多态。
package cjchapter4.chapter3
//private-default-protected-public 访问修饰符的大小
public open class Emp{
var name : String = ""
var age :Int16 = 0
public func showInfo()
{
println("群友的姓名是:${name},年龄是:${age}")
}
public func eat():Unit
{
println("正常的聊天")
}
public func eat(name:String):String
{
println("聊天的内容可以自行定义:${name}")
name
}
}
public class Manager <:Emp{
}
public class Worker <:Emp{
}
public func exec2()
{
var m : Manager = Manager()
m.name = "蓝星悼"
m.age =20
m.showInfo()
m.chat("早早早")
}
如上代码就是对方法重载最好的体现。
接下来我们来看看方法重写:
在继承关系中,子类和父类具有相同的方法名,相同的参数列表(参数的个数和类型),相同的返回值类型,与static无关。决定调用哪个重名的方法,是由创建的对象来决定的。
动态绑定机制,一个父类指向多个子类的现象,也就是大类型指向多个子类型的现象。
参考如下代码
package cjchapter4.chapter3
public open class Emp{
var name : String = ""
var age :Int16 = 0
public func showInfo()
{
println("群友的姓名是:${name},年龄是:${age}")
}
public func eat():Unit
{
println("正常的聊天")
}
public func eat(name:String):String
{
println("聊天的内容可以自行定义:${name}")
name
}
public open func run():Unit{
println("父类base的run方法-正常跑")
"111"
}
}
public class Manager <:Emp{
public override func run():Unit{
println("子类Manager的run方法->慢慢跑")
}
}
public class Worker <:Emp{
}
public func exec2()
{
var m : Manager = Manager()
m.name = "蓝星悼"
m.age =20
m.showInfo()
m.chat("早早早")
// 方法重写,调用哪个具体的方法,是由创建的对象来决定的
var m1 :Emp =Manager()
m1.run()
var m2 :Emp =Emp()
m2.run()
}
同样的上述代码中有两点需要注意的:
(1)private-default-protected-public 访问修饰符的大小
(2)在类中的方法,如果是不标注open关键字,子类是不能够重写的
抽象
具体的体现是抽象类和接口,为什么有抽象类和接口,其实一句话:就是为了加强多态,加强动态绑定,就是为了方法重写。
抽象类和接口,都不能实例化,都属于大类型,一定会有子类,怎么去实例化呢?通过子类完成实例化。 抽象类和接口绑定子类,抽象方法被子类重写,运行时多态。
抽象类被继承后,抽象类要声明成public,抽象类中可以有构造函数,抽象类中的构造函数要被子类依赖(显示的,隐私的)
抽象类被继承后,抽象类要声明成public
package cjchapter4.chapter4
public abstract class Base{
//抽象类中可以有构造函数 主构造函数
public Base(a1:Int64)
{
}
public func open():Unit
}
public class Son <: Base{
public Son()
{
super(10)
}
public func open():Unit{
}
}
package cjchapter4.chapter4
public abstract class Base {
//抽象类中可以有构造函数 主构造函数
public Base(a1: Int64) {
}
public func open(): Unit
}
public class Son1 <: Base {
public Son1() {
super(10)
}
public func open(): Unit {
}
}
public class Son2 <: Base {
public Son2() {
super(10)
}
public func open(): Unit {
}
}
public func exec4() {
// 抽象类不能被实例化
//var base :Base =Base(20)
// 父类base对象绑定
var base1: Base = Son1()
var base2: Base = Son2()
// 引用类型赋值
base1 = base2
}
接口被继承,接口也必须声明成public,接口中不能有构造函数,不能去实例化,通过子类完成实例化
package cjchapter4.chapter5
public interface A{
}
public class UserA <:A{
}
此外,有两点需要我们特别注意
仓颉的方法的参数都是不可变变量
package cjchapter4.chapter6
public class User{
var a1:Int64 = 0
public init(a1:Int64) {
//仓颉方法中参数是不可变量,不能修改其值
//a1 =100
//var a2 =a1
this.a1 = a1
}
public func changeA1()
{
//仓颉语言不支持前置的++运算,只支持后置++
this.a1 ++
}
public func changeA1( u1:User)
{
var u2 :User =User(200)
//u1是一个不可变变量
//u1 = u2
//这样是可以的
u2 = u1
println("${u2.a1}")//101
}
}
public func exec6()
{
var u1 :User =User(100)
u1.changeA1()
println("u1.a1的值为:${u1.a1}")//101
u1.changeA1(u1)
}
接口和抽象类的属性设计器被重写时,不能够做任何的修改
package cjchapter4.chapter8
public open class Base {}
public class Son <: Base {}
public interface UserInterfaces {
//接口中声明了抽象的属性设计器
public mut prop propValue: Base
}
public class UserClass <: UserInterfaces {
//var son =Son() // 这样是不可以的
//接口中对属性设计器,不能做任何的继承的修改
var son = Base()
public mut prop propValue: Base {
get() {
son
}
set(value) {
this.son = value
}
}
}
package cjchapter4.chapter9
public open class Base {}
public class Son <: Base {}
public abstract class ABUser {
//接口中声明了抽象的属性设计器
public mut prop propValue: Base
public open func show(): Unit
}
public class User <: ABUser {
var son = Base()
public mut prop propValue: Base {
get() {
son
}
set(value) {
this.son = value
}
}
public override func show(): Unit {
}
}
但是方法重写可以杯修改,而他之所以可以被修改,是基于继承关系
package cjchapter4.chapter10
public open class Base{
}
public class Son <:Base{
}
public interface UserInterface{
public func execFun():Base
}
public class User <:UserInterface{
public func execFun():Base{
Son()
}
}
至此我们学习了仓颉语言中的封装,继承,多态和抽象,要多加练习并要牢牢掌握,在今后的学习中我们可以给我们的这一个小小的简单的仓颉代码加上许许多多的新功能。相信经过学习,咱们一定能搞定仓颉语言。