접근 제어자(Access Modifier)는 클래스, 메서드, 변수의 접근 범위를 제어하는 키워드다. 각각 클래스, 메서드, 변수별로 접근 제어자의 적용 범위가 달라진다.
1. 클래스의 접근 제어자
- public
- 어떤 패키지(폴더)에서든 접근 가능
- 한 소스 파일(.java)에는 단 하나의 public 클래스만 존재 가능
- 파일명은 반드시 public 클래스의 이름과 같아야 함
- default(package-private)
- 접근 제어자를 명시하지 않은 경우의 기본값
- 같은 패키지 내에서만 접근 가능
src/
├── com.example.main/ << package(패키지)
│ ├── Main.java (public class Main) << class(클래스)
│ └── Helper.java (default class Helper) << 클래스
│
├── com.example.user/ << 패키지
│ ├── User.java (public class User) << 클래스
│ └── UserUtil.java (default class UserUtil) << 클래스
│
└── com.example.admin/ << 패키지
├── Admin.java (public class Admin) << 클래스
└── AdminUtil.java (default class AdminUtil) << 클래스
클릭하여 코드 복사
실제로 패키지는 폴더를 기준으로 하지만 폴더가 있다고 모두 패키지는 아니다. 실제로 패키지로 작동하려면 파일 안에 패키지의 범위를 선언해줘야 한다. 그리고 그 선언한 부분이 패키지의 단위가 되기 때문에 이 값이 달라지면 공유되는 범위도 달라지게 된다.
src/main/java/
└── com/
└── example/
│ ├── main/
│ │ ├── Main.java (package com.example.main;)
│ │ └── Helper.java (package com.example.main;)
│ │
│ └── user/
│ └── User.java (package com.example.user;)
│
other/
└── example/
└── Main/
└── Main2.java (package other.example.main;)
클릭하여 코드 복사
예를 들어 이런 구조라면
Main.java 파일에서 패키지를 com.example.main이라고 선언한다면 패키지의 범위는 com 폴더까지가 된다.
// Main.java
package com.example.main; // 이 선언으로 인해 com/ 폴더까지가 패키지 범위가 됨
클릭하여 코드 복사
그런데 여기서 해당 파일 내부의 class를 public으로 선언한다면 해당 클래스는 전역 클래스가 되어서 '모든' 패키지(폴더)에서 접근할 수 있다. 즉 패키지 범위 밖이어도 접근이 가능하다.
하지만 public이 아니라 default 클래스로 선언한다면 해당 패키지 내에서만 공유가 가능하다. 즉 아래쪽의 other 폴더 부분에서는 해당 클래스에 접근할 수 없게된다.
// com/example/main/Main.java
package com.example.main;
public class Main { // 전역 클래스: 모든 패키지에서 접근 가능
// ...
}
class Helper { // default 클래스: com/ 폴더 이하의 패키지에서만 접근 가능
// ...
}
// other/example/main/Main2.java
package other.example.main;
import com.example.main.Main; // public 클래스는 패키지 범위 밖에서도 import 가능
// import com.example.main.Helper; // default 클래스는 패키지 범위 밖이라 import 불가
클릭하여 코드 복사
또한 example 부분은 정해진 것이 아니라 마음대로 바꿀 수 있지만 보통은 컨벤션(Convention)에 따라서 명명한다.
// 권장되는 패키지 명명 규칙
package com.company.project; // 회사 도메인 거꾸로 + 프로젝트명
package org.apache.commons; // 조직 도메인 거꾸로 + 프로젝트명
package edu.university.dept; // 교육기관 도메인 거꾸로 + 부서명
// 권장되지 않는 방식
package MyPackage; // 대문자로 시작
package my_package; // 언더스코어 사용
package 한글패키지; // 영문이 아닌 문자 사용
클릭하여 코드 복사
2. 메서드의 접근 제어자
클래스 내부의 함수(메서드)도 클래스와 마찬가지로 접근 제어자를 사용한다. 다만 범위(스코프)가 좀 더 구체적이다. 각자 접근 제어자별로 범위가 달라지지만 기본적으로 클래스 안에서 사용되는 것이기 때문에 클래스에 붙어있는 접근 제어자의 영향을 받는다.
- public
- 가장 개방적인 접근 제어자로, 프로젝트 어디서든 접근이 가능
- 패키지가 다르더라도 import만 하면 자유롭게 사용할 수 있다
- 클래스가 default면 같은 패키지 내에서만 접근 가능
- 해당 메서드가 속한 클래스가 public인 경우에만 다른 패키지에서 접근 가능
- API로 공개하는 클래스나 메서드에 주로 사용된다
- default(package-private)
- 접근 제어자를 명시하지 않을 때의 기본값
- 같은 패키지 내에서만 접근이 가능하며, 다른 패키지에서는 접근이 불가능
- 패키지를 하나의 모듈로 보고 그 안에서만 접근을 허용할 때 사용
- private
- 가장 제한적인 접근 제어자로, 같은 클래스 내에서만 접근이 가능
- 외부에서는 절대 직접 접근이 불가능하며, 철저한 캡슐화가 필요한 내부 구현에 사용
- protected
- 상속 관계에 초점을 맞춘 접근 제어자
- 같은 패키지 내에서는 자유롭게 접근 가능하고, 다른 패키지라도 자식 클래스 내부에서는 접근이 가능
- 단, 다른 패키지에서 인스턴스를 통한 접근은 불가능
public class Example {
public String publicVar = "누구나 접근 가능";
protected String protectedVar = "같은 패키지 + 자식 클래스만 접근 가능";
String defaultVar = "같은 패키지만 접근 가능";
private String privateVar = "이 클래스 안에서만 접근 가능";
public void publicMethod() {
System.out.println("누구나 접근 가능한 메서드");
}
protected void protectedMethod() {
System.out.println("같은 패키지 + 자식 클래스만 접근 가능한 메서드");
}
void defaultMethod() {
System.out.println("같은 패키지만 접근 가능한 메서드");
}
private void privateMethod() {
System.out.println("이 클래스 안에서만 접근 가능한 메서드");
}
}
클릭하여 코드 복사
3. 접근 범위 비교
접근제어자 | 같은 클래스 | 같은 패키지 | 다른 패키지의 자식 클래스 |
다른 패키지 |
---|---|---|---|---|
public | O | O | O | O |
protected | O | O | O | X |
default | O | O | X | X |
private | O | X | X | X |
4. 변수의 접근 제어자
기본적으로 접근 제어자의 기능은 메서드와 동일하게 적용된다.
하지만 메서드 내부에서 선언되는 지역변수의 경우 별도로 접근 제어자를 붙이지 않는다. 이경우 변수의 범위가 해당 메서드 안쪽으로 제한되기 때문이다. 또한 지역 변수의 범위(스코프)는 해당 코드 블록 내로 제한된다.
public class Example {
// 1. 멤버 변수(필드): 접근 제어자 사용 가능
public int publicVar; // 어디서든 접근 가능
private String privateVar; // 같은 클래스 내에서만 접근 가능
protected double protectedVar; // 같은 패키지 + 자식 클래스에서 접근 가능
int defaultVar; // 같은 패키지에서만 접근 가능
public void method() {
// 2. 지역 변수: 접근 제어자 사용 불가
int localVar = 10; // 메서드 내에서만 사용 가능
if(true) {
int blockVar = 20; // if 블록 내에서만 사용 가능
}
// blockVar 사용 불가 - 블록을 벗어남
}
}
클릭하여 코드 복사
5. 현대 프로그래밍에서의 의미
- 순수 함수: 동일 입력 → 동일 출력 보장
- 메서드: 객체의 상태에 따라 다른 결과 가능
6. 언어별 차이
언어 | 용어 사용 |
---|---|
Java | 메서드 |
Python | 메서드/함수 |
JavaScript | 메서드/함수 |
C | 함수 |
C++ | 멤버함수/함수 |
7. 실무적 고려사항
- 객체지향: 메서드 사용
- 함수형 프로그래밍: 순수 함수 지향
- 하이브리드: 상황에 맞게 선택
결론: 메서드는 단순히 함수의 객체지향 버전이 아니라, 객체의 행위를 표현하는 고유한 개념이다. 객체의 상태를 변경하거나 접근할 수 있는 능력이 있다는 점에서 순수 함수와는 다른 특성을 가진다.
'Java > 자바 학습' 카테고리의 다른 글
자바 컬렉션 프레임워크 (0) | 2025.05.07 |
---|---|
자바의 예외 처리 (0) | 2025.05.07 |
메서드 vs 함수 (0) | 2025.05.01 |
클래스의 final (0) | 2025.05.01 |
자바의 클래스(Class) (0) | 2025.05.01 |