본문 바로가기

JAVA

캡슐화와 정보은폐

<font color='red'>public은 위에서 클래스를 지정할 때 여러 차례 나왔다. public은 단어 뜻 그대로 데이터를 완전히 공개한다.</font>


즉 외부로부터의직접적인 접근을 전혀 제한하지 않는다는 것이다. 한마디로 모든
클래스에서 직접적인 접근이 가능하다.

<font color='red'>private는 public과는 완전히 반대로 오직 클래스 자신만이 사용할 수 있도록 한다. 서브클래스는 물론 같은 패키지의 다른 클래스에게도 이를 공개하지
않으며, 서브 클래스에게 private로 선언된 데이터는 상속되지 않는다.</font>


<font color='red'>protected는 자신과 자신의 서브 클래스, 같은 패키지 내의 다른 클래스에게만 정보를 공개한다. 만약 서브 클래스도 아니고 같은 패키지에 소속돼 있지 않는 클래스로부터 접근된다면 이를 금지하게 된다. 서브 클래스에게는 공개되므로 protected로 선언된 데이터는 당연히 서브 클래스로 상속된다. </font>

<font color='red'>private protected는 자신과 자신의 서브 클래스에게만 정보를 공개한다. protected와 차이는 같은 패키지에 속한 다른 클래스에게 공개하지 않는다는 점이다. 서브 클래스에게 공개하므로 이로 선언된 데이터는 상속된다.</font>


<font color='red'>default는 위에서도 말했지만‘default’라고 지정하는 것이 아니라 아무 것도 지정하지 않은 것이다. 이 경우 자신과 같은 패키지의 다른 클래스에게만 정보를 공개한다. private protected와의 차이는 서브 클래스에게 공개를 안하다는 것이다. 여기서 주의할점은 같은 패키지인가 아닌가를 먼저 평가해 본다는 것으로, 설령
서브 클래스라 하더라도 같은 패키지에 속해 있다면 그 서브 클래스에게 공개한다. 다시 말해 아무런 관련 없는 클래스와 패키지 소속이 다른 서브 클래스에게는 공개하지 않는다. 데이터 상속 역시 서브 클래스의 같은 패키지 소속 여부에 따라 달라진다.</font>

처음에 이것을 읽어보면 대단히 혼동될 것이다. public과
private는 구분이 잘 가는데 나머지 3단계는 이것이 저것같고. 예
제와 필자 나름대로 개발(?)한 기억법을 통해 이들을 완전히 이해
하도록 하자. 이제 나올 예제는 어떤 한 가정에서 임종을 맞이한
아버지에 관한 것이다. 그와 그의 친형, 그의 아들, 혈육은 아니지
만 대부가 되어 생긴 양아들, 이들과 전혀 모르고 지나는 기타 세
상 사람들이란 상황을 두고 있다. 이게 갑자기 무슨 소리인가 하
겠지만 차츰 읽어가다 보면 왜 이런 예제를 들었는지 알게 될 것
이다.
이 예제에는 2개의 패키지가 있다. blood와 non_blood인데 이
는 곧 혈육인가 아닌가를 나타낸다. 아들(blood_son), 친형
(old_brother)은 혈육이므로 아버지와 같은 blood 패키지에 속하
고, 양아들(non_blood_son)과 기타 세상 사람들(people)은 혈육
이 아니므로 non_blood 패키지에 속한다. 정리하면 패키지는 혈
육이고, 서브 클래스는 자식이다.
이 예제를 실제 컴파일해 보면서 테스트하려면 현재의 작업 디
렉토리 밑에 blood란 서브 디렉토리가 있어야 하며, 그 blood 디렉
토리에 father.java를 컴파일한 결과가 들어가야 한다(<그림 8>).
이는 패키지 사용에 관련된 규칙으로 여기서는 설명을 생략한다.


<font color='blue'>
[father.java]
package blood;
public class father
{
private boolean death = true;//죽음(death)은 아버지만 가지는 것이다.
private protected boolean estate = true;
//아버지의 재산(estate)은 아들들에게 준다.
boolean wife= true;//아버지의 부인(wife)은 혈육들인 아들과 친형에게 맡긴다.
protected boolean grief= true;
/*슬픔(grief)은 아버지, 친형과 아들, 양아들 등 관련 있는 모든 이들이 가진다. */
public boolean clay= true;
//아버지의 몸은 죽어서 모든 이들에게 흙(clay)이 된다.
public father()
{
}
}
</font>


father.java는 5가지 인스턴스 변수를 가지고 있으며 각각의 은
폐 단계는 주석문과 같다. 이를테면 죽음은 아버지만이 가지는 것
이므로 private로 선언돼야 하며, 슬픔은 아버지를 전혀 모르는 사
람들을 제외한 나머지 사람이 가지게 되므로 protected로 선언돼
야 하는 것이다. 다음 각 예제에 컴파일 시 접근 에러가 나는 부분
을 주석 처리해 두었다.


<font color='blue'>
[blood_son.java]
package blood;
public class blood_son extends father
{
public blood_son()
{
//death = false; //컴파일 시 액세스 에러
estate = true;
wife = true;
</font>


고, 여기서 답만 이야기하자면 바로 Object라는 자바에 내장된
(pre-built) 클래스가 Nemo 클래스의 슈퍼 클래스 역할을 한다.
Object 클래스는 비단 Nemo뿐만 아니라 모든 클래스의 슈퍼 클
래스로 기본 지정돼 있다.
생성자 문제가 꽤 복잡하게 보이는데 사실 이런 것에 대해서 크
게 고민할 필요는 없다. 모든 것을 명시적으로 지정해 주기만 하
면 된다. 다만 Object 클래스는 기본 지정이므로 굳이 명시해 줄
필요가 없다.
이제 마지막으로 캡슐화와 정보 은폐에 대해서 다뤄 보기로 하
자. 캡슐화는 특별히 어떤 키워드 지정으로 하는 것은 아니다. 단
지 인스턴스 변수와 메쏘드를 하나의 클래스(객체)로 묶어 놓으
면 된다. 캡슐화는 정보 은폐에서 그 의미를 가진다고 했다. 자바
는 5가지 정보 은폐 단계를 가지고 있다.
■ public
■ protected
■ default
■ private protected
■ private
이의 5단계 정보 은폐를 지정할 때 쓰는 키워드는 public,
private, protected로 사실상 3개이다. private protected는 2개
의 키워드를 합한 것이고, default는 아무런 키워드도 지정하지
않았을 때 말 그대로 디폴트로 지정되는 은폐 단계를 말하는 것
이다. 위의 순서가 대체로 갈수록 심화되는 정보 은폐 단계의 순
서라고 할 수 있다(default와 private protected는 우선순위에서
width 1* height 2 = 2
filling Nemo of 1*2 with 1
모두 초기값만 사용하고 있다. test4에서 nemo1을 생성하려고
fillNemo 클래스 생성자를 부르면, 생성자가 없으므로 기본 생성
자가 대신 쓰인다. 기본 생성자의 역할은 단순히 자신의 슈퍼 클
래스의 생성자를 부르는 것이다(이것이 기본 생성자의 역할이다).
fillNemo 클래스에서‘fill_color = 1’로 초기화되었고, 기본 생성
자에 의해 슈퍼 클래스의 생성자가 불린다. 물론 이때 불리는 슈
퍼 클래스의 생성자는 인수가 없는 super();이다. 즉 fillNemo의
기본 생성자가 암시적으로 불려 쓰이면서 역시 슈퍼 클래스의 생
성자를 암시적으로 부르는 것이다. Nemo 클래스에서 인수가 없
는 Nemo()가 있으므로 아무런 문제 없이 width와 height는 원래
의 초기값으로 초기화되고, 그 결과는 앞과 같은 것이다.
만약 Nemo 클래스의 생성자들까지 모두 없애면 어떻게 될까?
그래도 에러는 나지 않고 여전히 앞과 같은 결과가 출력된다.
fillNemo 클래스에서 기본 생성자가 암시적으로 super();를 부르
는 것까지 같기 때문이다. 이제 앞의 첫번째 실험과는 달리 Nemo
클래스도 명시된 생성자가 없으므로 역시 기본 생성자를 부르고,
이 기본 생성자는 Nemo 클래스의 슈퍼 클래스의 생성자를 암시
적으로 부른다.
Nemo 클래스의 슈퍼 클래스? 눈치가 빠른 독자들은 Nemo 클
래스는 extends로 지정해 둔 슈퍼 클래스가 없다는 것을 금방 인
식했을 것이다. 자바는 모든 클래스에 암시적으로 슈퍼 클래스를
부여하게 돼 있다. 여기서 만든 Nemo 클래스는 비록 extends 키
워드를 통해 명시된 슈퍼 클래스는 없지만(그래서 가장 우두머리
인 것처럼 보이지만) 여전히 어떤 클래스의 서브 클래스로 계층
구조에 속해 있다. 자세한 것은 계속되는 연재에서 다루기로 하
자바에서 패키지(package)는 C++의 클래스 라이브러리같은 것이다.
즉 관련 있는 클래스를 한데 묶어 놓은 것이다. 자바에는 내장된 java
라는 총체적인 패키지가 있고 이 java밑으로 총 8개의 패키지가 들어
있다.
■ applet : 애플릿 구현에 관련한 클래스 모음
■ awt : GUI 요소 및 그래픽 요소들에 관련한 클래스 모음
■ awt.image : 이미지 프로세싱에 관련한 클래스 모음
■ awt.peer : awt 구성 요소에 관련한 클래스 모음
■ io : 각종 I/O에 관련한 클래스 모음
■ lang : 자바의 기본 구성에 관련한 클래스 모음
■ net : 네트워킹에 관련한 클래스 모음
■ util : 자료구조에 관련한 클래스 모음
물론 사용자도 임의의 패키지를 만들 수 있다. 이번호 예제에서도 두 개
의 패키지를 만들어 사용했다.
<그림 8> 패키지 사용을 위한 디렉토리 구성
현재 작업 디렉토리 -- blood(서브 디렉토리)



<font color='blue'>
blood_son.class father.class
old_brother.class
non_blood_son.class
people.class
grief = true;
clay = true;
}
}
blood_son은 father와 같은 패키지이자 서브 클래스이다. 따
라서 private형으로 선언된 death를 빼고는 전부 직접 접근할
수 있다.
[old_brother.java]
package blood;
import blood.father;
class old_brother
{
public old_brother()
{
father my_brother = new father();
//my_brother.death = false; //컴파일 시 액세스 에러
//my_brother.estate = false; //컴파일 시 액세스 에러
my_brother.wife = true;
my_brother.grief = true;
my_brother.clay = true;
}
}
old_brother에서 my_brother란 father형 객체를 하나 선언했
다. old_brother는 father와 같은 패키지란 관계를 가지고 있다. 따
라서 private형인 death와 private protected형인 estate만 빼고
전부 직접 접근이 가능하다.
[non_blood_son.java]
package non_blood;
class non_blood_son extends blood.father
{
public non_blood_son()
{
//death = false; //컴파일 시 액세스 에러
estate = true;
//wife = false; //컴파일 시 액세스 에러
grief = true;
clay = true;
}
}
father와 다른 패키지이자 서브 클래스인 양아들이다. private
형을 사용하지 못하는 것은 당연한 것이다. wife는 default로 선언
돼 있다. default는 같은 패키지에서만 사용 가능하므로 양아들에
서는 사용할 수 없다. 한편 estate는 private protected로 서브 클
래스에서만 사용할 수 있으므로 당연히 양아들에서 직접 접근이
가능하다.
[people.java]
package non_blood;
import blood.father;
public class people
{
public people()
{
father unknown = new father();
//unknown.death = false; //컴파일 시 액세스 에러
//unknown.estate = false; //컴파일 시 액세스 에러
//unknown.wife = false; //컴파일 시 액세스 에러
//unknown.grief = false; //컴파일 시 액세스 에러
unknown.clay = true;
}
}

</font>


people은 father와 아무 관련이 없으므로 public인 clay을 제외
하고는 어느 것도 직접 접근할 수 없다. 혈육에는 양아들은 포함
되지 않는다. 즉 서브 클래스라 하더라도 같은 패키지가 아니면
default로 선언된 데이터를 사용할 수 없다.
이제 protected, default, private protected가 어느 정도 이해될
것이다. 이제 이 3가지를 다음과 같이 기억하면 절대로 잊어버리
지 않을 것이다.

■ subclass는 자식으로서 자신의 분신과 같다고 할 수 있다. 따라서 어느 정도 private하다. -> private protected
■ 그래도 기본적으로 혈육(package)에게 더 정이 가는 법 -> default
■ 아는 사람들은 모두 보호해 주어야 한다 -> protected

'JAVA' 카테고리의 다른 글

jni interface  (0) 2013.09.26
jdk 1.6 + eclise 3.4  (0) 2013.09.26
byteToString  (0) 2013.09.26
JAVA API  (0) 2013.09.26
자바 프로그래밍을 위한 기본 구성 (eclipse, JDK, J2EE)  (0) 2013.09.26