Skip to content

Instantly share code, notes, and snippets.

@yaboong
Forked from kwon37xi/(01장) 기본기.scala
Created February 20, 2017 12:13
Show Gist options
  • Save yaboong/1b8c0d8212de7c49ec25c7a46f5b631f to your computer and use it in GitHub Desktop.
Save yaboong/1b8c0d8212de7c49ec25c7a46f5b631f to your computer and use it in GitHub Desktop.
쉽게 배워서 빨리 써먹는 Scala 프로그래밍 연습문제 풀이
/** Chapter 01 **/
/*
문제에 오역이 좀 있다. 아래에서 문제 자체를 검색해서 확인해 볼 것.
Java 7 이상에서 실행할 것.
https://www.google.co.kr/search?client=ubuntu&channel=fs&q=scala+for+the+impatient+exercise&ie=utf-8&oe=utf-8&gws_rd=cr&redir_esc=&ei=oqvrUb-1B6LwiQfjk4GQBg
Scala Doc : http://www.scala-lang.org/api/current/index.html
*/
/*
1. 스칼라 REPL에서 3을 입력하고 탭 키를 눌러라. 어떤 메소드를 부를 수 있나?
*/
println("# 1.1 --")
println(
"""
|!= ## % & * + - / < <<
|<= <init> == > >= >> >>> ^ asInstanceOf equals
|getClass hashCode isInstanceOf toByte toChar toDouble toFloat toInt toLong toShort
|toString unary_+ unary_- unary_~ |
|
""".stripMargin)
/*
스칼라 REPL에서 3의 제곱근을 계산하고 그 값을 제곱하라. 결과가 3과 얼마나 차이가 나는가?
(힌트: res 변수를 활용하라.)
*/
println("# 1.2 --")
val squareRootOf3 = math.sqrt(3)
println("sqrt of 3 : " + squareRootOf3)
println("sqrt of 3 * sqrt of 3 : " + (squareRootOf3 * squareRootOf3))
/*
3. res 변수들은 val인가 var인가?
*/
println("# 1.3 --")
println(
"""
|scala> res1 = 23423.32
|<console>:8: error: reassignment to val
| res1 = 23423.32
| ^
|
|오류 메시지로 보건에 val 이다.
""".stripMargin)
/*
4. 스칼라에서는 문자열을 숫자로 곱할 수 있다. "crazy" * 3을 REPL에서 해보라.
이 연산은 무엇을 하나? 스칼라독 어디에서 이를 찾을 수 있나?
*/
println("# 1.4 --")
println("\"crazy\" * 3 : " + ("crazy" * 3))
println(
"""
|문자열에 대한 곱셈은 해당 문자열을 곱하기 값만큼 반복한 문자열을 생성해준다.
|StringOpts에서 볼 수 있다.
|http://www.scala-lang.org/api/current/index.html#scala.collection.immutable.StringOps
""".stripMargin)
/*
5. 10 max 2는 무엇을 의미하나? max 메소드는 어느 클래스에 정의되어 있나?
*/
println("# 1.5 --")
println("10 max 2 : " + (10 max 2))
println(
"""
| 둘 중에 큰값 리턴.
|RitchInt 에 코드 들어 있음.
""".stripMargin)
/*
6. BigInt를 사용하여 2^1024를 계산하라.
*/
println("# 1.6 --")
println("2^1024 " + BigInt(2).pow(1024))
/*
7. probablePrime과 Random에 아무런 식별자 없이 probablePrime(100, Random)으로
임의의 소수를 얻으려면 무엇을 임포트해야하나?
*/
println("# 1.7 --")
import scala.BigInt._
import scala.util.Random
println("임의의 소수 : " + probablePrime(10, Random))
/*
8. 임시의 파일 혹은 디렉토리 이름을 생성하는 방법 중 하나는 임의의 BigInt를
생성하고 이를 36진법으로 변환하여 "qsnvbevtomcj38o06kul" 같은 문자열을 얻는
것이다. 스카라독을 뒤져 Scala에서 이를 할 방법을 찾아라.
*/
println("# 1.8 --")
println("임의의 소수를 생성하여 32진법으로 표기 : " + BigInt.probablePrime(128, Random).toString(32))
/*
스칼라에서 문자열의 첫 문자를 어떻게 얻는가? 마지막 문자는 어떻게 얻는가?
*/
println("# 1.9 --")
val str = "Hello, World!"
println("first letter : " + str(0) + ", last letter : " + str.last)
/*
10. 문자열 함수 take, drop, takeRight, dropRight는 무엇을 하나? substring을
사용하는 것에 비해 장점과 단점은 무엇인가?
*/
println("# 1.10 --")
println("Hello, World!".drop(6).dropRight(1))
println(
"""
|drop/take 를 사용하는 것이 substring보다 훨씬 직관적이다.
""".stripMargin)
/** Chapter 02 **/
/*
1. 숫자의 signum은 숫자가 양수이면 1, 음수이면 -1, 0이면 0이다. 이 값을 계산하는
함수를 작성하라.
*/
println("# 2.1 --")
def signum(num: Int) = {
if (num > 0) 1 else if (num < 0) -1 else 0
}
println("양수 : " + signum(23))
println("음수 : " + signum(-128))
println("영 : " + signum(0))
/*
2. 빈 븍록시 {}의 값은 무엇인가? 타입은 무엇인가?
*/
println("# 2.2 --")
println("{} = " + {} + ", isInstanceof Unit = " + {}.isInstanceOf[Unit])
// # 2.2 {} = (), isInstanceof Unit = true
/*
3. 스칼라에서 x = y = 1 할당이 유효한 상황 하나만 말해보라. (힌트 적당한 x 타입을 고른다)
*/
println("# 2.3 --")
var x: Unit = ()
var y = 0
x = y = 1
println("x 가 Unit 타입일 때? - " + x)
/*
4. 자바 루프 for (int i = 10; i >= 0; i++) System.out.println(i); 와 동일한
스칼라 코드를 작성하라.
*/
println("# 2.4 --")
for (i <- 10 to(0,-1)) println(i)
/*
5. n부터 0까지 숫자를 출력하는 countdown(n: Int) 프로시저를 작성하라.
*/
println("# 2.5 --")
def countdown(n: Int) {
val step = if (n < 0) 1 else -1
printf("from %d to 0 -> ", n)
for (i <- n to(0,step)) print(i + ", ")
println("-- end")
}
countdown(-10)
countdown(0)
countdown(10)
/*
6. 문자열의 모든 문자의 유니코드를 곱하는 for 루프를 작성하라. 예를들어
"Hello"문자들의 곱은 9415087488L이다.
*/
println("# 2.6 --")
var product = 1L
for (c <- "Hello") {
product *= c.toLong
}
println("Hello is " + product)
/*
7. 6번 문제를 루프를 쓰지 않고 풀어보라.(힌트 스칼라독의 StringOps를 살펴본다.)
*/
println("# 2.7 --")
/*
11페이지의 함수를 인자로 가지는 메소드를 기반으로 문제를 푼다.
*/
println("Hello의 모든 곱 with map,product : " + "Hello".map(_.toLong).product )
/*
8. 6번 문제에서 기술한 바와 같이 곱을 계산하는 product(s: String) 함수를 작성하라.
*/
println("# 2.8 --")
def product(s: String) = {
var product = 1L
for (c <- s) {
product *= c.toLong
}
product
}
println("Hello with product() " + product("Hello"));
/*
9. 6번 문제의 함수를 재귀함수로 만들라.
*/
println("# 2.9 --")
def recursiveMultiply(chars: Char*): Long = {
if (chars.length == 0) return 1L
chars.head * recursiveMultiply(chars.tail: _*)
}
println("Hello with recursiveMultiply is " + recursiveMultiply("Hello".toCharArray: _*))
/*
10. n은 정수인 x^n을 계산하는 함수를 작성하라. 다음 재귀 정의를 이용하라.
- n이 양의짝수이고, y = x^(n/2)이면 x^n = y^2
- n이 양의 홀수이면 x^n = x*x^(n-1)
- x^0 = 1
- n이 음수이면 x^n = 1 / x^-n
return 문을 사용하지 않는다.
*/
println("# 2.10 --")
def mypow(x: Long, n: Long): Long = {
if (n > 0) {
if (n % 2 == 0 && n > 2) mypow(mypow(x, n/2), 2)
else x * mypow(x, n-1)
} else if (n < 0) 1 / mypow(x, -n)
else 1L
}
def printpow(x: Long, n: Long) {
printf("%d^%d = by mypow %d, by math.pow = %d%n", x, n, mypow(x,n), math.pow(x, n).toLong)
}
printpow(2,3)
printpow(4, 10)
printpow(4, -10)
printpow(5, 1)
printpow(10,0)
/** Chapter 03 **/
/*
1. a를 0(포함)과 n(불포함) 사이의 임의의 수 n개의 배열로 설정하는 코드 조각을 작성하라.
*/
println("# 3.1 --")
import scala.util.Random
import scala.collection.mutable.ArrayBuffer
def randomNumberArray(n : Int) = {
(for (i <- 0 until n) yield Random.nextInt(n)).toArray
}
val randomNumbers = randomNumberArray(20)
println("난수들 : " + randomNumbers)
/*
2. 정수 배열의 인접한 원소를 교환하는 루프를 작성하라. 예를들어 Array(1,2,3,4,5)는
Array(2,1,4,3,5)가 된다.
*/
println("# 3.2 --")
val arr1 = Array(1,2,3,4,5)
for (i <- 1 until (arr1.length, 2)) {
val temp = arr1(i - 1)
arr1(i - 1) = arr1(i)
arr1(i) = temp
}
println("인접 원소 교환 : " + arr1)
/*
3. 2번 문제를 반복하되 교환한 값으로 새 배열을 생성하라. for/yield를 사용한다.
*/
println("# 3.3 --")
val arr2 = Array(1,2,3,4,5,6,7,8,9,10)
val arr2Changed = (for (i <- 0 until arr2.length) yield {
if (i % 2 == 1) {
arr2(i - 1)
} else if (i != (arr2.length - 1)) {
arr2(i + 1)
} else {
arr2(i)
}
}).toArray
println("교환후 새 배열 : " + arr2Changed)
/*
4. 정수 배열이 주어졌을 때, 기존 배열의 모든 양수 값이 기존 순서대로 오고 그 뒤에 모든 0 혹은
음수 값이 기존 순서대로 오는 새 배열을 작성하라.
*/
println("# 3.4 --")
val ex4ab = new ArrayBuffer[Int]()
val ex4arr = Array(1,2,0,3,4,-5,6,7,-2,-3,10)
ex4ab ++= (for (i <- 0 until ex4arr.length if ex4arr(i) > 0) yield ex4arr(i))
ex4ab ++ (for (i <- 0 until ex4arr.length if ex4arr(i) <= 0) yield ex4arr(i))
println(ex4ab.toArray)
/*
5. Array[Double]의 평균을 어떻게 계산하나?
*/
println("# 3.5 --")
val doubles = Array(3.3,5.3,8.3,1.2,6.7)
println(doubles.sum / doubles.length)
/*
6. Array[Int]를 어떻게 재배열하면 역순으로 정렬되게 나오나? 같은 일을 ArrayBuffer[Int]에는 어떻게 하나?
*/
println("# 3.6 --")
val ex6arr = Array(54,3,2,2,56,8,3,34,8,98,23).sorted.reverse
println("배열 : " + ex6arr)
val ex6ab = ArrayBuffer(54,3,2,2,56,8,3,34,8,98,23).sorted.reverse
println("ArrayBuffer : " + ex6ab)
// 너무 쉬운데, 문제 의도를 잘 못 파악한 것인가?
/*
7. 중복을 제거한 배열의 모든 값을 생성하는 코드 조각을 작성하라.
(힌트: 스칼라독을 참고한다.)
*/
println("# 3.7 --")
val ex7arr = Array(1,2,3,2,4,5,6,7,5,8,9,7,2,10,10)
println("중복 제거 : " + ex7arr.distinct.mkString("<", ",", ">"))
/*
8. "3.4 배열 변환" 마지막에 나오는 예제를 재작성하라. 음수 원소의 인덱스를 모으고,
시퀀스를 역순으로 만들고, 마지막 인덱스를 빼고, 각 인덱스에 a.remove(i)를 호출하라.
3.4절의 두가지 방법과 이 방법의 효율성을 비교하라.
*/
println("# 3.8 --")
println("TODO")
/*
9. java.util.TimeZone.getAvailableIDs가 리턴하는 미국 내 모든 시간대의 콜렉션을 만들어라.
"America/" 접미를 제거하고 그 결과를 정렬하라.
*/
println("# 3.9 --")
val americas = for (am <- java.util.TimeZone.getAvailableIDs if am startsWith "America") yield am.replaceFirst("America/", "")
println("America 모든 시간 대 : " + americas.sorted)
/*
10. java.awt.datatransfer._ 를 임포트하고 SystemFlavorMap 타입 오브젝트를 다음 호출로
만들어라.
val flavors = SystemFlavorMap.getDefaultFlavorMap().asInstanceOf[SystemFlavorMap]
DataFlavor.imageFlavor를 인자로 getNativesForFlavor 메소드를 호출하여 스칼라 버퍼로
리턴 값을 얻어라.
(왜 이런 이상한 클래스일까? 표준 자바 라이브러리에서 java.util.List 사용을 찾기가 쉽지 않다.)
*/
println("# 3.10 --")
import java.awt.datatransfer._
import scala.collection.JavaConversions.asScalaBuffer
import scala.collection.mutable.Buffer
val flavors = SystemFlavorMap.getDefaultFlavorMap().asInstanceOf[SystemFlavorMap]
val imageFlavors : Buffer[String] = flavors.getNativesForFlavor(DataFlavor.imageFlavor)
println("ImageFlavors : " + imageFlavors)
import scala.collection.mutable
/** Chapter 04 **/
/*
1.사고 싶은 여러 장치의 가격 맵을 만들라. 그러고 나서 Key는 같고 가격은 10% 할인된
두 번째 맵을 생성하라.
*/
println("# 4.1 --")
val devices = scala.collection.immutable.Map("넥서스4" -> 459000, "넥서스7" -> 330000)
val discountedDevices = for ((k, v) <- devices) yield (k, (v * 0.9).toInt)
println("10% 할인 : " + discountedDevices)
/*
2. 파일에서 단어들을 읽어 들이는 프로그램을 작성하라. 각 단어가 얼마나 빈번하게 등장하는지
세는 수정 가능한 맵을 이용하라. 단어를 읽어 들이는 데는 간단히 java.util.Scanner를
사용하라.
val in = new java.util.Scanner(new java.io.File("myfile.txt"))
while (in.hasNext()) process in.next()
또는 9장의 스칼라 방식을 참조하라.
마지막에 모든 단어와 횟수를 추력하라.
*/
println("# 4.2 --")
val in = new java.util.Scanner(new java.io.File("./scripts/(04장) 맵과 튜플.scala"))
val words = new mutable.HashMap[String, Int]
while (in.hasNext()) {
val word = in.next()
words(word) = words.getOrElse(word, 0) + 1
}
for ((word, count) <- words) {
printf("단어 \"%s\" -> %d%n", word, count)
}
/*
3. 2번 문제를 수정 불가능한 맵으로 반복한라.
*/
println("# 4.3 --")
val ex3In = new java.util.Scanner(new java.io.File("./scripts/(04장) 맵과 튜플.scala"))
var ex3Words = new scala.collection.immutable.HashMap[String, Int]
while (ex3In.hasNext) {
val word = ex3In.next()
ex3Words = ex3Words + (word -> (ex3Words.getOrElse(word, 0) + 1))
}
for ((word, count) <- ex3Words) {
printf("단어 \"%s\" -> %d%n", word, count)
}
/*
4. 2번 문제를 단어가 정렬되어 출력되게 정렬 맵으로 반복하라.
*/
println("# 4.4 --")
val ex4In = new java.util.Scanner(new java.io.File("./scripts/(04장) 맵과 튜플.scala"))
val ex4Words = new mutable.HashMap[String, Int]
while (ex4In.hasNext()) {
val word = ex4In.next()
ex4Words(word) = ex4Words.getOrElse(word, 0) + 1
}
val sortedWords = scala.collection.immutable.SortedMap[String, Int](ex4Words.toArray: _*)
for ((word, count) <- sortedWords) {
printf("단어 \"%s\" -> %d%n", word, count)
}
/*
5. 2번 문제를 java.util.TreeMap을 스칼라 API로 개조해서 반복하라.
*/
println("# 4.5 --")
import java.util.TreeMap
import scala.collection.JavaConversions.mapAsScalaMap
val ex5In = new java.util.Scanner(new java.io.File("./scripts/(04장) 맵과 튜플.scala"))
val ex5Words = new TreeMap[String, Int]
while (ex5In.hasNext()) {
val word = ex5In.next()
val count = if (ex5Words.containsKey(word)) ex5Words.get(word) else 0
ex5Words.put(word, count + 1)
}
for ((word, count) <- ex5Words) {
printf("단어 \"%s\" -> %d%n", word, count)
}
/*
6. "Mondy"를 java.util.Calendar.MONDAY로 매핑하고 다른 요일도 비슷한 방식으로 매핑하는
링크 해시 맵을 정의하라. 원소는 삽입된 순서로 방문이 일어남을 보이라.
*/
println("# 4.6 --")
import java.util.Calendar._
val days = scala.collection.mutable.LinkedHashMap ("Monday" -> MONDAY, "Tuesday" -> TUESDAY,
"Wednesday" -> WEDNESDAY, "Thursday" -> THURSDAY, "Friday" -> FRIDAY, "Saturday" -> SATURDAY,
"Sunday" -> SUNDAY)
for ((word, value) <- days) {
printf("요일 %s -> %d\n", word, value)
}
/*
7. 다음과 같이 모든 자바 속성의 표를 출력하라.
키 이름 | 값
...
테이블을 출력하기 전에 가장 긴 키의 길이를 찾아야 할 것이다.
*/
println("# 4.7 --")
import scala.collection.JavaConversions.propertiesAsScalaMap
val props : scala.collection.Map[String, String] = System.getProperties()
var longestLength = 0;
for (key <- props.keySet) {
longestLength = if (key.length > longestLength) key.length else longestLength
}
for ((key, value) <- props) {
printf("%-" + (longestLength + 1) +"s | %s%n", key, value)
}
/*
8. 배열에서 가장 작은 수와 큰 수의 쌍을 리턴하는 minmax(values: Array[Int])
함수를 작성하라.
*/
println("# 4.8 --")
def minmax(values: Array[Int]) : (Int, Int) = {
(values.min, values.max)
}
val (min, max) = minmax(Array(4, 32,65,34,78,32,12,65,76,98,0,5,2,34))
printf("Min : %d, Max : %d%n", min, max)
/*
9. v보다 작은 수의 개수, v와 같은 수의 개수, v보다 큰 수의 개수를 트리플로 리턴하는
lteqgt(values: Array[Int], v: Int) 함수를 작성하라.
*/
println("# 4.9 --")
def lteqgt(values: Array[Int], v: Int) : (Int, Int, Int) = {
var lt = 0
var eq = 0
var gt = 0
for (value <- values) {
if (value > v) { gt += 1}
else if (value < v) { lt += 1}
else eq += 1
}
(lt, eq, gt)
}
val (lt, eq, gt) = lteqgt(Array(1,2,3,4,5,6,7,8,9,5,6,3,4,7,8,9,5,2,4,5,7), 5)
printf("lt : %d, eq : %d, gt %d%n", lt, eq, gt)
/*
10. "Hello".zip("World")와 같이 두 문자열을 집(zip)하면 무슨일이 생기나? 가능한
유스 케이스를 생각하라?
*/
println("# 4.10 --")
println("zip : " + "Hello".zip("World"))
/** Chapter 05 **/
/*
1. "5.1 간단한 클래스와 인자 없는 메소드"에 나온 Counter 클래스를 Int.MaxValue에서 음수가 되지 않게 개선하라.
*/
println("# 5.1 ---")
class Counter(private var value : Int) {
def increment() {
if (value < Int.MaxValue) {
value += 1
}
}
def current = value
}
val c = new Counter(Int.MaxValue)
c.increment()
println("current : " + c.current)
/*
2. 메소드 deposit과 withdraw, 읽기 전용 프로퍼티 balance로 BankAccount 클래스를 작성하라.
*/
println("# 5.2 ---")
class BankAccount {
private var balance = 0
def currentBalance = balance
def deposit(money : Int) {
balance += money
}
def withdraw(money: Int) {
balance -= money
}
}
val ba = new BankAccount
ba.deposit(50000)
ba.withdraw(3000)
println("current balance : " + ba.currentBalance)
/*
3. 읽기 전용 프로퍼티 hours와 minutes, 이 시간이 다른 시간보다 앞선 시간인지 확인하는
before(other: Time): Boolean 메소드를 가진 Time 클래스를 작성하라. Time 오브젝트는
new Time(hrs, min)으로 생성할 수 있어야 하는데, 여기서 hrs는 군용 시간 형식(0과 23사이)이다.
*/
println("# 5.3 ---")
class Time(private var hrs : Int, private var min : Int) {
def description = hrs + "H " + min + "m"
def before(other: Time): Boolean = {
(hrs * 60 + min) < (other.hrs * 60 + other.min)
}
}
val t1 = new Time(19,37)
println("before false 여야함 : " + t1.before(new Time(19, 36)))
println("before true 여야함 : " + t1.before(new Time(20, 30)))
/*
4. 내부 표현이 자정 이후 분(0과 24 * 60 - 1)이 되도록 이전 문제의 Time 클래스를 재구현하라.
공개 인터페이스는 변경하지 말아야 한다. 바꿔 말해 클라이언트 코드는 이 변경 사항에 영향을
받지 않아야 한다.
--> 내부적으로 데이터 저장을 hrs:min 로 하지 말고 0시 0분 이후 지난 분수로 표현하라는 뜻.
즉, 새벽 1시 10분은 70 으로 내부적으로 데이터를 보관할 것.
*/
println("# 5.4 ---")
class TimeByMinutes(private val hrs: Int, private val min : Int) {
private val time = (hrs * 60 + min)
def description = (time / 60) + "H" + (time % 60) + "m"
def before(other: TimeByMinutes): Boolean = {
time < other.time
}
}
val tm1 = new TimeByMinutes(19,37)
println("before false 여야함 : " + tm1.before(new TimeByMinutes(19, 36)))
println("before true 여야함 : " + tm1.before(new TimeByMinutes(20, 15)))
/*
5. 읽기-쓰기 Java Bean 프라퍼티 name(String 타입)과 id(Long 타입)을 갖는 Student 클래스를
만들라. 어떤 메소드가 생성되는가? (javap를 사용하여 확인한다.) 스칼라에서 Java Bean 게터와 세터를
호출할 수 있나? 그렇게 하는 것이 좋나?
*/
println("# 5.5 ---")
import scala.beans.BeanProperty
class Student {
@BeanProperty var name : String = ""
@BeanProperty var id : Long = 0
}
// scalac Student.scala
// javap -private Student
/*
Compiled from "Student.scala"
public class Student {
private java.lang.String name;
private long id;
public java.lang.String name();
public void name_$eq(java.lang.String);
public void setName(java.lang.String);
public long id();
public void id_$eq(long);
public void setId(long);
public java.lang.String getName();
public long getId();
public Student();
}
*/
val s = new Student
s.setName("Fred")
s.setId(5)
println("Name : " + s.getName + ", Id : " + s.getId)
// setter/getter 호출가능하다. 웬만하면 피치 못할 경우에만 사용하지 말고, View Template 같은 곳에서만
// 사용하도록 하자.
/*
6. "5.1 간단한 클래스와 인자 없는 메소드"에 나온 Person 클래스에서 음수 나이를 0으로 바꾸는
기본 생성자를 제공하라.
-> 실제로는 Person 클래스는 5.2에 나온다.
*/
println("# 5.6 ---")
class Person(private var privateAge: Int) {
if (privateAge < 0) {
privateAge = 0
}
def age = privateAge
def age_=(newAge: Int) {
if (newAge > privateAge) privateAge = newAge
}
}
val p1 = new Person(-10)
println("age changed : " + p1.age)
val p2 = new Person(10)
println("age : " + p2.age)
/*
7. new Person("Fred Smith")와 같이 이름, 공백, 성을 포함한 문자열을 받는 기본 생성자가 있는
Person 클래스를 작성하라. 읽기 전용 프로퍼티인 firstName과 lastName을 제공하라. 기본 생성자
인자는 var, val, 일반 인자 중 어느 것이어야 하나? 왜 그런가?
*/
println("# 5.7 ---")
class PersonSeven(name: String) {
private val names = name.split(" ")
def firstName = names(0)
def lastName = names(1)
}
val ps = new PersonSeven("Fred Smith")
println("firstName : " + ps.firstName + ", lastName : " + ps.lastName)
// 기본생성자는 일반 인자를 사용한다. 외부로 전혀 노출될 이유가 없기 때문이다.
/*
8. 제조사, 모델명, 모델 연도를 읽기 전용 프로퍼티로 가지고 번호판을 읽기-쓰기 프로퍼티로 가지는
Car 클래스를 만들어라. 네개의 생성자를 제공하라. 모든 생성자는 제조사와 모델명을 요구한다.
선택적으로, 모델 연도와 번호판을 생성자에 지정할 수 있다. 그렇지 않으면 모델 연도는 -1이 되고
번호판은 빈 문자열이 된다. 어느 생성자를 기본 생성자로 선택할 것인가? 왜 그런가?
*/
println("# 5.8 ---")
class Car(val manufacturer: String, val modelName: String) {
private var modelYear: Int = -1
var licensePlate: String = ""
def this(manufacturer: String, modelName: String, modelYear: Int) {
this(manufacturer, modelName)
this.modelYear = modelYear
}
def this(manufacturer: String, modelName: String, licensePlate: String) {
this(manufacturer, modelName)
this.licensePlate = licensePlate
}
def this(manufacturer: String, modelName: String, modelYear: Int, licensePlate: String) {
this(manufacturer, modelName, modelYear)
this.licensePlate = licensePlate
}
override def toString = "Car { manufacturer: " + manufacturer + ", modelName: " + modelName + ", year: " + modelYear + ", licensePlate: " + licensePlate + "}"
}
val car = new Car("Hyundai", "Santafe R", 2012, "가나1234")
println(car)
car.licensePlate = "아자차4567"
println(car)
// car.modelYear = 2011 // Error!
// car.manufacturer = "Kia" // Error!
// car.modelName = "Sonata" // Error!
// 항상 필요한 manufacturer와 modelName을 기본생성자로 구현한다.
/*
9. 8번 문제의 클래스를 자바, C# 혹은 C++(원하는 선택으로) 재구현하라.
*/
println("# 5.8 --- pass")
/*
10. 다음 클래스를 살펴보고 이 클래스를 명시적인 필드와 디폴트 기본 생성자를 이용하여 재작성하라.
어떤 형태를 더 선호하는가? 왜 그런가?
class Employee(val name: String, var salary: Double) {
def this() { this("John Q. Public", 0.0) }
}
*/
// from http://stackoverflow.com/questions/10426146/constructors-in-scala-primary-auxiliary-default-primary/10999828#10999828
// var, val 에 주의해서 필드를 생성해야한다.
class Employee {
private var _name = "John Q. Public"
var salary: Double = 0.0
def this(name: String, salary: Double) {
this()
_name = name
this.salary = salary
}
def name = _name
}
val e = new Employee
println("Employee " + e.name + ", " + e.salary)
// 기본 생성자가 나은 듯 하다. 필드들을 원하는 형태로 즉각 생성할 수 있다.
// 그에반해 필드를 명시적으로 해야 할 경우에는 접근자를 복잡하게 만들어야 한다.
/** Chapter 06 **/
/*
1. inchesToCentimeters, gallonsToLiters, milesToKilometers 메소드를 가지는 Conversions
오브젝트를 작성하라.
*/
println("# 6.1 ---")
object Conversions {
// http://www.manuelsweb.com/in_cm.htm
// in * 2.54 = cm
def inchesToCentimeters(inches: Double) = {
inches * 2.54
}
// http://www.nomoreodor.com/gallons_to_liters_conversion.htm
// gallons * 3.7854 = liters
def gallonsToLiters(gallons: Double) = {
gallons * 3.7854
}
// http://www.metric-conversions.org/length/miles-to-kilometers.htm
// mi * 1.6093 = km
def milesToKilometers(miles: Double) = {
miles * 1.6093
}
}
println(1/0.62137)
println("12 inches = " + Conversions.inchesToCentimeters(12))
println("50 gallons = " + Conversions.gallonsToLiters(50))
println("80 miles = " + Conversions.milesToKilometers(80))
/*
2. 이전 문제는 그다지 객체 지향적이지 않다. 일반적인 슈퍼클래스인 UnitConversion을 제공하고
이를 확장하는 InchesToCentimeters, GallonsToLiters, MilesToKilometers 오브젝트를 정의하라.
*/
println("# 6.2 ---")
abstract class UnitConversion(val multipliedBy: Double) {
def convert(value: Double) = {
value * multipliedBy
}
}
object InchesToCentimeters extends UnitConversion(2.54) {
}
object GallonsToLiters extends UnitConversion(3.7854) {
}
object MilesToKilometers extends UnitConversion(1.6093) {
}
println("12 inches = " + InchesToCentimeters.convert(12))
println("50 gallosn = " + GallonsToLiters.convert(50))
println("80 miles = " + MilesToKilometers.convert(80))
/*
3. java.awt.Point를 확장하는 Origin 오브젝트를 정의하라. 이는 왜 좋은 생각이 아닌가?
(Point 클래스의 메소드를 자세히 살펴본다.)
*/
println("# 6.3 ---")
object Origin extends java.awt.Point {
}
// public x, y 때문에? 그리고 mutable 한 메소드때문에?
// Origin이라는 이름은 근본, 근원이라는 뜻을 담고 있고 이는 값이 바뀌어서는 안된다는 의미.
// mutable methods 때문에 값을 바꿀 수 있음.
/*
4. Point 클래스를 컴패니언 오브젝트와 함께 정의하여 new 없이 Point(3,4)와 같은
Point 인스턴스를 생성할 수 있게 하라.
*/
println("# 6.4 ---")
class Point private (val x: Int, val y: Int) {
override def toString() = "Point { x = " + x + ", y = " + y + " }"
}
object Point {
def apply(x: Int, y: Int) = {
new Point(x, y)
}
}
println(Point(10, 20))
/*
5. App 트레이트를 이용하여 명령 줄 인자를 공백으로 구분하여 역순으로 출력하는 스칼라 애플리케이션을
작성하라. 예를들어 scala Revers Hello World는 World hello를 출력해야 한다.
*/
println("# 6.5 ---")
object Reverse extends App {
for(arg <- args.reverse) {
print(arg + " ")
}
println()
}
/*
6. 4개의 카드 세트를 묘사하는 이뉴머레이션을 작성하여 toString 메소드가 ♣, ◆, ♥, ♠를 리턴하게 만들어라3
https://en.wikipedia.org/wiki/Playing_card
*/
println("# 6.6 ---")
object Card extends Enumeration {
type Card = Value
val Spade = Value(0, "♠")
val Heart = Value(1, "♥")
val Diamond = Value(2, "◆")
val Club = Value(3, "♣")
}
import Card._
println(Spade)
println(Heart)
println(Diamond)
println(Club)
/*
7. 이전 문제 카드 세트 값이 빨강인지 확인하는 함수를 구현하라.
*/
println("# 6.7 ---")
def isRed(card: Card) = {
card == Heart || card == Diamond
}
println("Spade is red? " + isRed(Spade))
println("Heart is red? " + isRed(Heart))
println("Diamond is red? " + isRed(Diamond))
println("Club is red? " + isRed(Club))
/*
8. RGC 색상 큐브의 8개의 모서리를 나타내는 이뉴머레이션을 작성하라. ID로 색상 값을 사용하라.
(예: 0xff0000은 빨강)
*/
println("# 6.8 ---")
// http://prosjekt.ffi.no/unik-4660/lectures04/chapters/jpgfiles/RGB_cube_color.jpg 참조
// 위 이미지에서 1은 사실 ff 를 뜻함.
object RGBCube extends Enumeration {
type RGBCube = Value
val Blue = Value(0x0000ff)
val Cyan = Value(0x00ffff)
val White = Value(0xffffff)
val Green = Value(0x00ff00)
val Yellow = Value(0xffff00)
val Red = Value(0xff0000)
val Black = Value(0x000000)
val Magenta = Value(0xff00ff)
}
// http://alvinalexander.com/scala/scala-string-formatting-java-string-format-method 참조
for (color <- RGBCube.values) {
println(color + " -> " + "0x%06X".format(color.id))
}
/** Chapter 07 **/
/*
1. package com.horstmann.impatient가
package com
package horstmann
package impatient
와 동일하지 않음을 보여주는 예제 프로그램을 작성하라.
*/
println("# 7.1 ---")
/* Chap07Ex01Constas.scala
package com.horstmann
object Chap07Ex01Consts {
val horstmannValue = "Horstmann's scala for the impatient."
}
*/
/* Chap07Ex01Firstcala
package com.horstmann.impatient
import com.horstmann.Chap07Ex01Consts
object Chap07Ex01First extends App {
println("com.horstmann.impatient 에서는 명시적 improt 필요 : " + Chap07Ex01Consts.horstmannValue)
}
*/
/* Chap07Ex01Secondcala
package com
package horstmann
package impatient
object Chap07Ex01Second extends App {
println("package com/horstmann/impatient 따로 지정은 import 불필요 : " + Chap07Ex01Consts.horstmannValue)
}
*/
/*
2. 최상위에 있지 않은 com 패키지를 이용하여 스칼라 친구를 골탕먹이는 퍼즐러를 작성하라.
*/
println("# 7.2 ---")
/* Chap07Ex02FakeCom.scala
package com.horstmann
object Chap07Ex02FakeCom {
val someValue = "wanted value!"
}
package impatient.com.horstmann {
object Chap07Ex02FakeCom {
val someValue = "fake value! -.-"
}
}
*/
/* Chap07Ex02Fooled.scalaackage com.horstmann.impatient
object Chap07Ex02Fooled extends App {
println(com.horstmann.Chap07Ex02FakeCom.someValue)
}
*/
// 이 결과로 "fake value! -.-" 가 출력된다.
/*
3. nextInt(): Int, nextDouble(): Double, setSeed(seed: Int): Unit 함수가 있는
random 패키지를 작성하라. 임의의 수 생성에는 다음 선형 합동 생성기를 사용하라.
next = previous * a + b % 2n -> 책에 오타. 책에는 2의 n제곱으로 표기 돼 있음.
여기서 a = 1664525, b = 1013904223, n = 32이다.
*/
println("# 7.3 ---")
/* Chap07Ex02-random-package.scala
package random
package object random {
private val a = 1664525
private val b = 1013904223
private val n = 32
private var seed : Int = 0
def next(): Double = {
seed = seed * a + b % (2 * n)
seed
}
def nextDouble(): Double = {
next()
}
def nextInt(): Int = {
next().toInt
}
def setSeed(seed: Int) {
this.seed = seed
}
}
object Test extends App {
random.setSeed(123123)
println("NextInt : " + random.nextInt())
println("NextInt : " + random.nextInt())
println("NextInt : " + random.nextInt())
println("NextDouble : " + random.nextDouble())
println("NextDouble : " + random.nextDouble())
println("NextDouble : " + random.nextDouble())
}
*/
/*
4. 스칼라 언어 설계자는 왜 단순히 패키지에 함수와 변수를 추가할 수
있게 허용하는 대신 패키지 오브젝트 문법을 제공핬다고 생각하나?
*/
println("# 7.4 ---")
println("""
Java 언어가 package에 멤버를 둘 수 있게 허용하지 않으므로
Package Object를 통해 클래스 package라는 클래스 객체로써 문제 해결.
""")
/*
5. private[com] def giveRaise(rate: Double)의 의미는 무엇인가? 이는 유용한가?
*/
println("# 7.5 ---")
println("""
com 패키지 멤버들이 볼 수 있는 메소드 giveRaise() 선언.
별로 필요할 것 같지는 않다.
""")
/*
6. 자바 HashMap에서 스칼라 HashMap으로 모든 원소를 복사하는 프로그램을 작성하라.
임포트를 사용하여 두 클래스의 이름을 변경하라.
*/
println("# 7.6 ---")
import java.util.{HashMap => JavaHashMap}
val javaHashMap = new JavaHashMap[String, Int]
javaHashMap.put("하나", 1)
javaHashMap.put("둘", 2)
javaHashMap.put("셋", 3)
import scala.collection.mutable.{HashMap => ScalaHashMap}
val scalaHashMap = new ScalaHashMap[String, Int]
import scala.collection.JavaConversions._
for ((k, v) <- javaHashMap) {
scalaHashMap += (k -> v)
}
println("ScalaHashMap : " + scalaHashMap)
/*
7. 6번 문제에서 모든 임포트는 최대한 안쪽 스코프로 옮기라.
*/
println("# 7.7 ---")
println("6번 자체를 수정함.")
/*
8.
import java._
import javax._
의 효과는 무엇인가? 이는 좋은 생각인가?
*/
println("# 7.8 ---")
println(
"""
|java 와 javax 패키지는 동일한 이름의 하위 패키지를 가지고 있다.
|이에 따라 패키지를 줄여 쓸 경우 올바르게 작동하지 않는다.
""".stripMargin)
/*
9. java.lang.System 클래스를 임포트하고, user.name 시스템 프라퍼티에서
사용자 이름을 읽고, Console 오브젝트에서 암호를 읽어 암호가 "secret"가
아니면 표준 에러 스트림으로 메시지를 출력하는 프로그램을 작성하라.
암호가 맞으면 표준 출력 스트림으로 인사를 출력하라. 다른
임포트는 사용하지 말고 전체 이름(점이 있는)도 사용하지 말아야 한다.
*/
println("# 7.9 ---")
println("Console이 java.io.Console이 아니라 scala.Console이라는게 함정.")
import java.lang.System
val userName = System.getProperty("user.name")
println(userName)
val password = Console.readLine("password : ")
if (password == "secret") {
Console.out.println("Hello, " + userName)
} else {
Console.err.println("Wrong password")
}
/*
10. StringBuilder 말고 scala 패키지가 덮어쓰는 java.lang 멤버는 무엇이 있는가?
*/
println("# 7.10 ---")
println(
"""
|대분의의 기본형 클래스들. Integer, Long, Boolean, ...
|
""".stripMargin)
/** Chapter 08 **/
/*
1. 다음 BankAccount 클래스를 매회 입금과 출금에 $1를 청구하는 CheckingAccount로 확장하라
*/
println("# 8.1 ---")
class BankAccount(initialBalance: Double) {
private var balance = initialBalance
def deposit(amount: Double) = { balance += amount; balance }
def withdraw(amount: Double) = { balance -= amount; balance }
}
class CheckingAccount(initialBalance: Double) extends BankAccount(initialBalance) {
override def deposit(amount: Double) = { super.deposit(amount - 1.0) }
override def withdraw(amount: Double) = { super.withdraw(amount + 1.0) }
}
val checkingAccount = new CheckingAccount(100.0)
println("deposit 10.0 : " + checkingAccount.deposit(10.0))
println("withdraw 15.0 : " + checkingAccount.withdraw(15.0));
/*
2. 1번 문제의 BankAccount를 확장하여 (earnMonthlyInterest 메소드가 불릴 때) 매달 이자를 지급하고,
매달 3번의 공짜 입금 혹은 출금을 제공하는 SavingAccount 클래스를 만들라. 거래 횟수는
earnMonthlyInterest에서 초기화하라.
*/
println("# 8.2 ---")
class SavingAccount(initialBalance: Double, monthlyInterest: Double) extends BankAccount(initialBalance) {
private var transactionCount = 0
private def transactionFee : Double = { transactionCount += 1; if (transactionCount > 3) 1.0 else 0 }
override def deposit(amount: Double) = { super.deposit(amount - transactionFee) }
override def withdraw(amount: Double) = { super.withdraw(amount + transactionFee)}
def earnMonthlyInterest() = {
transactionCount = 0
deposit(monthlyInterest)
}
}
val savingAccount = new SavingAccount(100.0, 2.0)
println("deposit 1.0 1 : " + savingAccount.deposit(1.0));
println("deposit 1.0 2 : " + savingAccount.deposit(1.0));
println("deposit 1.0 3 : " + savingAccount.deposit(1.0));
println("deposit 1.0 4 : " + savingAccount.deposit(1.0));
println("earnMonthlyInterest : " + savingAccount.earnMonthlyInterest());
println("withdraw 1.0 1 : " + savingAccount.withdraw(1.0));
println("withdraw 1.0 2 : " + savingAccount.withdraw(1.0));
println("withdraw 1.0 3 : " + savingAccount.withdraw(1.0));
println("withdraw 1.0 4 : " + savingAccount.withdraw(1.0));
/*
3. 종업원이나, 애완동물, 그래픽 모양 등 간단한 상속 계층 예제가 있는 Java 혹은
C++ 교과서를 참고하여 그 예제를 스칼라로 구현하라.
Java Vehicle Example: http://lanbuddy.com/java/lesson11.htm
//This is the class that will be inherited
public class Vehicle
{
public int doors;
public int seats;
public int wheels;
Vehicle()
{
wheels=4;
doors=4;
seats=4;
}
}
//This class inherits Vehicle.java
public class Car extends Vehicle
{
public String toString()
{
return "This car has "+seats+" Seats, "+doors+" Doors "+
"and "+wheels+" wheels.";
}
}
//This class inherits Vehicle.java
public class MotorCycle extends Vehicle
{
MotorCycle()
{
wheels=2;
doors=0;
seats=1;
}
void setSeats(int num)
{
seats=num;
}
public String toString()
{
return "This motorcycle has "+seats+" Seats, "+doors+" Doors "+
"and "+wheels+" wheels.";
}
}
//This class inherits Vehicle.java
public class Truck extends Vehicle
{
boolean isPickup;
Truck()
{
isPickup=true;
}
Truck(boolean aPickup)
{
this();
isPickup=aPickup;
}
Truck(int doors, int seats, int inWheels, boolean isPickup)
{
this.doors=doors;
this.seats=seats;
wheels=inWheels;
this.isPickup=isPickup;
}
public String toString()
{
return "This "+(isPickup?"pickup":"truck")+
" has "+seats+" Seats, "+doors+" Doors "+"and "+wheels+" wheels.";
}
}
*/
println("# 8.3 ---")
//This is the class that will be inherited
class Vehicle(val doors: Int = 4, val seats: Int = 4, val wheels: Int = 4) {
}
class Car(doors: Int = 4, seats: Int = 4, wheels: Int = 4) extends Vehicle(doors, seats, wheels) {
override def toString: String = { "This car has " + seats + " Seats, " + doors + " Doors and " + wheels + " wheels."}
}
class MotorCycle(seats: Int = 1) extends Vehicle(4, seats, 2) {
override def toString: String = { "This motorcycle has " + seats + " Seats, " + doors + " Doors and " + wheels + " wheels."}
}
class Truck(isPickup: Boolean = true, doors: Int = 4, seats : Int = 4, wheels: Int = 4) extends Vehicle(doors, seats, wheels) {
override def toString: String = { "This " + (if (isPickup) "pickup" else "truck") + " has " + seats + " Seats, " + doors + " Doors and " + wheels + " wheels."}
}
println("Car : " + new Car(2));
println("MotorCycle : " + new MotorCycle(2))
println("Truck : " + new Truck(true, 2, 4, 12))
/*
4. price와 description 메소드가 있는 추상 클래스 Item을 정의하라. SimpleItem은 가격과 설명을
생성자에 지정하는 아이템이다. val이 def를 오버라이드할 수 있다는 사실을 이용하기 바란다.
Bundle은 다른 아이템을 들고 있는 아이템이다. Bundle의 가격은 번들 내 가격들의 합이다.
또한 번들에 아이템을 추가하는 방법과 적절한 description 메소드도 제공하라.
*/
println("# 8.4 ---")
abstract class Item {
def price: Double
def description: String
}
class SimpleItem(override val price: Double, override val description: String) extends Item {
}
val simpleItem = new SimpleItem(10.0, "간단한 아이템")
println("simpleItem : " + simpleItem.price + ", " + simpleItem.description)
import scala.collection.mutable
import scala.collection.mutable._
class Bundle extends Item {
val items: ArrayBuffer[Item] = ArrayBuffer()
def add(item: Item) {
items += item
}
def price: Double = {
var sum = 0.0
for (item <- items) {
sum += item.price;
}
sum
}
def description: String = {
val descriptions = mutable.StringBuilder.newBuilder
descriptions.append("* Items")
.append(" : $")
.append(price)
.append("\n")
for (item <- items) {
descriptions.append(" - ")
.append(item.description)
.append(" $")
.append(item.price)
.append("\n")
}
descriptions.toString()
}
}
val bundle = new Bundle
bundle.add(new SimpleItem(5.0, "햄버거"))
bundle.add(new SimpleItem(1.0, "콜라"))
bundle.add(new SimpleItem(1.5, "감자칩"))
println("bundle : $" + bundle.price + "\n" + bundle.description)
/*
5. x와 y 좌표를 생성자에 지정할 수 있는 Point 클래스를 설계하라. 생성자에서 레이블 값,
x와 y 좌표를 다음과 같이 받는 LabelPoint 서브클래스를 제공하라.
new LabelPoint("Black Thursday", 1929, 230.07
*/
println("# 8.5 ---")
class Point(val x: Double, val y: Double) {
override def toString: String = { "Point("+ x + ", " + y +")" }
}
val point = new Point(4.5, 10.2)
println("포인트 " + point)
class LabelPoint(val label: String, x: Double, y: Double) extends Point(x, y) {
override def toString: String = { "Label - " + label + "(" + x + ", " + y + ")" }
}
val label = new LabelPoint("Black Thursday", 1929, 230.07)
println("레이블 " + label)
/*
6. 추상 메소드 centerPoint가 있는 추상 클래스 Shape, 서브클래스 Rectangle과 Circle을 정의하라.
서브클래스를 위한 적절한 생성자를 제공하고 각 서브클래스의 centerPoint 메소드를 오버라이드하라.
*/
println("# 8.6 ---")
abstract class Shape(startingPoint: Point) {
def centerPoint: Point
override def toString: String = {"Starting Point : " + startingPoint + ", CenterPoint : " + centerPoint}
}
class Rectangle(startingPoint: Point, width: Double, height: Double) extends Shape(startingPoint) {
override def centerPoint: Point = { new Point(startingPoint.x + (width / 2), startingPoint.y + (height / 2))}
}
class Circle(startingPoint: Point, radius: Double) extends Shape(startingPoint) {
override def centerPoint: Point = { startingPoint }
}
println("Rectangle : " + new Rectangle(new Point(10, 10), 50, 50))
println("Circle : " + new Circle(new Point(160.0, 190.23), 230.50))
/*
7. java.awt.Rectangle을 확장하고, 다음 3개의 생성자가 있는 Square 클래스를 제공하라. 모서리점과
너비를 받는 생성자, (0.0) 모서리에 주어진 너비를 받는 생성자, (0, 0)에 너비가 0인 생성자.
*/
println("# 8.7 ---")
class Square(x: Int, y: Int, width: Int) extends java.awt.Rectangle(x, y, width, width) {
def this(width: Int = 0) {
this(0, 0, width)
}
}
println("Square : " + new Square(80))
/*
8. "8.6 필드 오버라이드하기"에 나오는 Person과 SecretAgent 클래스를 컴파일하고 javap로
클래스 파일을 분석하라. name 필드가 몇개나 있는가? name 게터 메소드가 몇 개나 있는가?
게터 메소드들은 무엇을 얻는가? (힌트 -c와 -private 옵션을 사용한다.)
*/
println("# 8.8 ---")
println(
"""
| Chap08Ex08.scala 참조.
|
| Person.class
|$ javap -c -private Person
|Compiled from "Chapter08Ex08.scala"
|public class Person {
| private final java.lang.String name;
|
| public java.lang.String name();
| Code:
| 0: aload_0
| 1: getfield #13 // Field name:Ljava/lang/String;
| 4: areturn
|
| public java.lang.String toString();
| Code:
| 0: new #18 // class scala/collection/mutable/StringBuilder
| 3: dup
| 4: invokespecial #22 // Method scala/collection/mutable/StringBuilder."<init>":()V
| 7: aload_0
| 8: invokevirtual #26 // Method java/lang/Object.getClass:()Ljava/lang/Class;
| 11: invokevirtual #31 // Method java/lang/Class.getName:()Ljava/lang/String;
| 14: invokevirtual #35 // Method scala/collection/mutable/StringBuilder.append:(Ljava/lang/Object;)Lscala/collection/mutable/StringBuilder;
| 17: ldc #37 // String [name=
| 19: invokevirtual #35 // Method scala/collection/mutable/StringBuilder.append:(Ljava/lang/Object;)Lscala/collection/mutable/StringBuilder;
| 22: aload_0
| 23: invokevirtual #39 // Method name:()Ljava/lang/String;
| 26: invokevirtual #35 // Method scala/collection/mutable/StringBuilder.append:(Ljava/lang/Object;)Lscala/collection/mutable/StringBuilder;
| 29: ldc #41 // String ]
| 31: invokevirtual #35 // Method scala/collection/mutable/StringBuilder.append:(Ljava/lang/Object;)Lscala/collection/mutable/StringBuilder;
| 34: invokevirtual #43 // Method scala/collection/mutable/StringBuilder.toString:()Ljava/lang/String;
| 37: areturn
|
| public Person(java.lang.String);
| Code:
| 0: aload_0
| 1: aload_1
| 2: putfield #13 // Field name:Ljava/lang/String;
| 5: aload_0
| 6: invokespecial #45 // Method java/lang/Object."<init>":()V
| 9: return
|}
|
|$ javap -c -private SecretAgent
|Compiled from "Chapter08Ex08.scala"
|public class SecretAgent extends Person {
| private final java.lang.String name;
|
| private final java.lang.String toString;
|
| public java.lang.String name();
| Code:
| 0: aload_0
| 1: getfield #14 // Field name:Ljava/lang/String;
| 4: areturn
|
| public java.lang.String toString();
| Code:
| 0: aload_0
| 1: getfield #18 // Field toString:Ljava/lang/String;
| 4: areturn
|
| public SecretAgent(java.lang.String);
| Code:
| 0: aload_0
| 1: aload_1
| 2: invokespecial #22 // Method Person."<init>":(Ljava/lang/String;)V
| 5: aload_0
| 6: ldc #24 // String secret
| 8: putfield #14 // Field name:Ljava/lang/String;
| 11: aload_0
| 12: ldc #24 // String secret
| 14: putfield #18 // Field toString:Ljava/lang/String;
| 17: return
|}
|
|Person과 SecretAgent는 각자 name 필드를 가지고 있고, 각자 name() 게터를 가지고 있다.
|
""".stripMargin)
/*
9. "8.10 생성 순서와 조기 정의"에 나오는 Creature 클래스에서 val range를 def로
바꾸라. Ant 클래스에서도 def를 사용하면 어떤 일이 발생하나? 서브클래스에서 val을
사용하면 어떤 일이 발생하나? 왜 그런가?
*/
println("#8.9 ---")
class Creature {
def range: Int = 10
val env: Array[Int] = new Array[Int](range)
}
class Ant extends Creature {
override def range = 2
}
class AntVal extends Creature {
override val range = 2
}
val ant = new Ant
println("Ant.env.size() : " + ant.env.size)
val antVal = new AntVal
println("AntVal.env.size() : " + antVal.env.size)
println(
"""
|Creature 생성시 호출되는 range는 Ant 클래스에 오버라이드된 메소드이고,
|이 메소드는 Ant 클래스의 초기화와 상관없이 메소드 내부 로직을 실행하므로
|올바른 값인 2를 리턴한다.
|그에반해 AntVal은 Creature 생성시 호출되는 range가 메소드내에서 즉시 값을 리턴하지
|않고 아직 초기화 되지 않은 AntVal의 range 필드 값(0)을 리턴하게 된다.
""".stripMargin)
/*
10. scala/collection/immutable/Stack.scala 파일은 다음 정의를 포함한다.
class Stack[A] protected (protected val elems: List[A])
protected 키워드의 의미를 설명하라. (힌트: 5장의 비공개 생성자 논의를 되짚어본다.)
*/
println("#8.10 ---")
println(
"""
|protected는 서브클래스에서만 접근 가능한 가시성이다.
|따라서 기본 생성자가 protected라 함은 서브 클래스들만 해당 생성자를 호출할 수
|있다는 뜻으로 보인다.
""".stripMargin)
/** Chapter 09 **/
/*
1. 파일 내의 줄을 뒤집는 (마지막 줄을 첫 번째로 만드는 등) 스칼라 코드 조각을 작성하라.
*/
println("## 9.1 ---")
import scala.io._
import java.io._
val filename: String = "scripts/(09장-1)test.txt"
val source = Source.fromFile(filename)
val reversedLines: Array[String] = source.getLines.toArray.reverse
source.close()
val out = new PrintWriter(filename)
for (line <- reversedLines) out.println(line)
out.close()
/*
2. 탭이 있는 파일을 읽어 탭 간격이 n 컬럼 경계에 있게 각 탭을 공백으로 치환하여 그 결과를
같은 파일에 쓰는 스칼라 프로그램을 작성하라.
--> 해석 : 탭은 기본 8컬럼인데, 두글자 쓰고 탭을 누르면 실제로는 6칸만 전진하는 식으로 항상
8의 배수 단위로 다음 위치가 정해지는 방식을 뜻하는 듯.
여기서는 탭 크기를 4로 간주하고 만든다. 같은 파일에 쓰게 되면 테스트시마다 새로운 파일을
만들어야 해서 기본 파일을 만들어 놓그 그것을 복사한 뒤에 코드를 수행한다.
*/
println("## 9.2 ---")
import java.nio.file.Files
import java.nio.file.Paths
import java.nio.file.StandardCopyOption.REPLACE_EXISTING
val originalFilename = "scripts/(09장-2)original.txt"
val workFilename = "scripts/(09장-2)work.txt"
Files.copy(Paths.get(originalFilename), Paths.get(workFilename), REPLACE_EXISTING)
val work92File = Source.fromFile(workFilename)
val work92Lines = work92File.getLines.toArray
work92File.close()
// ... 작성할 것
/**
3.
*/
println("## 9.3 ---")
9
8
7
6
5
4
3
2
1
hel lo world!
nice to meet you!
starts with one tab.
starts with two tabs.
12 starts with 1 tab and two chars.
(09장-2)work.txt
package com.horstmann
object Chap07Ex01Consts {
val horstmannValue = "Horstmann's scala for the impatient."
}
package com.horstmann.impatient
import com.horstmann.Chap07Ex01Consts
object Chap07Ex01First extends App {
println("com.horstmann.impatient 에서는 명시적 improt 필요 : " + Chap07Ex01Consts.horstmannValue)
}
package com
package horstmann
package impatient
object Chap07Ex01Second extends App {
println("package com/horstmann/impatient 따로 지정은 import 불필요 : " + Chap07Ex01Consts.horstmannValue)
}
package random
package object random {
private val a = 1664525
private val b = 1013904223
private val n = 32
private var seed : Int = 0
def next(): Double = {
seed = seed * a + b % (2 * n)
seed
}
def nextDouble(): Double = {
next()
}
def nextInt(): Int = {
next().toInt
}
def setSeed(seed: Int) {
this.seed = seed
}
}
object Test extends App {
random.setSeed(123123)
println("NextInt : " + random.nextInt())
println("NextInt : " + random.nextInt())
println("NextInt : " + random.nextInt())
println("NextDouble : " + random.nextDouble())
println("NextDouble : " + random.nextDouble())
println("NextDouble : " + random.nextDouble())
}
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"
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment