본문 바로가기
JAVA

[JAVA] Chapter 7. Class (2)

by varcode 2023. 7. 8.
반응형

지난 포스팅에서 Naming Rule을 다루었는데, Naming Rule을 모르면 JAVA를 사용하지 못하는 것은 아니지만 Rule을 지키는 것이 협업에서 굉장히 중요하듯이, JAVA를 JAVA답게 사용하기 위하여 알아야하는 Class 개념이 있다.

 

① Message Passing
하나의 요구사항 != 하나의 클래스인데 클래스 간의 관계를 어떻게 설정해야 할까?
객체 지향
에서는 다른 클래스에 직접 접근해서 변수를 건드릴 수 없다. 클래스 안에서 선언되는 변수는 반드시 같은 클래스 내부에 있는 메서드로만 핸들링해야 한다. 따라서 내가 필요한 데이터를 넘겨주는 메서드를 찾은 후 리턴 값을 받아야 한다.
이처럼 객체 지향 프로그래밍에서 객체 간 상호 작용을 위해 메시지를 전달하는 것을 message passing이라고 한다. 메시지 전달을 통해 객체 간의 상호작용이 이루어지기 때문에 객체 간의 결합도가 낮아져 캡슐화, 추상화 및 다형성을 가능하게 한다.

 

② 생성자

class Bank {
    final int myMoney = 1000;
    final int numOfCoin = 20;
    
    public Bank(int money, int coin) {
        myMoney = money;
        numOfCoin = coin;
    }
}

클래스 내부의 변수를 final로 선언하면 값을 바꿀 수 없기 때문에 생성과 동시에 초기화를 해야 한다. 하지만 코드의 확장성을 위해서는 인스턴스를 생성하면서 전달받은 파라미터로 값을 초기화하는 것이 좋다. 이를 위해 final을 지우면 코드의 안정성이 떨어진다.

class Bank {
    int myMoney;
    int numOfCoin;
    
    public Bank(int money, int coin) {
        myMoney = money;
        numOfCoin = coin;
    }
}

 

이 상황에서 필요한 것이 바로 "생성자"다. 생성자(Constructor)란 객체가 생성될 때 호출되는 메서드로, 생성자는 final로 선언된 상수의 값을 한번 변경할 수 있기 때문에 객체 생성 시 필요한 초기화 작업을 수행한다. 생성자는 클래스와 같은 이름으로 정의되며 반환값이 없다. 추후에 다루겠지만, 자바에서는 생성자를 오버 로딩하여 여러 개의 생성자를 정의할 수 있다. 생성자를 명시적으로 정의하지 않으면 컴파일러가 자동으로 default 생성자를 추가한다.

 

그런데, Car myCar = new Car()이라는 코드에서 Car 옆에 소괄호를 쓰는 이유는?
Car myCar = new Car();
에서 Car()은 생성자(constructor)를 호출하기 위한 것이다. new Car에서 Car 클래스의 인스턴스를 생성하고, Car()에서 생성자를 호출하여 해당 인스턴스를 초기화한다. 생성자가 객체를 생성할 때 호출되어야 하기 때문에 클래스 이름과 생성자의 이름이 같아야 하는 것이다.

 

인스턴스 변수를 초기화시키는 방법
1. =
으로 초기화
2.
생성자로 초기화
3. setter
메서드를 사용해서 초기화
java
에서 변수나 상수에 값을 넣을 때 사용하는 메서드는 set, 빼낼 때는 get으로 시작하는 메서드를 사용하고 getter, setter라고 부른다. 하지만 setter로는 final로 선언된 상수를 초기화할 수 없다.

 

접근 제어

class Bank {
    int myMoney;
    int numOfCoin;
    public Bank() {...}
}

class Customer {
    public static void main(String[] args) {
        Bank bank = new Bank();
        bank.myMoney += 500;
    }
}

위 코드를 보면, main 메서드에서 Bank 클래스의 인스턴스 변수(myMoney)에 직접 접근하여 값을 수정했다. 이는 돈을 대출하는 클래스를 잘 만들었는데, 돈을 받는 쪽에서 가격을 잘못 입력하는 경우와 같다. Java에서는 한 클래스에서 다른 클래스의 변수에 직접 접근하는 것을 권장하지 않는다. Java에는 문제 예방을 위해 일부러 compile time error를 만들어내는 테크닉들이 있는데, 그중 하나가 접근 제어 지시자를 사용하는 것이다.

 

Access Control Specifier, 접근 제어 지시자
Java에서는 클래스, 변수, 메서드 앞에 접근 제어 지시자를 사용하여 접근 범위를 제어할 수 있다.

1. private : private이 붙은 변수나 메서드는 같은 클래스 내부에서만 접근이 가능하다. 이를 통해 정보 은닉 (Information hiding)이 가능하며, message passing을 통해서만 변수를 조작할 수 있도록 클래스 내부의 인스턴스 변수에는 private을 붙이는 것이 좋다.

2. default : default public, protected, private가 붙어있지 않은 것으로, 같은 패키지 내부에서만 접근이 가능하다.

3. protected : protecteddefault의 확장으로, 다른 패키지더라도 상속이 걸린 클래스라면 접근이 가능하다.

4. public : public 접근 제어 지시자는 접근 제한이 없다.

 

singleton pattern

public class A {
    private A() {
        // code
    }
}

위의 코드는 클래스 앞에 public이 붙어 있으므로 누구나 접근이 가능하다고 생각할 수 있지만, 생성자를 호출할 수 없으므로 인스턴스를 만들 수 없다. 다른 클래스에서 A() 메서드에 접근할 수 없기 때문에 A rv = new A();를 적으면 compile error가 뜬다. , 위의 형태는 같은 클래스 내부에서만 접근 가능하다.

Singleton pattern은 오직 하나의 인스턴스만 생성되도록 하는 디자인 패턴이다. 외부에서 생성자를 호출할 수 없고, 클래스 내부에서 유일한 인스턴스를 생성하고 반환하는 메서드를 호출할 수 있다.
Singleton pattern
을 사용하면 객체 생성과 소멸에 대한 관리를 효율적으로 할 수 있고, 하나의 인스턴스만 생성되므로 여러 곳에서 공유해서 사용해야 하는 경우에도 문제가 발생하지 않는다.

반응형

'JAVA' 카테고리의 다른 글

[JAVA] Chapter 8. Class Variable & Class Method  (0) 2023.07.10
[JAVA] Chapter 7. Class (3)  (0) 2023.07.09
[JAVA] Chapter 7. Class (1)  (0) 2023.07.07
[JAVA] Chapter 6. Method  (0) 2023.07.06
[JAVA] Chapter 5. Control  (0) 2023.07.05

댓글