Scala練習七
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指的是這個引數只有子類才能訪問