IBM®
메인 컨텐츠로 가기
    Korea [국가변경]    이용약관
 
 
   
        제품    서비스 & 솔루션    고객지원 & 다운로드    회원 서비스    
메인 컨텐츠로 가기

한국 developerWorks  >  자바  >

바쁜 자바 프로그래머를 위한 스칼라 입문: 클래스 동작 (한글)

스칼라(Scala)의 클래스 문법과 의미를 이해하자

developerWorks
문서 옵션

JavaScript가 필요한 문서 옵션은 디스플레이되지 않습니다.

샘플 코드

영어원문

영어원문


제안 및 의견
피드백

난이도 : 초급

Ted Neward, Principal, Neward & Associates

옮긴이: 김도형 dwkorea@kr.ibm.com

2008 년 4 월 22 일

™ 프로그래머가 스칼라를 이해하기 위해서는 우선 객체부터 쳐다보는 것이 자연스럽습니다. 이 연재의 두 번째인 이번 글에서는 언어의 효용은 새로운 기능을 통합할 수 있는 능력으로 평가할 수 있다는 언어 평가의 기본 전제를 따라 복소수(complex number) 지원 예를 살펴봅니다. 그 과정에서 스칼라의 클래스 정의와 사용에 관한 흥미로운 사실들을 알게 될 것입니다.

지난 글에서는 스칼라 프로그램을 실행하고 비교적 단순한 특징을 살펴보기 위해 필요한 최소한의 스칼라 문법을 살펴 보았다. 'Hello World'와 'Timer' 예제를 통해 스칼라의 Application 클래스를 살펴보고, 메서드 정의와 무명 함수를 위한 문법도 살펴 보았다. 아울러 Array[]와 타입 추론(type inference)에 대해서도 약간씩 살펴 보았다. 스칼라는 그 외에도 많은 특징을 갖고 있는데, 이번 글에서는 이러한 스칼라 코딩의 복잡한 부분을 살펴보겠다.

이 연재에 대해

필자인 Ted Neward는 이 연재를 통해 독자들에게 스칼라 프로그래밍 언어를 심층적으로 설명한다. 이 새 developerWorks 연재를 통해 최근의 스칼라를 둘러싼 떠들썩한 호평의 실체를 살펴보고, 스칼라의 언어적 특성의 일부가 실제 어떻게 쓰이지도 배울 것이다. 비교가 필요할 때는 항상 스칼라 코드와 자바 코드를 나란히 보일 예정이다. 하지만 곧 알게 되겠지만 스칼라에 있는 많은 요소는 자바 언어와 직접적인 관계가 없는 것들이고, 이런 부분이 스칼라를 매력적으로 만든다. 그렇다면 자바 코드로도 할 수 있다면 왜 힘들여 스칼라를 배울까?

스칼라의 함수 프로그래밍 지원은 아주 매력적이지만 자바 개발자가 스칼라에 관심을 가져야 하는 유일한 이유는 아니다. 사실 스칼라는 함수적 개념과 객체 지향을 혼합한 언어다. 자바에서 스칼라로 넘어오는 프로그래머 입장에서 스칼라를 더욱 친숙하게 느끼려면 스칼라의 객체 지원을 살펴보고 언어상 자바와 비교해 보는 편이 좋다. 여기서 유의할 것은 이런 특징 중 일부는 곧장 대응하는 자바 쪽 개념이 없고, 경우에 따라서는 대응하는 개념이 있더라도 정확히 대응되기보다는 비슷할 뿐인 경우가 있다는 점이다. 앞으로 이런 구분이 중요한 경우 구체적으로 명시하겠다.

스칼라에도 클래스가 있다.

스칼라가 지원하는 클래스 개념에 대해 장황하고 추상적인 설명을 하기보다는 먼저 스칼라 플랫폼에 유리수(rational number) 지원을 추가하기 위해 사용할 수 있는 클래스 정의를 살펴보자(대부분 "Scala By Example"에서 베껴왔다(참고자료를 살펴보라).


Listing 1. rational.scala
                
class Rational(n:Int, d:Int)
{
  private def gcd(x:Int, y:Int): Int =
  {
    if (x==0) y
    else if (x<0) gcd(-x, y)
    else if (y<0) -gcd(x, -y)
    else gcd(y%x, x)
  }
  private val g = gcd(n,d)
  
  val numer:Int = n/g
  val denom:Int = d/g
  
  def +(that:Rational) =
    new Rational(numer*that.denom + that.numer*denom, denom * that.denom)
  def -(that:Rational) =
    new Rational(numer * that.denom - that.numer * denom, denom * that.denom)
  def *(that:Rational) =
    new Rational(numer * that.numer, denom * that.denom)
  def /(that:Rational) =
    new Rational(numer * that.denom, denom * that.numer)

  override def toString() =
    "Rational: [" + numer + " / " + denom + "]"
}

Listing 1의 전반적인 구조는 지난 10년 동안 자바 코드에서 봐 왔던 것과 어휘적으로는 비슷한 반면, 몇몇 새로운 요소도 분명히 눈에 뜨인다. 클래스 정의를 조목조목 살펴보기에 앞서 새 Rational 클래스를 사용하는 예를 살펴보자.


Listing 2. RunRational
                
class Rational(n:Int, d:Int)
{
  // ... as before
}

object RunRational extends Application
{
  val r1 = new Rational(1, 3)
  val r2 = new Rational(2, 5)
  val r3 = r1 - r2
  val r4 = r1 + r2
  Console.println("r1 = " + r1)
  Console.println("r2 = " + r2)
  Console.println("r3 = r1 - r2 = " + r3)
  Console.println("r4 = r1 + r2 = " + r4)
}

Listing 2는 특별히 흥미롭지는 않다. Rational을 두 개 생성하고 이 둘을 서로 더하고 빼서 유리수를 두 개 더 생성한다. 그리고 마지막에 그 유리수 네 개를 콘솔에 출력한다. (여기서 Console.println()scala.*에 정의된 스칼라 코어 라이브러리의 일부로 자바의 java.lang처럼 모든 스칼라 프로그램에 자동으로 임포트(import)된다.)




위로


몇 가지 방법으로 당신을 생성하오리까?

이제 Rational 클래스 정의에서 다시 첫 행을 살펴보자.


Listing 3. 스칼라의 기본 생성자
                
class Rational(n:Int, d:Int)
{
  // ...

제네릭스와 비슷한 문법이라고 생각할지도 모르겠지만 사실 Rational 클래스의 기본이자 우선인 생성자(constructor)다. 즉 nd는 해당 생성자의 인자일 뿐이다.

스칼라는 생성자가 하나인 편을 선호하는데 대부분의 클래스에서 생성자가 하나이거나 편의상 모든 생성자가 하나의 생성자로 연결되는 경우가 대부분이라는 점에서 일리가 있다. 스칼라에서는 필요하면 추가로 생성자를 정의할 수도 있다.


Listing 4. 생성자 연결
                
class Rational(n:Int, d:Int)
{
  def this(d:Int) = { this(0, d) }

여기서 자바에서의 생성자 연결과 마찬가지로 스칼라에서도 우선 생성자(Int,Int 형태)를 호출하는 방식으로 연결한다는 점에 유의하자.

세부, (구현) 세부…

유리수 연산을 할 때는 약간의 수치적인 기교를 부리면 도움이 된다. 즉 특정 연산이 쉽도록 공통 분모를 찾아두면 좋다. 1/2에 2/4를 더해야 할 때 Rational 클래스는 2/4가 1/2과 같다는 것을 알아채고 덧셈 전에 적절히 변환할 수 있을 정도로 똑똑해야 한다.

그 때문에 Rational 클래스 내부의 private 함수인 gcd()g값을 정의했다. 스칼라에서 생성자가 호출될 때는 클래스 몸체 전체가 계산되는데, 앞선 gnd의 최대 공약수(common denominator)로 초기화되어, numer와 denom을 적절히 설정하는 데 사용된다(역주: 원문에서는 numer와 denom 대신 nd로 되어 있지만 내용상 오류다).

잠시 Listing 1로 돌아가 보면, Rational 클래스의 값을 돌려주도록 toString 메서드를 재정의했음을 알 수 있다. 이 메서드는 앞으로 RunRational 예제에서 Rational 클래스를 다루기 시작할 때 유용하게 쓰일 것이다.

단, 여기서 toString 주변의 문법을 유의 깊게 살펴보자. 스칼라가 베이스 클래스(base class)에 재정의할 메서드가 있는지를 확인할 수 있게 메서드 정의 선두에 override 키워드가 있어야 한다. 이는 타이핑 실수로 생기는 미묘한 오류를 예방하는 데 도움을 준다(자바 5에서 @Override 애노테이션(annotation)을 추가한 이유와 같다). 또 메서드 내부를 보면 알 수 있기는 하지만 리턴 타입을 써 주지 않았고, return 키워드로 리턴 값을 명시적으로 지정하지도 않았다. 당연하지만 자바에서는 반드시 지정해야 하는 것들이다. 대신 스칼라에서는 함수의 마지막 값을 리턴 값으로 취급한다(자바 문법이 더 좋다면 return 키워드를 사용해도 무방하다).




위로


핵심적인 값들

다음으로 numer와 denom의 정의를 각각 살펴보자. 자바 프로그래머라면 문법만 얼핏 봐서는 numerdenom이 각각 n 나누기 gd 나누기 g로 초기화된 Int 필드라고 생각할 것이다. 하지만 실상은 그렇지 않다.

엄밀히 말해 스칼라는 numerdenom 메서드를 인자 없이 호출하는 것이다. 즉 스칼라에서 접근자(accessor)를 정의하는 빠르고 쉬운 문법이다. Rational 클래스는 그 외에도 numer, denom, g라는 private 필드가 있지만 numerdenom은 기본이 private 접근이고 g는 private 접근으로 명시되어 있어 외부로부터 숨겨져 있다 (역주: 앞서처럼 원문에서는 여기도 numer와 denom 대신 n과 d라고 하고 있으나 n과 d는 생성자의 인자일 뿐이다. 본문에서 numer와 denom은 메서드라고 설명하고 있지만 아래 역컴파일 결과를 보면 알 수 있듯 같은 이름의 private 필드도 자동으로 정의된다).

이쯤 되면 여러분 내면의 자바 프로그래머가 "numordenom의 값을 바꾸는 설정자(setter)는 어디 있지?"라고 물을지도 모르겠다. 사실 그런 설정자는 없다. 스칼라의 뛰어난 점 중 하나는 기본적으로 개발자가 내용을 바꿀 수 없는 객체를 만들도록 장려한다는 데 있다. 필요한 경우 Rational 내부를 수정하는 메서드를 생성할 수 있는 문법은 있지만 그렇게 하면 자동적으로 멀티스레드에 안전한 클래스 특성이 훼손된다. 따라서 최소한 이번 예제에서는 Rational 클래스를 그대로 두자.

내용을 바꿀 수 없으면 Rational 객체를 어떻게 다룰 수 있냐는 의문이 생기는 건 당연하다. java.lang.String 객체와 마찬가지로 이미 생성된 Rational 객체를 가져다가 값을 수정할 수는 없다. 따라서 유일한 대안은 이미 생성된 Rational 객체의 값에서 새로운 Rational 객체를 생성하거나 아예 처음부터 새 값을 줘서 생성하는 것뿐이다. 이런 관점에서 +, -, *, /라는 다소 신기한 이름의 메서드 네 개를 주목해 보자.

참고로 보이는 것과는 달리 해당 메서드들은 연산자 중복 정의(operator-overloading)는 아니다.




위로


연산자여, 내게 숫자를 줘

(역주: Operator, ring me a number가 원문이며 "교환원, 이 번호로 연결해 주세요"라는 뜻으로도 해석될 수 있는 중의적인 표현이다.)

스칼라에서는 "모든 것은 객체"다. 지난 글에서 이 원칙이 함수도 객체라는 발상에 어떻게 적용되는지를 살펴 보았다. 스칼라에서는 함수를 변수에 대입하거나 객체 인자로 함수에 넘길 수도 있다. 이 원칙과 똑같이 중요한 원칙은 "모든 것은 함수"라는 것이다. 즉 이번 예제에서 add라는 함수와 +라는 함수 사이에는 아무런 차이도 없다. 어쩌다 보니 우스꽝스런 이름이 붙었을 뿐 스칼라에서 모든 연산자는 클래스에 정의된 함수다.

Rational 클래스에는 연산자가 네 개 정의되어 있는데 더하기, 빼기, 곱하기, 나누기 등 모두 표준 수학 연산자다. 이름은 각기 해당하는 수학 기호인 +, -, *, / 이다.

하지만 각 연산자가 매번 새 Rational 객체를 생성하는 방식으로 동작한다는 점에 유의하자. 다시 말하지만 이는 java.lang.String의 동작 방식과 매우 비슷하고, 멀티스레드에 안전한 코드가 되기 때문에 스칼라에서는 기본 구현이다. (공유되는 상태가 특정 스레드에 의해 변경되지 않는다면 해당 상태를 동시적으로 접근하더라도 걱정할 필요가 없다. 여러 스레드 간에 공유되는 객체의 내부 상태도 암묵적으로 공유되는 상태다.)

네 어디가 그렇게 새롭니?

"모든 것은 함수"라는 규칙에는 두 가지 강력한 효과가 있다.

첫째, 앞서 봤듯 함수 자체를 객체로 취급하고 저장할 수 있다. 이를 통해 지난 글에서 살펴본 것처럼 효과적인 재사용 시나리오가 가능하다.

둘째, 스칼라 언어 설계자가 제공하겠다고 생각한 연산자와 스칼라 프로그래머가 제공되어야 한다고 생각하는 연산자 사이에 특별히 구분이 없다. 예를 들어 분자와 분모를 뒤집어 새 Rational 객체를 돌려주는, 유리수의 역(inversion)을 구하는 연산자를 추가한다고 생각해 보자(즉 Rational(2,5)를 주면 Rational(5,2)를 돌려주는 연산자). ~ 기호가 해당 개념을 가장 잘 나타낸다고 하면 그 이름으로 새 메서드를 정의할 수 있고 Listing 5에서 보듯 자바 코드의 다른 연산자와 똑같이 동작한다.


Listing 5. 뒤집어 보자
                
  val r6 = ~r1
  Console.println(r6) // should print [3 / 1], since r1 = [1 / 3]

스칼라에서 이 단항 연산자를 정의하는 것은 약간 꼼수가 필요하다. 하지만 순수하게 문법적인 흠이다.


Listing 6. 다음처럼 뒤집는다.
                
class Rational(n:Int, d:Int)
{
  // ... as before ...

  def unary_~ : Rational =
    new Rational(denom, numer)
}

약간 꼼수를 쓴 부분은 당연하지만 단항 연산자로 쓸 거라는 것을 스칼라 컴파일러에 알려주기 위해 unary_ ~ 앞에 "unary_"를 덧붙이는 부분이다. 이렇게 하면 다른 객체 지향 언어에서 일반적인 객체 참조 다음에 메서드를 적는 것과 달리 순서가 뒤집힌다.

이런 특성은 "모든 것은 객체"라는 규칙과 함께 효과적이지만 설명하기 쉬운 몇 가지 코드 형태를 가능하게 해 준다.


Listing 7. 값 더하기
                
  1 + 2 + 3 // same as 1.+(2.+(3))
  r1 + r2 + r3 // same as r1.+(r2.+(r3))

스칼라 컴파일러는 직관적인 정수 덧셈 예제에 대해서는 응당 정해진 대로 동작한다. 하지만 유리수의 경우도 문법적으로는 모두 같다. 이는 프로그래머가 스칼라 언어에 포함된 "내장(built-in)" 타입과 차이가 없는 타입을 개발할 수 있다는 것을 의미한다.

심지어 스칼라 컴파일러는 += 연산자처럼 의미가 미리 정해진 "연산자"에서조차 뭔가 의미를 추론하려고 시도한다. 예를 들어 다음 코드는 Rational 클래스에 += 연산자를 명시적으로 정의하지 않았는데도 기대하는 대로 동작한다.


Listing 8. 스칼라는 추론한다.
                  
  var r5 = new Rational(3,4)
  r5 += r1
  Console.println(r5)

출력해 보면 r5는 짐작한 대로 [13 / 12]다.




위로


스칼라의 동작 원리

스칼라는 자바 바이트코드로 컴파일되고 당연하지만 JVM 위에서 실행된다. 이는 스칼라 컴파일러가 javac와 마찬가지로 0xCAFEBABE로 시작하는 .class 파일을 토해 놓는다는 것만 봐도 자명하다. 또한 JDK에 포함된 자바 바이트코드 역어셈블러(javap)를 생성된 Rational 클래스에 걸었을 때 어떤 결과가 나오는지도 살펴 보라. Listing 9에 결과를 보였다.


Listing 9. rational.scala를 컴파일해 나오는 클래스들
                  
C:\Projects\scala-classes\code>javap -private -classpath classes Rational
Compiled from "rational.scala"
public class Rational extends java.lang.Object implements scala.ScalaObject{
    private int denom;
    private int numer;
    private int g;
    public Rational(int, int);
    public Rational unary_$tilde();
    public java.lang.String toString();
    public Rational $div(Rational);
    public Rational $times(Rational);
    public Rational $minus(Rational);
    public Rational $plus(Rational);
    public int denom();
    public int numer();
    private int g();
    private int gcd(int, int);
    public Rational(int);
    public int $tag();
}


C:\Projects\scala-classes\code>

스칼라 클래스에 정의된 "연산자"는 이름이 이상하기는 하지만 자바 프로그래밍 관례에 따라 메서드 호출로 변환된다. Rational 클래스에는 생성자가 두 개 정의되어 있는데 하나는 인자로 int 값 하나를 받고 다른 하나는 int 두 개를 받는다. 혹자는 대문자로 시작하는 int 타입을 보고 java.lang.Integer를 위장한 것으로 생각했을 수도 있을 것이다. 하지만 스칼라 컴파일러는 클래스 정의 시 Int를 일반적인 자바 기본 타입인 int로 변환할 정도로 똑똑하다.

시험 중, 시험 중, 하나, 둘, 셋…

좋은 프로그래머는 코드를 작성하지만 위대한 프로그래머는 테스트를 작성한다는 것은 잘 알려진 격언이다. 지금까지 보인 스칼라 코드에서는 이 규칙을 따르는 데 있어 다소 소홀했다. 그래서 이번에는 Rational 클래스를 전통적인 JUnit 테스트에 집어 넣으면 어떻게 되는지를 살펴보자. Listing 10을 보자.


Listing 10. RationalTest.java
                
import org.junit.*;
import static org.junit.Assert.*;

public class RationalTest
{
    @Test public void test2ArgRationalConstructor()
    {
        Rational r = new Rational(2, 5);

        assertTrue(r.numer() == 2);
        assertTrue(r.denom() == 5);
    }
    
    @Test public void test1ArgRationalConstructor()
    {
        Rational r = new Rational(5);

        assertTrue(r.numer() == 0);
        assertTrue(r.denom() == 1);
            // 1 because of gcd() invocation during construction;
            // 0-over-5 is the same as 0-over-1
    }    
    
    @Test public void testAddRationals()
    {
        Rational r1 = new Rational(2, 5);
        Rational r2 = new Rational(1, 3);

        Rational r3 = (Rational) reflectInvoke(r1, "$plus", r2); //r1.$plus(r2);

        assertTrue(r3.numer() == 11);
        assertTrue(r3.denom() == 15);
    }
    
    // ... some details omitted
}

SUnit

이미 SUnit이라는 스칼라에 기반을 둔 단위 테스트 도구도 있다. Listing 10에 있는 테스트에 SUnit을 썼다면 리플렉션 기반의 대안을 쓸 필요가 없었을 것이다. 스칼라 기반의 단위 테스트 코드는 스칼라 클래스에 맞게 컴파일된다. 따라서 컴파일러가 기호를 적절히 조율할 수 있다. 프로그래머에 따라서는 POJO를 다루면서 다른 방법 대신 스칼라로 단위 테스트를 작성하는 것을 더 매력적으로 느끼기도 한다.

SUnit은 표준 스칼라 배포판의 scala.testing 패키지 내에 포함되어 있다(SUnit에 대한 추가 정보는 참고자료를 살펴 본다).

Rational 클래스가 잘, 합당하게 동작한다는 것을 확인하는 것 외에 위 테스트는 자바 코드에서 스칼라 코드를 호출할 수 있다는 것을 보여준다. 연산자를 쓸 때 약간 엇박자가 나기는 하지만 말이다. 여기서 좋은 점은 관련 테스트 코드를 바꿀 필요 없이 자바 클래스를 스칼라 클래스로 옮겨가면서 천천히 스칼라를 사용해 볼 수 있다는 점이다.

테스트 코드에서 유일하게 어색한 부분은 연산자 호출이다. 즉 이 예제에서는 Rational 클래스의 + 메서드를 호출하는 부분이다. javap 출력을 다시 보면 스칼라가 + 함수를 JVM 메서드 $plus로 변환했다는 것을 알 수 있다. 하지만 자바 언어 명세에 따르면 식별자(identifier)에 $ 문자를 쓸 수 없다. (그래서 $ 문자가 내부 클래스나 무명 내부 클래스 이름에 사용되는 것이다.)

그런 메서드를 호출하려면 테스트를 그루비(Groovy)나 JRuby 언어(혹은 $ 문자에 제약을 두지 않는 다른 언어)로 작성하거나 약간의 Reflection 코드를 작성해야 한다. 여기서는 후자를 택했는데 스칼라 관점에서는 그다지 중요하지 않다. 하지만 이 글의 코드 번들에 포함된 결과에는 관심을 가지기 바란다(다운로드 부분을 본다).

이런 대안은 자바 식별자로 사용될 수 없는 함수 이름에만 필요하다.




위로


더 "나은" 자바

필자가 처음 C++를 배울 때 Bjarne Stroustrup은 C++를 배우는 방법 중 하나로 C++를 "더 나은 C"(참고자료를 보라)로 보도록 권했다. 스칼라는 전통적인 자바 POJO(역주: Plain Old Java Object의 약자)를 작성하는 더욱 간결한 방법을 제공하기 때문에, 어떤 관점에서는 오늘날 자바 개발자도 스칼라를 "더 나은 자바"로 봐야 할지도 모르겠다. Listing 11의 전통적인 Person이라는 POJO를 살펴 보자.


Listing 11. JavaPerson.java(원 POJO)
                
public class JavaPerson
{
    public JavaPerson(String firstName, String lastName, int age)
    {
        this.firstName = firstName;
        this.lastName = lastName;
        this.age = age;
    }
    
    public String getFirstName()
    {
        return this.firstName;
    }
    public void setFirstName(String value)
    {
        this.firstName = value;
    }
    
    public String getLastName()
    {
        return this.lastName;
    }
    public void setLastName(String value)
    {
        this.lastName = value;
    }
    
    public int getAge()
    {
        return this.age;
    }
    public void setAge(int value)
    {
        this.age = value;
    }
    
    public String toString()
    {
        return "[Person: firstName" + firstName + " lastName:" + lastName +
            " age:" + age + " ]";
    }
    
    private String firstName;
    private String lastName;
    private int age;
}

이제 같은 클래스를 스칼라로 작성해 보자.


Listing 12. person.scala(멀티스레드에 안전한 POJO)
                
class Person(firstName:String, lastName:String, age:Int)
{
    def getFirstName = firstName
    def getLastName = lastName
    def getAge = age

    override def toString =
        "[Person firstName:" + firstName + " lastName:" + lastName +
            " age:" + age + " ]"
}

Listing 12에서 정의한 클래스를 Listing 11에서 정의한 클래스가 사용되는 곳에 그대로 대체해 넣을 수는 없다. Listing 11의 Person 클래스는 내용을 바꾸는 설정자(setter)가 있기 때문이다. 하지만 원 Person의 변경자 주위에 동기화를 위한 코드가 없다는 점을 고려하면 스칼라 쪽이 사용하기에 더 안전하다. 또한 여기서 목적이 Person의 코드 행 개수를 줄이는 것이라면 스칼라가 각 생성자 인자마다 자동으로 접근자 메서드를 생성한다는 점을 고려해 getFoo 형태의 프로퍼티 메서드를 완전히 없앨 수도 있다. 그렇게 하면 String을 돌려주는 firstName()lastName(), int를 돌려주는 age() 함수가 생긴다.

심지어 내용을 변경하는 변경자가 반드시 필요한 경우라도 Listing 13에서 보듯이 스칼라 쪽이 더 간단하다.


Listing 13. person.scala(완전한 POJO)
                
class Person(var firstName:String, var lastName:String, var age:Int)
{
    def getFirstName = firstName
    def getLastName = lastName
    def getAge = age
    
    def setFirstName(value:String):Unit = firstName = value
    def setLastName(value:String) = lastName = value
    def setAge(value:Int) = age = value

    override def toString =
        "[Person firstName:" + firstName + " lastName:" + lastName +
            " age:" + age + " ]"
}

참고로 생성자 인자에 var 키워드가 추가됐음을 눈 여겨 보자. 너무 깊게 들어가지 않고 설명하면 var는 해당 값이 변할 수 있다는 것을 컴파일러에 통보하는 역할을 한다. 따라서 스칼라는 접근자(String firstName(void))와 변경자(void firstName_$eq(String))를 모두 생성한다. 일단 변경자가 생성되면 이를 사용해 setFoo 프로퍼티 변경 메서드를 쉽게 추가할 수 있다.




위로


결론

스칼라는 객체 지향 패러다임의 장점을 잃지 않고 함수적 개념과 간결함을 통합하려는 시도다. 이 연재에서 이미 느꼈을지도 모르지만 스칼라는 (뒤늦기는 하지만) 자바 언어에 있는 끔직한 문법 문제를 해결한다.

이번 "바쁜 자바 개발자를 위한 스칼라 입문"의 두 번째 글에서는 스칼라의 객체 지원을 살펴 보았다. 스칼라의 객체 지원으로 함수 개념에 깊은 이해 없이도 스칼라를 사용하기 시작할 수 있을 것이다. 지금까지 배운 것만 가지고도 프로그래밍 작업을 줄이는 데 스칼라를 사용하기 시작할 수 있다. 예를 들면 스칼라로 스프링(Spring)이나 하이버네이트(Hibernate) 같은 다른 프로그래밍 환경에 필요한 POJO를 만들 수 있다.

하지만 이제 잠수모와 호흡 장치를 단단히 잡기 바란다. 이 연재의 다음 글은 함수 개념이라는 풀의 깊은 바닥까지 내려가는 시발점이 될 테니까 말이다.





위로


다운로드 하십시오

설명이름크기다운로드 방식
이 기사의 스칼라 코드 예제j-scala02198-code.zip2.6MBHTTP
다운로드 방식에 대한 정보


참고자료

교육

제품 및 기술 얻기
  • Scala: 스칼라를 다운로드해 이 연재를 따라가며 배워보자!

  • SUnit: 스칼라 배포판의 일부로 scala.testing 패키지에 정의되어 있다.


토론


필자소개

Ted Neward photo

Ted Neward는 Neward & Associates의 사장으로 자바, .NET, XML 서비스와 다른 플랫폼에 대한 컨설팅, 조언, 교육, 강연을 한다. 워싱턴 주 시애틀 근처에 산다.




기사에 대한 평가


보다 나은 서비스를 제공하기 위함이오니 잠시 짬을 내어 이 양식을 제출하여 주십시오.



아니오잘 모르겠음
 


 


12345
 


이 문서 북마킹 하기

mar.gar.in mar.gar.in naver naver eolin eolin del.icio.us del.icio.us





위로


Java and all Java-based trademarks are trademarks of Sun Microsystems, Inc. in the United States, other countries, or both. 기타 회사, 제품, 및 서비스명은 다른 상표나 서비스 마크일 수 있습니다.

developerWorks 콘텐트를 다른 사이트에 전재하기:
developerWorks 콘텐트에 대한 저작권은 IBM에 있습니다. IBM의 서면 허가나 원본 저자의 허락이 없이는 전재를 금합니다. 저희 콘텐트를 전재하시려면 IBM developerWorks 담당자 에게 문의하십시오.
    IBM 소개 개인정보 보호정책 문의