app开发者平台在数字化时代的重要性与发展趋势解析
672
2022-09-02
ScalaNote05-类、属性、方法
类
通俗定义
**看一个实际案例:**张老太养了只猫猫:一只名字叫小白,今年3岁,白色。还有一只叫小花,今年10岁,花色。请编写一个程序,当用户输入小猫的名字时,就显示该猫的名字,年龄,颜色。如果用户输入的小猫名错误,则显示 张老太没有这只猫猫。
类:
管理多个不同类型的数据-[属性](如猫名字、年龄、颜色)对属性进行操作-[方法](如猫可以run、cry等等)
类是抽象的,概念的,代表一类事物,比如人类,猫类…对象是具体的,实际的,代表一个具体事物,如上面案例中的小花、小白。类是对象的模板,对象是类的一个个体,对应一个实例。
Scala定义类
在Scala中,我们可以这样定义一个类
class 类名 { 类体}
属性
类体中定义类的属性和类的方法,其中类的属性可以为值数据类型,也可是引用类型,比如cat类的age属性。
属性的定义语法同变量,示例:[访问修饰符] var 属性名称 [:类型] = 属性值
class cat{ val name:String = "" var age:Int=0 private var color:String="white" var color2 = "color1="+color}
defined class cat
以上面的cat类为例:定义了name、age、color三个属性,其中color为私有属性,对象中不可以引用,只能在类内部访问。如果需要一个只读属性,可以用val。
val catx = new cat()
catx: cat = cat@1aa638ff
catx.age =2
catx.age: Int = 2
catx.name
res56: String = ""
catx.name ="Name can not change"
上面报错,name只能访问,不可修改
catx.color2
res57: String = color1=white
catx.color
class Person { var age : Int = 10 var sal = 8090.9 //给属性赋初值,省略类型,会自动推导 var Name = null // Name 是什么类型? null类型 var address : String = null // address还是string var hiscat = new cat()}
defined class Person
也可以不指定属性值,而用"_"代替。如下所示:
class Dog{ var name:String=_ //默认null var age:Int=_ //默认0 var isDog:Boolean=_ //默认false var eatamount:Float=_ //默认0.0}
defined class Dog
val puppy = new Dog()
puppy: Dog = Dog@10e68ad8
println("puppy.name="+puppy.name+"\n" +"puppy.age="+puppy.age+"\n" +"puppy.isDog="+puppy.isDog+"\n" +"puppy.eatamount="+puppy.eatamount)
puppy.name=nullpuppy.age=0puppy.isDog=falsepuppy.eatamount=0.0
对象
什么是对象,引用下菜鸟教程:类是对象的抽象,而对象是类的具体实例。类是抽象的,不占用内存,而对象是具体的,占用存储空间。类是用于创建对象的蓝图,它是一个定义包括在特定类型的对象中的方法和变量的软件模板。
在scala中创建对象的语法如下:
val | var 对象名 [:类型] = new 类型()
对于第一点,一般情况下使用val即可,第2点则需要注意,如下例,Child是Person子类,如果通过new Child()新建一个对象leo,并且希望类型为Person则必须指定类型为Person,否则默认为Child。这个用法有点儿骚气~
class Person{ var name="jack"}class Child extends Person{ var age=6}
defined class Persondefined class Child
val leo1 = new Child()val leo2:Person = new Child()
leo1: Child = Child@44f3c0dleo2: Person = Child@250716e
leo1.getClass
res6: Class[_ <: Child] = class Child
leo2.getClass
res5: Class[_ <: Person] = class Child
对象访问属性很简单,对象.属性即可
leo1.age
res7: Int = 6
leo2.age
类和对象的内存分配机制
类和对象的内存分配机制,可以通过一张图了解:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5pTZDPaB-1582286688619)(…/Picture/pic02.png)]
即新建一个对象p1,再将p1赋给p2,此时两个变量都指向同一个对象,其实有点像python的浅copy,如果其中有个值发生变化,两者都变。看一个例子:
class Dog{ var name = "jack"}val p1 = new Dog()var p2 = p1println("p1.name="+p1.name+"\n"+"p2.name="+p2.name)p2.name = "john"println("p1.name="+p1.name+"\n"+"p2.name="+p2.name)
p1.name=jackp2.name=jackp1.name=johnp2.name=johndefined class Dogp1: Dog = Dog@ed3b2ffp2: Dog = Dog@ed3b2ffp2.name: String = john
方法
方法和函数定义差不多,我自己理解,方法就是一个对象的函数。看个例子方便理解
class Dog{ var name = "jack" def bark(name:String){ println("I am "+name+"\n"+"I can wangwangwang") }}val p1 = new Dog()p1.bark(p1.name)
I am jackI can wangwangwangdefined class Dogp1: Dog = Dog@3b70573a
这里定义了bark的方法,对象调用这个方法是把名字传进去即可。
构造器
在上例中,如果我们在new Dog时就初始化一个name属性,该怎么处理呢?这里可以使用构造器(constructor),又叫构造方法,它是类的一种特殊的方法,它的主要作用是完成对新对象的初始化。
主构造器
构造器又分为主构造器和辅助构造器,主构造器是通过类名后面跟的括号里加参数列表来定义,辅助构造器是通过关键字this定义。
class 类名(形参列表) { // 主构造器 // 类体 def this(形参列表) { // 辅助构造器 } def this(形参列表) { //辅助构造器可以有多个... }}
class Student(inName:String="jfdja",inAge:Int){ val name = inName val age = inAge println("Name = "+inName+ "; Age = "+age)} val student1 = new Student("Jacky",19)val student2 = new Student(inAge=18,inName="Jack")val student3 = new Student(inAge=20)
Name = Jacky; Age = 19Name = Jack; Age = 18Name = jfdja; Age = 20defined class Studentstudent1: Student = Student@2b6f5b1bstudent2: Student = Student@370d1fffstudent3: Student = Student@34bbfa45
主构造器会执行类定义中的所有语句,当我们没有指定参数名时,按照从左往右顺序赋值,如果变量类型不一致会报错。也可以带上参数名,此时顺序可不一致。这样看,类的参数初始化和函数参数赋值好像也差不多,参数也可以有默认值,这样是不规范?
辅助构造器
辅助构造器有些细节我自己也没有搞清楚,简单记录下韩老师讲的内容吧。 辅助构造器名称为this,多个辅助构造器通过不同参数列表进行区分,比如参数的个数不一样或者参数的类型一致。
下面的内容不保证正确,代码是能跑通。看下面代码,如果使用辅助构造器,则在辅助构造器的第一行需要调用主构造器
这里把主构造器的两个参数也放到辅助构造器里了,第一行直接调用this(inName,inAge)如果辅助构造器参数不包含inName,inAge,则需要this(“jacky”,10)这样调用
class Person(inName: String, inAge: Int) { var name: String = inName var age: Int = inAge age += 10 println("Main constructor \n"+"name =" +name+"\n"+"age =" +age) def this(inName: String, inAge: Int,name: String) { this(inName,inAge) this.name = name println("Auxiliary constructor \n"+"name =" +name+"\n"+"age =" +age) } def showInfo(): Unit = { println("Person Info:") println("name=" + this.name) println("age=" + this.age) }}
defined class Person
val eve = new Person("abc",20,"cba")
Main constructor name =abcage =30Auxiliary constructor name =cbaage =30eve: Person = Person@577b4310
从代码执行顺序上可以看出:
传入了(“abc”,20,“cba”),根据参数个数和参数类型,调用辅助构造器辅助构造器第一行调用主构造器,因此完成print操作之后在执行辅助构造器里面的代码,对name重赋值,并且print
class Person(inName: String, inAge: Int) { var name: String = inName var age: Int = inAge age += 10 println("Main constructor \n"+"name =" +name+"\n"+"age =" +age) def this(name: String) { this("inName",10) this.name = name println("Auxiliary constructor \n"+"name =" +name+"\n"+"age =" +age) } def showInfo(): Unit = { println("Person Info:") println("name=" + this.name) println("age=" + this.age) }}
defined class Person
new Person("abc")
Main constructor name =inNameage =20Auxiliary constructor name =abcage =20res5: Person = Person@69af6740
再看一个特殊的case:
class B{ println("B--->")}class A extends B{ println("A--->") def this(name:String){ this println("A NAME = "+name) }}new Aprintln("--------lines--------")new A("AA")
B--->A--->--------lines--------B--->A--->A NAME = AAdefined class Bdefined class Ares8: A = A@18572a9c
上面的code可以看到,当A继承B时,新建A类对象时:
先调用父类的主构造器,输出"B—>"再调用A的主构造器,输出"A—>"最后执行辅助构造器中的println("A NAME = "+name)
属性的高级部分
这部分涉及下面三个点:
class Boy(inName:String,val inAge:Int,var inSex:String){ //println("Love U,Simple") def showInfo(){ println("Boy Info:") println("name=" + inName) println("age=" + inAge) println("inSex=" + inSex) }}val x = new Boy("jack",16,"male")x.inSex ="female"x.showInfo()
Love U,SimpleBoy Info:name=jackage=16inSex=femaledefined class Boyx: Boy = Boy@5ed73402x.inSex: String = female
结合上面的代码,即:
主构造器里的var inSex可以被修改而val inAge 可读不可写但是这俩都编程了对象的属性
Bean属性
JavaBeans规范定义了Java的属性是像getXxx()和setXxx()的方法。许多Java工具(框架)都依赖这个命名习惯。为了Java的互操作性。将Scala字段加@BeanProperty时,这样会自动生成规范的 setXxx/getXxx 方法。这时可以使用 对象.setXxx() 和 对象.getXxx() 来调用属性。 注意:给某个属性加入@BeanPropetry注解后,会生成getXXX和setXXX的方法并且对原来底层自动生成类似xxx(),xxx_$eq()方法,没有冲突,二者可以共存。
java的东西我不懂,直接看个例子吧
import scala.beans.BeanPropertyclass Car { @BeanProperty var brand: String = "Audi"}val x = new Car()println("x.name = "+x.brand)println("x.getBrand = "+x.getBrand)x.setBrand("Mercedes Benz")println("x.getBrand = "+x.getBrand)
x.name = Audix.getBrand = Audix.getBrand = Mercedes Benzimport scala.beans.BeanPropertydefined class Carx: Car = Car@34febf56
稀里糊涂地看了一天了,没有java基础学scala还挺费劲~Whatever,还是要好好学习!
2020-02-21 于南京市栖霞区
版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。
发表评论
暂时没有评论,来抢沙发吧~