Java, 상속과 접근 제어자
상속 관계의 접근 제어를 위한 코드를 작성한다.
부모와 자식 패키지를 별도로 분리해주어야 한다.

접근 제어자 표현을 위해 UML 표기법 일부 사용
- + : public
- # : protected
- ~ : default
- - : private
접근 제어자 종류
- private: 모든 외부 호출을 거부한다.
- default (package-private): 같은 패키지 안에서 허용한다.
- protected: 같은 패키지 안에서 허용한다. 패키지가 다른 경우 상속 관계만 허용한다.
- public: 모든 외부 호출을 허용한다.
private
거부한 범위가 크고, public
이 허용 범위가 크다.
private -> default -> protected -> public 순으로 허용 범위가 크다.
코드 작성
다음 경로의 파일을 만들도록 한다.
parent, child 패키지가 다르다는 것을 확인하면서 코드를 작성해야 한다.
src
└access (+)
├Main.java
├parent (+)
│ └Parent.java (+)
└child (+)
└Child.java (+)
Parent.java
package access.parent;
public class Parent {
public int publicValue;
protected int protectedValue;
int defaultValue;
private int privateValue;
public void publicMethod() {
System.out.println("Parent::publicMethod");
}
protected void protectedMethod() {
System.out.println("Parent::protectedMethod");
}
void defaultMethod() {
System.out.println("Parent.defaultMethod");
}
private void privateMethod() {
System.out.println("Parent.privateMethod");
}
public void printParent() {
System.out.println("== Parent 메소드 ==");
System.out.println("publicValue = " + publicValue);
System.out.println("protectedValue = " + protectedValue);
System.out.println("defaultValue = " + defaultValue);
System.out.println("privateValue = " + privateValue);
// 모두 접근 가능한 부모 메소드
defaultMethod();
privateMethod();
System.out.println("== Parent 메소드 끝 ==");
}
}
Child.java
package access.child;
import access.parent.Parent;
public class Child extends Parent {
public void call() {
publicValue = 1; // Parent 필드를 상속받아 받아 사용할 수 있다.
protectedValue = 1; // 상속 관계로 허용하고 있다.
// defaultValue = 1; // 컴파일 오류 다른 패키지로 접근 불가 함
// privateValue = 1; // 컴파일 오류, 접근 불가
publicMethod();
protectedMethod(); // 상속 관계로 허용 받아 메소드를 수행 가능하다.
// defaultMethod(); // 컴파일 오류 다른 패키지로 접근 불가 함
// privateMethod(); // 컴파일 오류, 접근 불가
printParent();
}
}
Main.java
package access;
import access.child.Child;
public class Main {
public static void main(String[] args) {
Child child = new Child();
child.call();
}
}
자식 클래스에서 Child 호출하면 부모 클래스의 Parent 에 얼마나 접근되었는지 확인하는 코드이다.
실행 결과
Parent::publicMethod
Parent::protectedMethod
== Parent 메소드 ==
publicValue = 1
protectedValue = 2
defaultValue = 0
privateValue = 0
Parent.defaultMethod
Parent.privateMethod
== Parent 메소드 끝 ==
접근 제어자 - 필드
- publicValue: 필드가 public 제어자로 접근 허용하였다.
- protectedValue: 필드가 protected 상속 관계로 접근 허용하였다.
- 상속 관계가 아닐 시 같은 패키지에 있다면 접근을 허용된다.
- defaultValue: 필드가 default 제어자로 접근을 허용하지 않았다.
- 부모와 자식 패키지가 다르다.
- privateValue: 필드가 private 제어자로 접근을 허용하지 않았다.
- 모든 외부 접근을 차단하므로 접근할 수 없다.
접근 제어자 - 메소드
- 메소드 호출은 Child.call() 메인에서 호출
- 호출한 printParent() 메소드는 자신에게 없으므로 부모에게 메소드를 찾는다.
- 상속된 부모의 메소드를 찾았으므로 printParent() 메소드를 호출한다.
- printParent 메소드는 부모 클래스의 소유자로 private 제어자를 포함한 모든 것을 접근을 허용하고 있다.
접근 제어자의 메모리 구조
앞서 말한 printParent() 메소드 호출을 Child.call() 자식 클래스에서 호출하는 것을 살펴보았다. 같은 메모리 공간을 사용한다 하더라도 부모 클래스랑 자식 클래스는 방을 나누어서 접근제어자가 다르다는 것을 알 수 있다.
