2012년 8월 6일 월요일

Java 에서 객체의 초기화 (2)

>> Java에서 객체의 초기화(1) 에서 이어짐.


 
생성자 (Constructors)

객체 초기화의 중심요소는 '생성자'이다. 자바에서, 생성자는 메서드와 비슷하나, 메서드는 아니다.생성자는 메서드처럼 파라미터를 셋팅할 수 있고, 코드로 된 몸체를 가진다. 그러나 생성자는 return type 이 없어 메서드와는 다르다. 개발자는 메서드와 마찬가지로 생성자에 특정 접근권한을 줄 수 있지만, public, protected, package 접근자가 붙은 생성자는 서브클래스에 상속되지 않는다. (생성자의 access level 은 단순히 생성자 호출가능 여부가 아니라 객체의 인스턴스화를 결정한다.)


생성자의 기초 (Constructor basics)

소스파일에서 생성자는 클래스의 이름과 같은 이름을 가진 메서드 선언(declaration)처럼 보이지만, return type 이 없다. CoffeCup 클래스에서 생성자의 선언은 다음과 같다 :


// In source packet in file init/ex2/CoffeeCup.java   
 
class CoffeeCup {
    // Constructor looks like a method declaration
    // minus the return type
    public CoffeeCup() {
        // Body of constructor
    }
    // ...
}


메서드 처럼, 파라미터의 순서, 개수, 타입의 다양화를 통해 생성자를 오버로드할 수 있다. 두 개의 생성자를 가진 CoffeeCup 클래스는 다음과 같다 :

// In source packet in file init/ex3/CoffeeCup.java   
 
class CoffeeCup {
    private int innerCoffee;
    public CoffeeCup() {
        innerCoffee = 237;
    }
    public CoffeeCup(int amount) {
        innerCoffee = amount;
    }
    // ...
}


객체가 new 연산자로 초기화될 때, 생성자는 반드시 명시되어야 한다. 다음과 같이 두 개의 생성자를 가진 CoffeeCup 클래스는 두가지 방법으로 초기화될 수 있다 :

// In source packet in file init/ex3/Example3.java   
 
class Example3 {
    public static void main(String[] args) {
        // Create an empty cup
        CoffeeCup cup1 = new CoffeeCup();
        // Create a cup with 355 ml of coffee in it
        CoffeeCup cup2 = new CoffeeCup(355);
    }
}



인자가 없는 생성자 (The no-arg constructor)

자바 용어에서 파라미터를 가지지 않은(혹은 인자가 없는) 생성자는 "no-arg constructors"로 불린다. 코드에서 보여지듯, CoffeeCup 객체의 첫번째 인스턴스화는 인자가 없는 생성자에 명시되어있다. 두번째 인스턴스화는 int 형 파라미터를 요구하는 생성자에 명시되어있다.


this() 호출 (The this() invocation)

You may want to do this if you have several overloaded constructors in a class, all of which must execute much of the same code. Here's an example:

생성자로부터, this() 문을 사용함으로서 동일한 클래스에서 또다른 생성자를 명시적으로 호출할 수 있다. 클래스에서 여러 오버로드된 생성자가 있다면, 다음과 같이 모두 거의 동일한 코드를 수행해야만 한다.

// In source packet in file init/ex4/CoffeeCup.java   
 
class CoffeeCup {
    private int innerCoffee;
    public CoffeeCup() {
        this(237); // Calls other constructor
        // Could have done more construction here
    }
    public CoffeeCup(int amount) {
        innerCoffee = amount;
    }
    // ...
}


예와 같이, 인자가 없는 생성자는 int 와 같은 파라미터를 가진 또 다른 생성자를 호출한다. 237 이라는 값을 다른 생성자에 넘김으로서 innerCoffe 에 값을 할당한다.

메서드에서는 this()를 호출할 수 없다. 생성자에서 this()를 호출한다면, 반드시 그것을 생성자 내의 다른 코드 이전에 첫번째로 호출해야만 한다. 그리고, this()는 단 한번만 호출할 수 있다. this()가 호출된 후에 포함된 다른 코드들은 호출된 생성자가 완료된 후에 수행된다.


생성자는 메서드가 아니다.

메서드와 생성자사이의 다른 점은 다음 사실을 살펴보며 설명하겠다 : The name of a class is a valid name for its methods. In other words, class CoffeeCup could have methods named CoffeeCup:
클래스의 이름은 클래스에 속한 메서드의 이름에 적합한 이름이다. 달리말하면, CoffeeCup 클래스는 CoffeeCup 이란 메서드를 가질 수 있다.

// In source packet in file init/ex5/CoffeeCup.java
// THIS WORKS, BUT IT IS AN EXAMPLE OF POOR METHOD NAMING  
 
class CoffeeCup {
    private int innerCoffee;
    public CoffeeCup() {    // The constructor
        innerCoffee = 237;
    }
    public void CoffeeCup() {   // The method
        innerCoffee = 99;
    }
    // ...
}


위의 소스코드에서 CoffeeCup 클래스의 정의를 감안할 때, 다음과 같이 가능하다 :


// In source packet in file init/ex5/Example5.java 
 
class Example5 {
    public static void main(String[] args) {
        CoffeeCup cup = new CoffeeCup(); // invoke the constructor  
        cup.CoffeeCup(); // invoke the method
    }
}


비록 클래스명칭과 같은 이름의 메서드를 만들 수 있다하더라도, 실제론 다른 개발자들이 생성자와 혼동할 수도 있으며, 올바른 메서드 디자인 방식을 깨는 것이기에 결코 그렇게하면 안된다.

첫째, 클래스명은 '동사'가 아니라 '명사'이다.(적어도 '명사'여야 한다.) 메서드명칭은 동사여야 한다. 메서드가 수행하는 동작을 명칭으로 써야한다. 'CoffeeCup'은 동작이 아니다. 또한 'CoffeeCup'은 첫번째문자가 소문자여야 한다는 명명규칙 역시 따르지 않았다. 이 예제의 목적은 단지 생성자와 같은 명칭의 메서드가 생성자와 충돌하지 않는다는 것을 보여줌으로서 생성자는 메서드가 아니다라는 사실을 강조하는 것이다.


기본생성자(Default constructors)

만약 클래스에 생성자가 선언되어있지 않다면, 컴파일러는 자동으로 기본생성자(Default Constructor)를 생성한다. 기본 생성자는 파라미터가 없으며(no-arg constructor), 빈 (코드)몸체를 가진다. 개발자가 명시적으로 생성자를 선언하지 않았을 경우, 컴파일러가 자동적으로 기본생성자를 생성해주기 때문이다. 모든 클래스는 최소한 하나의 생성자가 생성된다.  예를 들어, CoffeeCup 클래스에 생성자가 선언되어있지 않은 경우는 다음과 같다. :



// In source packet in file init/ex6/CoffeeCup.java

class CoffeeCup {
    private int innerCoffee;
    public void add(int amount) {
        innerCoffee += amount;
    }
    //...
}


컴파일러는 마치 개발자가 명시적으로 빈 몸통을 가진 인자가 없는 생성자(no-arg constructor)를 명시적으로 선언한 것과 같은 클래스파일을 생성할 것이다. :


// In source packet in file init/ex7/CoffeeCup.java

class CoffeeCup {
    private int innerCoffee;
        public CoffeeCup() {
    }
    public void add(int amount) {
        innerCoffee += amount;
    }
    //...
}

컴파일러는 클래스 자체의 접근레벨과 동일한 권한을 가진 기본생성자를 제공한다. 이전 예제처럼 CoffeeCup 클래스는 public 이며, 기본생성자도 public 이다. 만약 CoffeeCup 클래스가 package 레벨의 접근권한을 가지고 있다면, 기본 생성자 역시 그러할 것이다.



>>  Java 에서 객체의 초기화 (3) 으로 이어짐.