접근제어자 복습
1. private: 해당 클래스 내부에서만 접근 가능
의미
- 해당 클래스 안에서만 접근 가능
- 같은 패키지에 있든, 상속을 받았든, 다른 클래스에서는 절대 접근 불가
- 완벽한 정보 은닉(Encapsulation)을 위한 제어자
예제 코드
class Person {
private String name = "John"; // private 필드 (Person 클래스 내부에서만 접근 가능)
public String getName() { // 외부에 공개하는 메서드
return name;
}
private void secretMethod() { // private 메서드 (Person 클래스 안에서만 호출 가능)
System.out.println("비밀 메서드 실행");
}
public void callSecretMethod() {
secretMethod(); // 클래스 내부에서는 private 메서드 호출 가능
}
}
public class Main {
public static void main(String[] args) {
Person p = new Person();
// System.out.println(p.name); // 컴파일 에러 (private 필드는 외부에서 직접 접근 불가)
System.out.println(p.getName()); // public 메서드를 통해 우회 접근 가능
// p.secretMethod(); // 컴파일 에러 (private 메서드 호출 불가)
p.callSecretMethod(); // 우회 메서드를 통해 호출 가능
}
}
포인트
- 정보 은닉 완벽 보장
- 외부에서 직접 접근을 차단하고, 반드시 공개된 메서드(public)를 통해서만 접근하도록 유도
- 안전한 캡슐화 설계에 필수
2. default: 같은 패키지 내에서만 접근 가능 (접근 제어자 생략 시)
의미
- 아무 접근 제어자도 안 쓰면 default
- 같은 패키지 안에서는 접근 가능
- 다른 패키지에서는 접근 불가
- 패키지 단위 모듈화를 위한 제어자
예제 코드
// mypackage/Person.java
package mypackage;
class Person { // 접근 제어자 생략 = default
String name = "John"; // default 필드
void sayHello() { // default 메서드
System.out.println("Hello, " + name);
}
}
// mypackage/Main.java
package mypackage;
public class Main {
public static void main(String[] args) {
Person p = new Person(); // 같은 패키지이므로 접근 가능
System.out.println(p.name); // 같은 패키지라 접근 가능
p.sayHello(); // 같은 패키지라 접근 가능
}
}
다른 패키지에서 접근 시
// 다른 패키지에서는 아래처럼 오류 발생
/*
// 다른패키지/OtherPackageClass.java
package 다른패키지;
import mypackage.Person; // ❌ 에러! 같은 패키지가 아니라서 import 자체가 불가
public class OtherPackageClass {
public static void main(String[] args) {
Person p = new Person(); // ❌ 접근 불가
}
}
*/
포인트
- 같은 패키지 내에서만 접근 가능
- 패키지 단위로 기능을 묶어서 외부 접근을 제한할 때 유용
- 외부 노출 최소화의 기본 전략으로 사용 가능
3. protected: 같은 패키지 또는 하위 클래스에서 접근 가능
의미
- 같은 패키지에서는 default처럼 접근 가능
- 다른 패키지라도 상속받은 자식 클래스라면 접근 가능
- 부모가 자식에게 상속해주고 싶은 중요한 데이터나 메서드에 주로 사용
예제 코드
부모 클래스 (parentpkg/Parent.java)
package parentpkg;
public class Parent {
protected String name = "John"; // protected 필드
protected void sayHello() { // protected 메서드
System.out.println("Hello, " + name);
}
}
같은 패키지 자식 클래스 (parentpkg/SamePackageChild.java)
package parentpkg;
public class SamePackageChild extends Parent {
public void greet() {
System.out.println(name); // 같은 패키지라 바로 접근 가능
sayHello(); // 같은 패키지라 바로 호출 가능
}
}
다른 패키지 자식 클래스 (childpkg/Child.java)
package childpkg;
import parentpkg.Parent;
public class Child extends Parent {
public void greet() {
System.out.println(name); // 다른 패키지지만 상속받아서 접근 가능
sayHello(); // 다른 패키지지만 상속받아서 호출 가능
}
}
다른 패키지에서의 사용 (childpkg/Main.java)
package childpkg;
public class Main {
public static void main(String[] args) {
Child c = new Child();
c.greet(); // 상속받은 메서드를 통해 protected 접근 가능
// c.name; // 컴파일 에러 (protected는 자식 클래스 내부에서만 접근 가능)
}
}
포인트
- protected는 상속 구조에서 자식 클래스에 필요한 정보만 전달할 때 사용
- 외부 클래스는 접근 불가
- 실무에서는 상속 구조를 최소화하려는 트렌드 때문에 많이 쓰이진 않음
- 프레임워크에서는 확장 포인트로 제공하는 경우 많음
4. public: 어디서나 접근 가능
의미
- 패키지와 상관없이 어디서든 접근 가능
- 완전한 공개
- 외부 API, 라이브러리 인터페이스 등에 주로 사용
예제 코드
mypackage/Person.java
package mypackage;
public class Person {
public String name = "John"; // public 필드
public void sayHello() { // public 메서드
System.out.println("Hello, " + name);
}
}
다른 패키지에서 접근 (otherpackage/Main.java)
package otherpackage;
import mypackage.Person;
public class Main {
public static void main(String[] args) {
Person p = new Person();
System.out.println(p.name); // 다른 패키지에서도 접근 가능
p.sayHello(); // 다른 패키지에서도 호출 가능
}
}
포인트
- 공개 API 설계할 때 기본으로 사용
- 과도한 공개는 캡슐화 위반
- 실무에서는 꼭 필요한 메서드만 공개하고, 나머지는 숨기는 방식으로 설계
접근제어자 복습
1. private: 해당 클래스 내부에서만 접근 가능
의미
예제 코드
포인트
2. default: 같은 패키지 내에서만 접근 가능 (접근 제어자 생략 시)
의미
예제 코드
다른 패키지에서 접근 시
포인트
3. protected: 같은 패키지 또는 하위 클래스에서 접근 가능
의미
예제 코드
부모 클래스 (parentpkg/Parent.java)
같은 패키지 자식 클래스 (parentpkg/SamePackageChild.java)
다른 패키지 자식 클래스 (childpkg/Child.java)
다른 패키지에서의 사용 (childpkg/Main.java)
포인트
4. public: 어디서나 접근 가능
의미
예제 코드
mypackage/Person.java
다른 패키지에서 접근 (otherpackage/Main.java)
포인트