일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- sorting
- Class
- greedy
- bit manipulation
- Math
- Data Structure
- Tree
- hash table
- Matrix
- SQL
- 코딩테스트
- dynamic programming
- 코테
- Counting
- implement
- Stack
- database
- 자바
- simulation
- array
- Number Theory
- string
- 파이썬
- two pointers
- Binary Search
- Method
- java
- Binary Tree
- geometry
- 구현
- Today
- Total
코린이의 소소한 공부노트
제어자 본문
영어에는 여러 품사가 있는데, 그중 형용사는 명사 앞 또는 뒤에 붙어서 명사를 수식해주는 역할을 한다.
갑자기 영어 시간이 된...것은 아니고, 이번에 공부할 제어자가 형용사 역할을 하기 때문에 잠깐 언급해본 것뿐이다..
제어자는
1. 클래스와 클래스의 멤버(변수, 메서드)에 부가적인 의미를 부여해준다.
- 예시) public: '공공의, 공적인'이라는 뜻으로, 이것을 붙인 클래스나 변수, 메서드는 누구나 사용할 수 있는 상태가 됨
- 나머지는 아래에서 자세히 설명 예정
2. 접근 제어자와 그 외 제어자로 나눌 수 있다.
- 접근 제어자: public, protected, default(아무것도 붙이지 않으면 됨), private
- 그 외 제어자: static, final, abstract, native, transient, synchronized, volatile, strictfp
3. 제어자는 클래스나 변수, 메서드 앞에 붙여 사용한다.
- 하나의 대상에 여러 제어자를 같이 사용할 수 있음(접근 제어자는 4개 중 1개만 사용 가능)
- 순서는 상관없지만, 보통 접근 제어자를 제일 앞에 씀
public static final int MAX = 100; // 접근 제어자가 맨 앞
static final public int MIN = 0; // 접근 제어자가 맨 뒤
먼저 볼 것은 일반 제어자인데, 가장 많이 쓰는 3가지만 살펴보려 한다.
[static - 클래스의, 공통적인]
1. static + 멤버 변수
- 모든 인스턴스에 공통적으로 사용되는 클래스 변수(cv)가 된다.
- cv는 인스턴스를 생성하지 않고도 사용 가능하다.
- cv는 클래스가 메모리에 로드될 때 생성된다.
2. static + 메서드
- 인스턴스를 생성하지 않고도 호출이 가능한 스태틱 메서드(sm)가 된다. = 클래스 메서드
- sm 내에서는 iv, im을 직접 사용할 수 없다.
class StaticClass{
static int i = 100; // 클래스 변수
static { // 클래스 초기화 블럭
// static 변수의 복잡한 초기화
}
static int max(int a, int b) { // 클래스 메서드
return a>b ? a : b;
}
}
[final - 마지막의, 변경될 수 없는]
1. final + 클래스
- 변경될 수 없는 클래스, 확장될 수 없는 클래스가 된다.
- 그렇기 때문에 다른 클래스의 조상이 될 수 없다. -> 마지막 클래스
- 예시) String 클래스, Math 클래스
2. final + 메서드
- 변경될 수 없는 메서드가 된다.
- 그렇기 때문에 오버라이딩을 통해 재정의 될 수 없다.
3. final + 변수
- 값을 변경할 수 없는 상수가 된다.
- 보통 변수 이름을 대문자로 표기한다.
final class FinalClass{ // 조상이 될 수 없는 클래스
final int LIMIT = 200; // 값을 변경할 수 없는 멤버변수(상수)
final int getLimit() { // 오버라이딩할 수 없는 메서드
final int LM = LIMIT; // 값을 변경할 수 없는 지역변수(상수)
return LM;
}
}
[abstract - 추상의, 미완성의]
1. abstract + 메서드
- 선언부만 작성하고 구현부는 작성하지 않은 추상 메서드임을 알려준다.
2. abstract + 클래스
- 클래스 내에 추상 메서드가 선언되어있음을 의미한다.
- 클래스 내의 메서드가 미완성이므로 클래스도 미완성이라는 뜻이다.
- 미완성 설계도이기 때문에 객체 생성을 할 수 없다.
-> 추상 클래스를 상속받아서 완전한 클래스(구상 클래스)로 만들어야 객체 생성이 가능해진다.
abstract class AbstractClass{ // 추상 클래스(추상 메서드를 포함한 클래스)
abstract void doSomething(); // 추상 메서드(구현부가 없는 메서드)
}
// 메인 내부
AbstractClass a = new AbstractClass(); // error. Cannot instantiate the type AbstractClass
지금부터 볼 접근 제어자는 이름 그대로 해당 클래스/메서드/변수를 사용할 수 있는 범위를 제어하는 역할을 한다. 접근 제어자의 영어 뜻과 함께 접근 가능 범위를 여러 각도에서 설명해보겠다.
1. private: '사적인, 은밀한'
- 같은 클래스 내에서만 접근이 가능하다.
- private로 선언된 것의 유효 범위는 해당 클래스 내부이다.
- 다른 클래스에서는 접근할 수 없다.
2. default: '기본' (-> 접근 제어자를 아무것도 붙이지 않은 것)
- 같은 패키지 내에서만 접근이 가능하다.
- 접근 제어자를 붙이지 않으면 그것의 유효 범위는 해당 패키지 내부이다.
- 다른 패키지에서는 접근할 수 없다.
3. protected
- 같은 패키지 내에서, 그리고 다른 패키지의 자손 클래스에서 접근이 가능하다.
- protected로 선언된 것의 유효 범위는 해당 패키지 내부 + 다른 패키지에 선언된 자손 클래스 내부이다.
- 다른 패키지에 있으면서 상속받지 않은 클래스에서는 접근할 수 없다.
4. public
- 접근 제한이 없다.
- public으로 선언된 것의 유효 범위는 프로젝트 전체다.
- 모든 패키지에서 접근 가능하다.
아래 코드를 읽고 그림으로 설명된 접근 제어자의 범위를 보면 애매하게 이해된 부분도 명확하게 알 수 있게 된다! 코드가 조금 길기 때문에 천천히 읽어보는 것을 추천한다. 범위를 정하는 기준점이 되는 클래스는 Parent 클래스이다.
// Parent.java
package pkg1;
public class Parent{ // 접근 제어자가 default가 아닌 이유는 설명 끝부분에
private int pvt; // 같은 클래스
int dft; // 같은 패키지
protected int prt; // 같은 패키지 + 다른 패키지 자손
public int pub; // 전체
public void printMembers() {
System.out.println(pvt); // OK
System.out.println(dft); // OK
System.out.println(prt); // OK
System.out.println(pub); // OK
}
}
1. private의 범위 확인 - pkg1 패키지에 Parent라는 public 클래스를 만들었다.
1) 접근 제어자 별로 정수형 변수를 만들었다.
2) public 메서드도 1개 만들었다. 이 메서드는 4개의 변수를 다 출력하는 역할을 한다.
- 같은 클래스 내부이기 때문에 pvt에 접근 가능 -> OK
- 같은 클래스 -> 같은 패키지(pkg1) 내부이기 때문에 dft에 접근 가능 -> OK
- 같은 패키지 내부이기 때문에 prt에 접근 가능 -> OK
- public은 접근 제한이 없으므로 pub에 접근 가능 -> OK
// Parent.java
package pkg1;
class Test1 {
public static void main(String[] args) {
Parent p = new Parent();
System.out.println(p.pvt); // error
System.out.println(p.dft); // OK
System.out.println(p.prt); // OK
System.out.println(p.pub); // OK
}
}
2. default의 범위 확인 - pkg1 패키지에 Test1라는 default 클래스를 만들었다.
1) 메인에서 Parent 객체 p를 생성했다.
2) p를 이용해 4가지 변수에 접근해보기로 했다.
- Parent와 다른 클래스이기 때문에 pvt에 접근 불가 -> error
- 같은 패키지(pkg1) 내부이기 때문에 dft에 접근 가능 -> OK
- 같은 패키지 내부이기 때문에 prt에 접근 가능 -> OK
- public은 접근 제한이 없으므로 pub에 접근 가능 -> OK
// Test2.java
package pkg2;
import pkg1.Parent; // 상속을 위한 import
class Child extends Parent{
public void printMembers() {
System.out.println(pvt); // error
System.out.println(dft); // error
System.out.println(prt); // OK
System.out.println(pub); // OK
}
}
3. protected의 범위 확인 - pkg2 패키지에 Child라는 default 클래스를 만들었다.
1) Parent 클래스를 상속받았기 때문에, Parent 클래스의 모든 멤버를 이용할 수 있다.
2) 접근 가능 여부를 확인해보기 위해 Parent 클래스에 있던 메서드를 똑같이 써봤다.
- Parent와 다른 클래스이기 때문에 pvt에 접근 불가 -> error
- 다른 패키지(pkg1 != pkg2) 내부이기 때문에 dft에 접근 불가 -> error
- 다른 패키지(pkg1 != pkg2)지만 pkg1의 클래스(Parent)를 상속받은 자손이기 때문에 prt에 접근 가능 -> OK
- public은 접근 제한이 없으므로 pub에 접근 가능 -> OK
// Test2.java
package pkg2;
import pkg1.Parent; // 객체 생성을 위한 import
public class Test2 {
public static void main(String[] args) {
Parent p = new Parent();
System.out.println(p.pvt); // error
System.out.println(p.dft); // error
System.out.println(p.prt); // error
System.out.println(p.pub); // OK
}
}
4. public의 범위 확인 - pkg2 패키지에 Test2라는 public 클래스를 만들었다.
1) Parent 클래스를 import하고 메인에서 p라는 객체를 만들었다.
2) p를 이용해 4가지 변수에 접근해보기로 했다.
- Parent와 다른 클래스이기 때문에 pvt에 접근 불가 -> error
- 다른 패키지(pkg1 != pkg2) 내부이기 때문에 dft에 접근 불가 -> error
- 다른 패키지(pkg1 != pkg2) + pkg1의 클래스를 상속받지 않았기 때문에 prt에 접근 불가 -> error
- public은 접근 제한이 없으므로 pub에 접근 가능 -> OK
위 코드와 설명을 읽고, 색깔로 구분된 접근 제어자별 범위를 살펴보면 충분히 이해가 될 것이다.
[파일 TMI]
1. Child 클래스가 상속받기 위해서는 다른 패키지에 있는 Parent 클래스가 public으로 선언되어야 한다.
2. Parent 클래스와 같은 패키지 내의 다른 클래스가 있어야 defualt의 범위를 확인할 수 있다.
-> 그래서 메인은 Test1 클래스에 있지만 pkg1이 있는 파일 이름이 Parent 클래스가 되었다.
3. Child 클래스는 protected의 범위, Test2 클래스는 public의 범위를 확인하기 위해 만든 클래스이다.
'Java' 카테고리의 다른 글
다형성 (0) | 2022.04.19 |
---|---|
접근 제어자를 이용한 캡슐화 (0) | 2022.04.18 |
임포트와 스태틱 임포트 (0) | 2022.04.14 |
패키지와 클래스 경로 (0) | 2022.04.13 |
생성자 super() vs 참조변수 super (0) | 2022.03.23 |