1. 扩展如下的BankAccount类,新类CheckingAccount对每次存款和取款都收取1美元的手续费
class BankAccount ( initialBalance: Double) {
private var balance = initialBalance
def deposit (amount: Double) = { balance += amount; balance }
def withdraw(amount: Double)={ balance -= amount; balance }
}
程序代码:
-
class BankAccount(initialBalance:Double){
-
private var balance=initialBalance
-
def deposit(amount:Double)={
-
balance+=amount
-
balance
-
}
-
def withdraw(amount:Double)={
-
balance-=amount
-
balance
-
}
-
def currentBalance=balance
-
}
-
//一种实现
-
class checkingAccount (initialBalance:Double) extends BankAccount(initialBalance){
-
override def deposit(amount:Double)={
-
super.deposit(amount-1)
-
}
-
override def withdraw(amount:Double)={
-
super.withdraw(amount+1)
-
}
-
}
-
object checkingAccount{
-
val cha=new checkingAccount(1000)
-
val dbal=1000
-
val wbal=800
-
def main(args: Array[String]): Unit = {
-
cha.deposit(dbal)
-
println("
存入 :
"+dbal+"
余额
: "+cha.currentBalance)
-
cha.withdraw(wbal)
-
println("
取出 :
"+wbal+"
余额
: "+cha.currentBalance)
-
}
-
}
运行结果:
存入 :1000 余额: 1999.0
取出 :800 余额: 1198.0
2. 扩展前一个练习的BankAccount类,新类SavingsAccount每个月都有利息产生( earnMonthlylnterest方法被调用 ),并且有每月三次免手续费的存款或取款。在eamMonthlylnterest方法中重置交易计数
程序代码:
-
class SavingsAccount(initialBalance:Double) extends BankAccount(initialBalance){
-
private var freeCount=3
-
private val interestRate=0.03
-
def CurrentCount = freeCount
-
def earnMonthlyInterrest:Double={
-
freeCount=3
-
super.deposit(super.deposit(0)*interestRate)
-
super.deposit(0)*interestRate
-
}
-
override def deposit(amount:Double):Double={
-
if(freeCount>0){
-
freeCount-=1
-
super.deposit(amount)
-
}else{
-
super.deposit(amount-1)
-
}
-
}
-
override def withdraw(amount:Double):Double={
-
if(freeCount>0){
-
freeCount-=1
-
super.withdraw(amount)
-
}else{
-
super.withdraw(amount+1)
-
}
-
}
-
}
-
object SaveTest{
-
val dbal=1000
-
val wbal=100
-
var interest=0.0
-
val sa=new SavingsAccount(1000)
-
def main(args: Array[String]): Unit = {
-
for(i<- 1 to 32){
-
if(i>=1&& i<=4){
-
sa.deposit(1000)
-
println(i+"
号存入:
"+dbal+"
余额:
"+sa.currentBalance+"
剩余免费次数
: "+sa.CurrentCount)
-
}else if(i>=29&&i<=31){
-
if(i==30)
-
interest=sa.earnMonthlyInterrest
-
sa.withdraw(100)
-
println(i+"
号取出:
"+wbal+"
余额:
"+sa.currentBalance+"
剩余免费次数
: "+sa.CurrentCount)
-
-
}
-
}
-
println("
一个月的利息为:
"+interest+"
剩余免费次数
: "+sa.CurrentCount)
-
}
-
}
运行结果:
1号存入: 1000余额: 2000.0 剩余免费次数: 2
2号存入: 1000余额: 3000.0 剩余免费次数: 1
3号存入: 1000余额: 4000.0 剩余免费次数: 0
4号存入: 1000余额: 4999.0 剩余免费次数: 0
29号取出: 100余额: 4898.0 剩余免费次数: 0
30号取出: 100余额: 4944.94 剩余免费次数: 2
31号取出: 100余额: 4844.94 剩余免费次数: 1
一个月的利息为: 151.3482 剩余免费次数: 1
3. 翻开你喜欢的Java或C++教科书,一定会找到用来讲解继承层级的示例,可能是员工、宠物、图形或类似的东西,用Scala来实现这个示例
-
abstract
class Animal{
-
def run
-
}
-
class Cat
extends Animal{
-
override def run=println("
I can run,miao!")
-
}
-
class Dog
extends Animal{
-
override def run=println("
I can run,wang!")
-
}
-
object AnimalTest {
-
def main(args: Array[String]): Unit = {
-
val cat=
new Cat
-
val dog=
new Dog
-
cat.run
-
dog.run
-
}
-
}
运行结果:
I can run,miao!
I can run,wang!
4. 定义一个抽象类ltem,加入方法price和description。Simpleltem是一个在构造器中给出价格和描述的物件。利用val可以重写def这个事实。Bundle是一个可以包含其他物件的物件。其价格是打包中所有物件的价格之和。同时提供一个将物件添加到打包当中的机制,以及一个合适的description方法
程序代码:
-
abstract class Item{
-
def price:Double
-
def description:String
-
}
-
class SimpleItem(override val price:Double,override val description:String) extends Item{
-
}
-
-
class Bundle() extends Item{
-
val itemList=scala.collection.mutable.ArrayBuffer[Item]()
-
def addItem(item:Item){
-
itemList+=item
-
}
-
override def price={
-
var p:Double=0
-
itemList.foreach(i=>p=p+i.price)
-
p
-
}
-
override def description={
-
var des=""
-
itemList.foreach(i=>des=des+i.description+"")
-
des
-
}
-
}
-
object ItemTest {
-
val bundle=new Bundle
-
def main(args: Array[String]): Unit = {
-
val priceArr=Array(2.5,100,3.5,40,32.5)
-
val desArr=Array("
铅笔
","
水杯
","
笔记本
","
火腿肠
","
鼠标
")
-
for(i <- 0 until 5){
-
bundle.addItem(new SimpleItem(priceArr(i),desArr(i)))
-
}
-
println("
购物篮信息如下:
")
-
bundle.itemList.foreach(item=>println("
描述:
"+item.description+"
价格
: "+item.price))
-
println("
所购物品如下:
"+bundle.description)
-
println("
本次购物合计:
"+bundle.price+"
¥
")
-
}
-
}
运行结果:
购物篮信息如下:
描述: 铅笔价格: 2.5
描述: 水杯价格: 100.0
描述: 笔记本价格: 3.5
描述: 火腿肠价格: 40.0
描述: 鼠标价格: 32.5
所购物品如下: 铅笔水杯笔记本火腿肠鼠标
本次购物合计: 178.5¥
5. 设计一个Point类,其x和y坐标可以通过构造器提供。提供一个子类LabeledPoint,其构造器接受一个标签值和x、y坐标,比如:
new LabeledPoint("Black Thursday", 1929, 230.07)
程序代码:
-
class Point(val x:Double,val y:Double) {
-
override def toString="x= "+x+" y= "+y
-
}
-
class LabelPoint(val label:String,override val x:Double,override val y:Double)extends Point(x,y){
-
override def toString ="label= "+label+"x= "+x+"y= "+y
-
}
-
object PointTest{
-
def main(args: Array[String]): Unit = {
-
val point=new Point(2,3)
-
val lpoint=new LabelPoint("
圆形
",2,3)
-
println(point)
-
println(lpoint)
-
}
-
}
运行结果:
x= 2.0 y= 3.0
label= 圆形 x= 2.0y= 3.0
6. 定义一个抽象类Shape、一个抽象方法centerPoint,以及该抽象类的子类Rectangle和Circle。为子类提供合适的构造器,并重写centerPoint方法
程序代码:
-
abstract class Shape {
-
abstract def centerPoint: Point
-
}
-
-
class Rectangle(p1: Point, p2: Point, p3: Point) extends Shape {
-
override def centerPoint = {
-
//
略
-
}
-
}
-
-
class Circle(p1: Point, p2: Point, p3: Point) extends Shape {
-
override def centerPoint = {
-
//
略
-
}
-
}
运行结果:
7. 提供一个Square类,扩展自java.awt.Rectangle并且有三个构造器:一个以给定的端点和宽度构造正方形,一个以(0,0)为端点和给定的宽度构造正方形,一个以(0,0)为端点、0为宽度构造正方形。
程序代码:
-
import java.awt.Point
-
import java.awt.Rectangle
-
-
class Squre extends Rectangle{
-
height=0
-
width=0
-
x=0
-
y=0
-
def this(p:Point,w:Int){
-
this()
-
this.height=w
-
this.width=w
-
this.x=p.x
-
this.y=p.y
-
}
-
def this(width:Int){
-
this(new Point(0,0),width)
-
}
-
}
-
object SqureTest {
-
def main(args: Array[String]): Unit = {
-
val rect1=new Squre()
-
val rect2=new Squre(2)
-
val rect3=new Squre(new Point(2,3),5)
-
println(rect1)
-
println(rect2)
-
println(rect3)
-
}
-
}
运行结果:
org.hebut.yu.two.Squre[x=0,y=0,width=0,height=0]
org.hebut.yu.two.Squre[x=0,y=0,width=2,height=2]
org.hebut.yu.two.Squre[x=2,y=3,width=5,height=5]
8. 编译的Person和SecretAgent类并使用javap分析类文件。总共有多少name的getter方法,它们分别取什么值
程序代码:
class Person ( val name: String ) {
override def toString=getClass.getName+"name="+ name+ "]"
}
class SecretAgent (codename: String) extends Person (codename) {
override val name = "secret" // 不想暴露真名…
override val toString = "secret" // …或类名
}
执行命令:
javap -p : 查看编译的内容
javap -c : 查看想详细操作指令
javap -v : 查看常量池
运行结果:Person.scala
运行结果:Person.scala
分析:可以看到两个类中都有name()方法,但是子类覆写了父类的。SecretAgent和Person不一样的是name设置了默认值,用-v查看,name的secrect实际上是在构造函数中设置的
执行命令:javap -v org.hebut.yu.Person
执行命令:javap -v org.hebut.yu.SecretAgent
9. 在Creature类中,将val range替换成val def。如果你在Ant子类中也用def的话会有什么效果,如果在子类中使用val又会有什么效果,为什么
程序代码:
class Creature {
val range : Int=10
val env: Array[Int] = new Array[Int] ( range)
}
class Ant extends Creature {
override val range=2
}
class Ant extends {
override val range=2
} with Creature
描述:★★★★★★
def覆写def,子类的env可以正确初始化。而用val覆写def,env会被初始化成0长度。这个跟val覆写val的道理是一样的。父类和子类同时存在私有的同名变量range和相同的range的getter,但是父类构造函数先被调用,却在其中调用子类的getter。因为父类 的getter以被子类覆写。子类的range因为此时还没初始化,所以返回了0。父类构造函数,错误地使用0来初始化了env。这种行为本身就是个坑,但是也提供了非常大的灵活性。面向对象的Template设计模式就依赖这种行为实现的,所以还是多多善用为妙。
10. 文件scala/collection/immutable/Stack.scala包含l如下定义:
class Stack[A] protected ( protected val elems: List[Al )
请解释protected关键字的含义
前一个protected是指主构造器的权限, 即默认情况下,是不能已传入elems的方式创建Stack对象的,elems的protected指的是这个参数只有子类才能访问