Scala教程(六)类、属性和对象字段
1 类(class)
1.1 定义类
Scala是一种纯粹的面向对象编程语言,而又无缝地结合了命令式和函数式的编程风格。在面向对象的语言有两个重要的概念:类(class)和对象(object也被称为实例—instance),其中类是对象的抽象。可以把类理解为模板,对象才是真正的实体。
代码示例:
class Person() {
// 定义age 为类私有属性
private var age = 0; //必须初始化字段
// 定义方法 age +=1,默认方法公有
defincrement(){age += 1}
// 将age中的值赋值到current
def current =age;
}
def main(args:Array[String]): Unit = {
val person = new Person();
// person.age=10; //私有的不能设置值
person.increment();
person.increment();
println(person.current);
}
输出结果:2
1.2 getter/setter方法
类中的字段自动带有getter/setter方法。你也可以用定制的getter/setter方法替换掉原来的字段的字定义,而不必修改使用的客户端——这就是所谓的“统一访问原则”。
代码示例:
class Student {
// 声明age属性,默认生成get\set方法,同时默认age是private
var age = 0;
//私有的变量只有getter方法没有setter方法
// private[this]只能在当前class中使用,不能在其它方法中使用
private[this] var privateWeight = 120;
// val private[this]修饰的变量只能当前类使用
var name = "Scala";
def weight = privateWeight;
// 添加 private [this] 关键字后只在本类中使用
// def isFat(other:Student) = privateWeight < other.privateWeight;
}
def main(args: Array[String]): Unit = {
val student = new Student();
// 赋值时调用student.age的set方法 def age_=(x$1: Int): Unit
student.age =20
// 调用student.age,其实上调用get方法:def age: Int
println(student.age);
}
输出结果:20
1.3 主构造函数
Scala中,每个类都有主构造函数,主构造函数并不以this的方式定义,而是与类定义交织在一起,主构造器的参数被编译成字段。
代码示例:
class Computer /*主构造函数*/() {
// 类级别声明的变量必须赋值
var display :String ="LED";
// 私有属性
private var price = 3000;
// 私有属性,只能在本类中使用
private[this] var cpu = "四核";
def this(display:String){
// 最终都需要调用默认this()默认构造
this();
this.display =display;
}
defsayConfig(){
println("显示器:"+this.display+",价格:"+this.price+",cpu:"+this.cpu);
}
}
def main(args:Array[String]): Unit = {
var computer = new Computer();
computer.display = "3D";
computer
computer.sayConfig();
}
输出结果:显示器:3D,价格:3000,cpu:四核
1.4 辅助构造函数
Scala可以有任意多的构造函数,除主构造函数外还有任意多的辅助构造器:
1.辅助类的构造器的名称为this(如果与类名相同修改类名的时候不方便)
2.每一个辅助构造器都必须以一个对先前已定义的其它辅助或主构造器的调用开始。
代码示例:
class Moblie /*主构造函数*/private /*私有构造器*/(val brand:String,val price:Int){
// 定义变量
var networkType :String ="";
// 重载构造函数
def this(brand:String,price:Int,networkType:String){
this(brand,price);
this.networkType =networkType;
}
}
def main(args: Array[String]): Unit ={
// // 在构造函数加private修饰,构造函数将不可用
// var moblie = new Moblie("SAMSUNG",4500);
// moblie.networkType = "三星"
//
// // 在构造函数加private修饰,构造函数将不可用
// var moblie = new Moblie("SAMSUNG",4500);
// println("品牌:"+moblie.brand);
//
var moblie = new Moblie("SAMSUNG",4500,"3G网络通信");
println("品牌:"+moblie.brand);
println("价格:"+moblie.price);
println("通信类型:"+moblie.networkType);
}
1.5 内部类
Scala可以将一个类定义在另一个类里面或者一个方法里面,这样的类称为内部类。
代码示例:
// class Outer{outer=>语法使得outer变量指向Outer.this。对这个变量,可以 使用任何合法的名称。
class Outer(val name:String){ outer =>
class Inner(val name:String){
deffoo(b:Inner) = println("Outer:"+outer.name + ",Inner:"+b.name)
}
}
def main(args:Array[String]): Unit = {
// scala内部类,隶属于外部类实体本身
val outer1 = new Outer("Spark");
val outer2 = new Outer("Hadoop");
val inner1 = new outer1.Inner("scala");
val inner2 = new outer2.Inner("java");
inner1.foo(inner1);
inner2.foo(inner2);
}
输出结果:
Outer:Spark,Inner:scala
Outer:Hadoop,Inner:java
参数生成的字段及方法:
构造函数 |
生成的字段方法 |
name:String |
对象私有字段。如果没有方法使用name,则没有该字段。 |
Private val/var name String |
私有字段,私有getter/setter方法。 |
Val/var name:String |
私有字段,公有getter/setter方法 |
2 对象(object)
2.1 伴生对象
在Java或C++中即有实例方法又有静态方法。在Scala可以通过类与同名的“伴生”对象来达到同样的目的。
类和它的伴生对象可以互相访问私有特性。它们必须在于同一个源文件中。
代码示例:
// 伴生对象(一般情况下,做为伴生类的静态区域)
object University {
private var studentNo = 0;
def newStudentNo(): Int = {
studentNo = studentNo + 1
studentNo
}
}
// 伴生类
class University {
var id = University.studentNo;
private var number = 0;
def adClass(number: Int) {
this.number += number;
}
}
2.2 apply方法
使用apply方法会省去new关键字使用起来更方便。通常apply方法返回的是伴生类的类的对象。
// 伴生类
class ApplyTest(){
def apply() = println("I am into Spark so much!!!");
def haveAtry(){
println("Have a try on apply!");
}
}
// 伴生对象-apply中的应用
object ApplyTest {
def apply (): ApplyTest = {
println("I am into Scala to much!!!")
new ApplyTest
}
}
// 方法调用
object Oop {
def main(args: Array[String]): Unit = {
val a = ApplyTest();
a.haveAtry();
println(a());
}
}
输出结果:
I am into Scala to much!!!
Have a try on apply!
I am into Spark so much!!!
()
3 面向对象编程(OOP)
3.1 scala继承(extends)
子类继承父类的特征和行为,使得子类具有父类的各种属性和方法。或子类从父类继承方法,使得子类具有父类相同的行为。
特点:在继承关系中,父类更通用、子类更具体。父类具有更一般的特征和行为,而子类除了具有父类的特征和行为,还具有一些自己特殊的特征和行为。在继承关系中。父类和子类需要满足is-a的关系。子类是父类。
表示父类和子类的术语:父类和子类、超类和子类、基类和派生类。
代码示例:
class Animal(val name:String,val age:Int){
println("The primaryconstructor of Animal!!!")
// 颜色-白色
val color= "white";
// 睡觉4小时
def sleep = "4hours";
// 重写toString方法
override deftoString() = "I am a Animal Animal.toString method";
}
class Dog(name:String,age:Int,val height:String)
extends Animal(name,age) {
println("This is thesubClass of Animal,Primaryconstructor of Dog!!!")
// 重写color 属性
override val color= "yellow";
override deftoString() = "I am a Dog !"+ super.sleep;
}
//方法调用
def main(args:Array[String]): Unit = {
val dog = new Dog("Poodle",6,"10cm");
println(dog.color);
println(dog.height);
println(dog.toString());
}
输出结果:
The primary constructor of Animal!!!
This is the subClass of Animal,Primary constructor ofDog!!!
yellow
10cm
I am a Dog !4 hours
3.2 抽象类(abstractclass)
使用了关键词abstract声明的类叫作“抽象类”。如果一个类里包含了一个或多个抽象方法,类就必须指定成abstract(抽象)。“抽象方法”,属于一种不完整的方法,只含有一个声明,没有方法主体。
代码示例:
// 抽象类
abstract classSuperTeacher(var name:String){
// 定义抽象id 属性
var id : Int;
// 定义抽象age 属性
var age: Int;
// 定义抽象teach方法
def teach;
}
/*
* 实现类TeacherForMaths需要现实抽象类中所有的属性和方法
*/
classTeacherForMaths(name:String)extends SuperTeacher(name){
// 实现 抽象 id 属性赋值
override var id =name.hashCode();
// 实现 抽象 age 属性赋值
var age: Int = 25;
// 实现 抽象 teach 属性赋值
def teach:Unit = {
println("Teaching!!!");
}
}
// 方法调用
defmain(args: Array[String]): Unit = {
var teacher = newTeacherForMaths("Scala");
teacher.teach;
println("teacher.id="+teacher.id);
println("teacher.age="+teacher.age);
}
输出结果:
Teaching!!!
teacher.id=79698214
teacher.age=25
3.3 特征(trait)
特性封装方法和字段定义,然后可以通过将它们混合成类被重用。不同于类继承,其中每个类都必须继承只有一个父类,一类可以在任意数量特质混合。
特征用于通过指定支持的方法的签名定义的对象类型。Scala中也允许部分实现特性但可能不具有构造参数。trait中可以带有实现的方法,也可以带有抽象方法,使用trait的方法是with而混入类中。
代码示例:
trait Logger {
// 空方法,即方法内部不做任务实现
deflog(msg:String){}
}
/*
* 控制台日志类继承日志类
*/
class ConsoleLogger extends Logger with Cloneable{
defconsoleLogger(){
println("It'sme !!!");
}
}
/*
* 使用trait关键字混入日志
*/
trait TraitLogger extends Logger {
override def log(msg:String){
println("TraitLoggerlog is :" + msg);
}
}
// 代码调用
def main(args:Array[String]): Unit = {
// 子类重写父类的方法
var consoleLogger = newConsoleLogger();
consoleLogger.consoleLogger();
// trait关键字混入
val traitlogger = newConsoleLogger with TraitLogger
traitlogger.log("It'sme !!!")
}
输出结果:
It's me !!!
TraitLogger log is :It's me !!!
3.4 多重继承
Scala的类只能够继承单一父类,但是如果是特征的话就可以继承多个,从结果来看就是实现了多重继承。
代码示例:
// 定义Human类
class Human(){
println("Human");
}
// 定义trait特性,继承Human类
trait TTeacher extends Human(){
println("TTeacher");
// 抽象方法
def teach
}
// 定义trait PianoPlayer继承Human
trait PianoPlayer extends Human(){
println("PianoPlayer");
defpianoPlayer = {println("I'm playing piano.")}
}
// PianoTeacher类,继承Human类,实现TTeacher特征、PianoPlayer特征。
// 对象在构造时,依次从左向右构造
class PianoTeacher() extends Human with TTeacher withPianoPlayer {
// 实现TTeacher中teach方法
override def teach ={println("I'm training students.")}
}
3.5 AOP实现
AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
代码示例:
// 定义特征Action
trait Action {
def doAction
}
// 被加入的方面,定义一下加入了前置处理和后置处理的特征TBeforeAfter
trait TBeforeAfter extends Action {
// abstractoverride 关键字覆盖默认抽象方法,
// 实际被执行的是被调用的实体类中所定义的方法,实际执行将由子类实现。
abstract override def doAction{
// 调用super.doAction之前的打印
println("Initialization");
// 调用super.doAction方法
super.doAction
// 调用super.doAction之后的打印
println("Destroyed");
}
}
// Work类实现Action特征
class Work extends Action {
// 实现doAction方法
override def doAction= println("Working...")
}
// 代码调用
def main(args:Array[String]): Unit = {
// 调用doAction方法
val work = new Work withTBeforeAfter;
work.doAction;
}
输出结果:
Initialization
Working...
Destroyed
--以上为类、属性和对象字段的内容,谢谢大家对我的关注。
——厚积薄发(yuanxw)