鲁春利的工作笔记,好记性不如烂笔头
1、扩展类
extends是Scala中实现继承的保留字;
class week extends month{......}
week类继承了month类所有非私有成员;
week类是month类的子类,month类是week类的超类;
子类能重写超类的成员(字段、方法);
class week(val num : Int) extends month(val num : Int) {......}
单例对象同样能从类中继承,与类的继承语法相同:object day extends week {......}
重写
Scala中使用override保留字进行方法、字段重写
class week extends month {
override def firstday () {......}
}
override保留字声明其后的字段或方法是对超类的重写,也可以写在类定义参数中。
class week (override val lastday : String) extends month(val lastday : String)
重新定义的字段和方法不可重写(override),方法不同(参数类型或个数)不可重写。
scala> class month {
| def secondary(m : String) {
| println("secondary is " + m);
| }
| }
defined class month
scala>
scala> class week extends month {
| override def secondary(m : String) { // 重写该方法
| println("secondary is " + m);
| }
| }
defined class week
2、重写规则
重写def
用val:利用val能重写超类没有参数的方法;
用def:子类方法与超类成员重名;
用var:同时重写getter、setter方法,只重写getter方法报错。
重写val:
用val:子类的一个私有字段与超类的字段重名,getter方法重写超类的getter方法
重写var:
用var:当超类的var是抽象的才能被重写,否则超类的var都会被继承。
// 新建文件month.scala,内容为:
abstract class month {
val zero : Int;
val one = 25; // 可在子类中用val重写
var two = 15; // 不可在子类中用var重写,因为不是抽象的
var three : Int;
def firstday ; // 可在子类中用val重写
def now ; // 可在子类中用var重写
def now_ ;
def lastday(m : Char) = {} // 可在子类中用def重写
}
// 通过scalac命令编译该文件
D:\LuclAppServ\scala-SDK\source>scalac month.scala
D:\LuclAppServ\scala-SDK\source>javap.exe -private month.class
// 通过javap命令查看生成的文件
Compiled from "month.scala"
public abstract class month {
// val变量且被初始化了
private final int one;
// var变量且被初始化了
private int two;
// val变量但为抽象的,直接生成了getter方法
public abstract int zero();
// 只有getter方法
public int one();
// 同时具有getter和setter方法(=被转义为$eq)
public int two();
public void two_$eq(int);
// var变量但为抽象的,直接生成了getter和setter方法
public abstract int three();
public abstract void three_$eq(int);
// 其他抽象的方法
public abstract void firstday();
public abstract void now();
public abstract void now_();
// 具有方法体,非抽象方法
public void lastday(char);
// 构造函数
public month();
}
通过IDE工具生成的week.scala代码如下
/**
* @author lucl
*/
class week extends month {
override val zero : Int = 10;
override var three : Int = 3;
override def firstday : Unit = {
println("method of firstday.");
}
override def now : Unit = {
println("method of now.");
}
override def now_ : Unit = {
println("method of now_.");
}
}
object week {
def main (args : Array[String]) {
var w = new week();
println(w.zero + "\t" + w.now);
}
}
查看生成的week子类代码
D:\LuclAppServ\workspaces\scala\scalaproj\bin>javap -private week.class
Compiled from "week.scala"
public class week extends month {
private final int zero;
private int three;
public int zero();
public int three();
public void three_$eq(int);
public void firstday();
public void now();
public void now_();
public week();
public static void main(java.lang.String[]);
}
D:\LuclAppServ\workspaces\scala\scalaproj\bin>javap -private week$.class
Compiled from "week.scala"
public final class week$ {
public static final week$ MODULE$;
public static {};
public void main(java.lang.String[]);
private week$();
}
说明:
子类构造器运行在超类构造器之后,在超类的构造器调用的子类被重写后,返回值可能不正确。
/**
* @author lucl
*/
class A {
val num = 31;
val days = new Array[Int](num);
println("When invoke Class A the length of days is " + days.length + ".");
def dayLength = {
println("Class A : the length of days is " + days.length + ".")
}
}
/**
* @author lucl
*/
object B extends A {
override val num = 7;
def main (args : Array[String]) {
dayLength;
println("The finally value of num is " + num);
}
}
运行结果:

构造B对象前先执行A的构造器,num被初始化为31,days被初始化为Array数组;
Array数组初始化时需要调用num,但num被子类重写了,但此时B的构造器还未被调用,num被初始化为0,days被初始化为长度为0的数组;
A的构造器执行完毕,执行B的构造器,num被初始化为7,但此时A中days已初始化过不会再更新其初始化信息,days的数组长度为0。
解决方法:
将超类的val声明为final(不可再被子类重写);
将超类的val声明为lazy;
在子类中使用提前定义语法。
a. final
当A类中的num声明为final val num : Int = 7,则子类中不可再重写该字段;
b. lazy
/**
* @author lucl
*/
class A {
lazy val num = 31; // 通过lazy标注
val days = new Array[Int](num);
println("When invoke Class A the length of days is " + days.length + ".");
def dayLength = {
println("Class A : the length of days is " + days.length + ".")
}
}
/**
* @author lucl
*/
object B extends A {
override lazy val num = 7;
def main (args : Array[String]) {
dayLength;
println("The finally value of num is " + num);
}
}
运行结果
c. 提前定义
把需要提前定义的语句块放在extends与超类之间,并后接with保留字。
class B extends {override val num = 7; } with A {......}
/**
* @author lucl
*/
object B extends {override val num = 7; } with A {
def main (args : Array[String]) {
dayLength;
println("The finally value of num is " + num);
}
}
执行结果:

3、抽象类
不能被实例的类叫做抽象类,用保留字abstract标记;
抽象类的某个或某几个成员没有被完整定义,这些没有被完整定义的成员为抽象字段或方法。
/**
* @author lucl
*/
abstract class year {
val name : Array[String]; // 抽象的val,带有一个抽象的getter方法
var num : Int; // 抽象的var,带有抽象的getter/setter方法
def sign; // 没有方法体/函数体,是一个抽象方法
}
只要类中有任意一个抽象成员,必须使用abstract标记;
重写抽象方法、抽象字段不需要使用override保留字。
保护
当一个类不希望被集成、拓展时,可在类声明前加上final保留字
final class year {......}
当一个类的某些成员不希望被重写时,可在成员声明前加上final保留字
class year {final def sign {......}}
当超类中的某些成员需要被子类继承,又不想对子类以外成员可见时,在成员声明前加上protected保留字;
protected[this],将访问限定于当前对象(子类也不可访问),类似于private[this];
/**
* @author lucl
* 只要类中有一个成员是抽象的,则类就需要声明为抽象类
*/
abstract class Human {
var name : String; // 抽象字段
def sleep() : String; // 抽象方法
def info (address : String);
}
/**
*
*/
abstract class Teacher (tname : String, age : Int) extends Human {
println(tname + "\t" + age);
override var name : String = tname;
// 若将类声明为def sleep = "8 hours",在下面调用super.sleep()的位置会提示返回的为Unit
override def sleep() : String = "8 hours.";
def info (address : String);
}
/**
* Worker继承Teacher时有两个参数name和age需要从Worker中传递参数
* Worker的的参数名字需要与Teacher中一致,否则IDE会提示错误
*/
class Worker(tname : String, age : Int, salary : Int) extends Teacher (tname, age) {
override def info (address : String) {
println(tname + "' home is in " + address);
println(tname + "'s age is " + age + ", earn ¥" + salary + ".");
}
override def toString = {
tname + " is a worker, sleep " + super.sleep;
}
}
object AbstractClassOps {
def main(args : Array[String]) {
val w = new Worker ("zhangsan", 25, 3000);
w.info("BeiJing");
println(w);
}
}
/**
zhangsan 25
zhangsan' home is in BeiJing
zhangsan's age is 25, earn ¥3000.
zhangsan is a worker, sleep 8 hours.
*/
4、类的private属性
/**
* @author lucl
*/
// 默认是public类型的
class Person {
// age必须赋值,否则该类必须为abstract的
private var age : Int = 0;
// 没有private修饰默认是public的
// 无参的方法可以省略(),调用时可以省略();
def increment() = age += 1;
// 若声明的方法不带(),则调用时不可带()
def current = age;
// 类可以直接访问伴生对象的私有属性
def speak = Person.sayHello;
}
class Student {
/**
* 声明为private类型的参数,只能通过当前类的函数来访问
*/
private var privateAge : Int = 0;
// 仅限于类的当前实例对象访问,其他传入的对象(如下面的other)将不可访问private[this]修饰的变量
private [this] val name : String = "";
// 自定义的getter/setter方法 ,用来操作私有字段
def age = privateAge;
def age_ (newAge : Int) {
privateAge = newAge;
}
/**
* this对象的使用,表示调用该方法的当前对象
*/
def sameStudent (other : Student) = {
// 上面的等号表示有返回结果,否则最后的true会提示:
// a pure expression does nothing in statement position;
// you may be omitting necessary parentheses
if (this.privateAge != other.privateAge) {
false;
}
/**
* 此时通过other将无法访问该name对象
* value name is not a member of Student
*/
/*if (this.name != other.name) {
false;
}*/
true;
}
// 在student中则不可通过Person类直接访问sayHello方法,提示:
// method sayHello in object Person cannot be accessed in object Person
// def speak = Person.sayHello;
// 但可以通过如下方式访问:
var p = new Person;
p.speak; // 这里会直接执行
}
/**
* 对象为类的伴生对象,类为对象的伴生类
*/
object Person {
def main (args : Array[String]) {
var p = new Person();
println("age is : " + p.age); // 可以访问到私有属性
p.increment;
println("age is : " + p.age);
println("current is : " + p.current);
// 带有()则提示“Int does not take parameters”
// p.current();
val s = new Student();
// variable privateAge in class Student cannot be accessed in Student
// s.privateAge;
println(s.age);
s.age_(20);
println(s.age);
}
private def sayHello () {
println("Singleton object Person to say.");
}
}
/**
// 输出结果
age is : 0
age is : 1
current is : 1
Singleton object Person to say.
0
20
*/
5、嵌套类
Scala允许任何语法结构中嵌套任何语法结构,因此能在类中定义类,类似于Java中的内部类。
内部类中可以访问外部类的成员,利用外部类.this或指针实现。
scala> class HelloWorld {pointto =>
val value2 = "HelloWorld";
class HI {
var value3 = HelloWorld.this.value2;
var value4 = pointto.value2;
}
}
scala> var one = new HelloWorld;
one: HelloWorld = HelloWorld@4b134f33
scala> one.value2;
res52: String = HelloWorld
scala> class Family (val hname : String, val wname : String) {
class Husband (var name : String) {
println("Husband is : " + name);
}
class Wife (var name : String) {
println("Wife is " + name);
}
def info () {
var husband = new Husband(hname);
var wife = new Wife(wname);
println("This family holds husband " + husband.name + ", wife " + wife.name);
}
}
scala> val f = new Family("Tom", "Jerry");
f: Family = Family@62de96e8
scala> f.info();
Husband is : Tom
Wife is Jerry
This family holds husband Tom, wife Jerry
Java内部类:内部类是属于外部类的;
/**
*
* @author lucl
* Java内部类示例
* 说明:Java内部类是从属于外部类的
*/
public class JavaOuter {
private String name;
public JavaOuter (String name) {
this.name = name;
}
/**
* 内部类
*/
// 一旦用static修饰内部类,它就变成静态内部类了。
class Inner {
private String name;
public Inner (String name) {
this.name = name;
}
public void foo (Inner inner) {
System.out.println("\t" + JavaOuter.this.name + "\t" + inner.name);
}
}
public void foo () {
System.out.println("Outer : " + this.name);
}
/**
* @param args
*/
public static void main(String[] args) {
JavaOuter outer1 = new JavaOuter("Spark");
JavaOuter outer2 = new JavaOuter("Hadoop");
JavaOuter.Inner inner1 = outer1.new Inner("scala");
JavaOuter.Inner inner2 = outer2.new Inner("java");
outer1.foo();
inner1.foo(inner1);
outer2.foo();
inner2.foo(inner2);
outer1.foo();
inner1.foo(inner2); // 在这里inner1可以调用inner2
}
}
/**
// 输出结果
Outer : Spark
Spark scala
Outer : Hadoop
Hadoop java
Outer : Spark
Spark java
*/
Scala内部类:内部类是属于外部类的对象的;
/**
* @author lucl
* Scala内部类示例
* 说明:Scala内部类是从属于外部类的对象的
*/
class ScalaOuter(val name : String) {outer =>
/**
* 内部类
*/
class Inner (val name : String) {
def foo (inner : Inner) {
println("\t" + outer.name + "\t" + inner.name + ".");
}
}
def foo () {
println("Outer : " + outer.name);
}
}
object OOPInScala {
/**
* main方法
*/
def main (args : Array[String]) {
val outer1 = new ScalaOuter ("Spark");
val outer2 = new ScalaOuter ("Hadoop");
val inner1 = new outer1.Inner("scala");
val inner2 = new outer2.Inner("java");
outer1.foo;
inner1.foo(inner1);
outer2.foo;
inner2.foo(inner2);
// 对于scala来说,这inner1调用foo方法传递参数时,是不可以将inner2作为参数传递的
// IDE提示:type mismatch; found : outer2.Inner required: outer1.Inner
// inner1.foo(inner2);
}
}
/**
// 输出结果
Outer : Spark
Spark scala.
Outer : Hadoop
Hadoop java.
*/