private
,package-private
,protected
, public
이다.final
과 관련이 있으며 해당 개념은 아이템 17에 나온다.[핵심 정리]
프로그램 요소의 접근성은 가능한 최소한으로 하라. 꼭 필요한 것만 골라서 최소한의 public API를 설계하자. 그 외에는 클래스, 인터페이스, 멤버가 의도치 않게 API로 공개되는 일이 없도록 해야한다. public 클래스의 경우엔 상수용 public static final 필드 외에는 어떠한 public 필드도 가져서는 안 된다. public static final 필드가 참도하는 객체가 불변인지 확인하라.
캡슐화
또는 정보 은닉
이라고 부른다.접근 제한자
라는 접근 제어 매커니즘을 제공한다.Package-private
의 경우엔 default값으로 굳이 접근 제한자를 작성하지 않는다면 package-private이다.public
/package-private
로 선언하여 사용할 수 있다.public
을 붙여 사용하면 해당 클래스, 인터페이스는 open API가 된다. package-private
을 붙여 사용하면 해당 클래스, 인터페이스는 해당 패키지 안에서만 사용이 가능하게 된다.class PackagePrivateClass{
}
//탑 레벨 클래스
public class TopLevelPrivateClass {
// 정보 은닉을 위한 private 클래스
private class PrivateClass{
}
}
package-private
로 선언해서 내부 구현으로 만들자.public
으로 선언한 클래스나 인터페이스의 경우엔 공개 API가 되기 때문에 계속해서 하위 호환을 위해 영원히 관리해주어야 한다.package test;
//Package-private class
class PackagePrivateClass {
void packagePrivateMethod(){
System.out.println("package-private Method");
}
}
package-private
접근 제한자를 사용한 경우에 다른 패키지에서는 해당 클래스를 사용할 수 없다.package test;
public class TopLevelPrivateClass {
public void Test() {
//package-private의 경우엔 동일 패키지 내에서 사용 가능
PackagePrivateClass packagePrivateClass = new PackagePrivateClass();
packagePrivateClass.packagePrivateMethod();
//private의 경우엔 동일 탑 레벨 클래스, 인터페이스 내에서만 사용 가능
PrivateClass privateClass = new PrivateClass();
privateClass.privateMethod();
}
private class PrivateClass{
private void privateMethod(){
System.out.println("private Method");
}
}
}
private
접근 제한자를 사용한 경우에 동일 레벨 클래스, 인터페이스에서만 사용이 가능하다.private
클래스에 접근할 수 없다.private
: 멤버 선언 후 탑레벨 클래스에서만 접근 package-private
: 멤버가 소속된 패키지 안의 모든 클래스에서 접근할 수 있다. 이때 접근 제한자를 명시하지 않았다면 접근 제한자는 package-private이다. (단 인터페이스의 멤버의 경우엔 명시하지 않은 경우 public이 적용된다.)protected
:package-private
의 접근 범위를 포함하며 이 멤버를 선언한 클래스의 하위 클래스에서도 접근 가능하다.public
: 모든 곳에서 접근할 수 있다.public class PublicClass{
private int privateField;
int packagePrivateField; //package-private field
protected int protectedField;
public int publicField;
}
필드가 가변 객체를 참조 - 코드
package test;
import org.junit.jupiter.api.Test;
import java.util.ArrayList;
import java.util.List;
public class MutableObject {
List<String> mutableField = new ArrayList<>(List.of("hello"));
@Test
void mutableObjectTest(){
MutableObject mutableObject = new MutableObject();
mutableObject.mutableField.add("mutable Field World!");
System.out.println("가변 객체의 변경 상태: "+mutableObject.mutableField);
}
}
필드가 가변 객체를 참조 - 결과
final이 아닌 public으로 선언 - 코드
package test;
import org.junit.jupiter.api.Test;
public class MutableObject {
public StringBuilder stringBuilder = new StringBuilder("hello");
@Test
void mutableObjectTest(){
MutableObject mutableObject = new MutableObject();
mutableObject.stringBuilder.append(", World!");
System.out.println("가변 객체의 변경 상태: "+mutableObject.stringBuilder.toString());
}
}
final이 아닌 public으로 선언 - 결과
package test;
public class PublicTopLevelClass {
}
package test;
class PackagePrivateTopLevelClass {
}
public class PublicClass{
private int privateField;
int packagePrivateField; //package-private field
protected int protectedField;
public int publicField;
}
package test;
public class MutableObject {
private void PrivateMethod(){
}
void PackagePrivateMethod(){
}
protected void ProtectedMethod(){
}
public void PublicMethod(){
}
}
package test;
public class TopLevelClass {
private class PrivateClass{
}
class PackagePrivateClass{
}
protected class ProtectedClass{
}
public class PublicClass{
}
}