제어자는 어떤 것들이 있으며, 어떻게 사용할까?
제어자 (Modifier)
--
제어자는
클래스, 변수, 메서드 등에 특정한 동작인 속성을 부여하는 키워드로 부가적인 의미를 추가적으로 부여한다.
제어자 종류
- 접근 제어자 (Access Modifiers)
- 기타 제어자 (Non-Access Modifiers)
--
접근 제어자 (Access Modifiers)
--
접근 제어자는
클래스, 변수, 메서드에 대한 접근에 대한 제한을 설정하는 키워드다.
접근 제어자 종류
- public : 접근 제한없이 어디서든 접근 가능
- protected : 같은 패키지 내의 클래스 or 다른 패키지의 자식 클래스에서 접근 가능
- default (기본값) : 같은 패키지 내에서만 접근 가능
- private : 같은 클래스 내에서만 접근 가능
protected 접근 제어자는
같은 패키지 내에서만 접근할 수 있지만
만약 다른 패키지에서 해당 protected 접근 제어자를 가지고 있는 클래스를 상속 받은 자식 클래스가 있다면
다른 패키지더라도 자식 클래스에서는 접근할 수 있다.
default 접근 제어자는 기본값으로
접근 제어자를 생략하면 자동으로 default로 설정된다.
참고
클래스에는 접근 제어자 protected와 private를 사용할 수 없다.
접근 제어자 기본 형식
접근제어자 class 클래스명 { ... }
접근제어자 반환타입 메서드명() { ... }
접근제어자 타입 변수명;
public class TestClass {
int age; // 접근 제어자 생략으로 자동 default 지정
protected void start() {
String name = "홍길동"; // 접근 제어자 생략으로 자동 default 지정
private String gender = "남";
System.out.println(name + gender);
}
}
만약 생성자에 private 접근 제어자로 지정하면
해당 클래스의 접근 제어자가 public이더라도
생성자에 접근을 외부에서 접근을 못하니 객체 생성이 불가능하다.
반대로
변수에 private 접근 제어자로 지정하여 외부에서 접근이 불가능하지만
같은 클래스에 있는 public 접근 제어의 메서드를 통해 가져올 수도 있다.
--
기타 제어자 (Non-Access Modifiers)
--
기타(그외) 제어자는
접근 제어와는 무관하게
해당 크래스나 멤버의 동작을 정의하는 역할을 하는 키워드다.
접근 제어자는 한 번에 하나만 정의할 수 있지만
기타 제어자는 한 번에 여러개 정의할 수 있다.
ex) public static final int a = 100;
대표적인 기타 제어자
- static
- final
- abstract
기타 제어자 기본 형식
기타제어자 class 클래스명 { ... }
기타제어자 반환타입 메서드명() { ... }
기타제어자 타입 변수명;
static
"클래스의" or "공통적인"의 의미를 가진 키워드로
클래스 차원에서 공유하여 객체 생성 없이 접근이 가능하며
해당 클래스의 모든 객체에서 공유하므로 접근해서 사용할 수 있다.
static 사용 가능한 파트
- 변수
- 메서드
- 초기화 블록
특징
- 해당 클래스의 모든 객체에서 공유하여 사용 가능 (즉, 클래스 자체에 속하여 사용)
- 객체 생성없이 바로 해당 클래스 이름을 통해 직접 호출 가능
- static를 선언한 멤버(메서드)에서는 static이 아닌 멤버(인스턴스 멤버)에 접근 불가
예시 코드
class StaticTest {
static int width = 200; // 클래스 변수
static int height = 100;
static { // 클래스 초기화 블록
...
}
static int max(int a, int b) { // 클래스 메서드
return a > b ? a : b;
}
}
final
"마지막의" or "변경될 수 없는"이라는 의미를 가진 키워드로
한 번 초기화(값 지정)를 하면 더 이상 변경을 불가능하게 한다.
final 사용 가능한 파트 (거의 모든 대상에 사용 가능)
- 클래스 : 상속 불가능 (자식 클래스 정의 불가능)
- 메서드 : 오버라이딩 불가능
- 변수 : 초기화 후 값 변경 불가능
예시 코드
final class FinalTest { // 부모가 될 수 없는 클래스
final int MAX_SIZE = 10; // 상수 (멤버변수)
final void getMaxSize() { // 오버라이딩 불가한 메서드
final int LV = MAX_SIZE; // 상수 (지역변수)
return MAX_SIZE;
}
}
abstract
"추상의" or "미완성의"라는 의미를 가진 키워드로
선언만 작성하고 내용은 구현하지 않은 클래스나 메서드를 가리킬 때 사용한다.
abstract 사용 가능한 파트
- 클래스
- 메서드
abstract 클래스를 "추상 클래스",
abstract 메서드를 "추상 메서드"라고 부른다.
참고
abstract 키워드는 해당 클래스나 메서드가 미구현 상태임을 자바에게 명시적으로 알리기 위해 사용된다.
그렇다고 구현된(구현부 완성) 메서드나 클래스에 abstract 키워드를 붙여 객체 생성을 못하도록 하는 것은 불가능하다.
꼭 미구현된(구현부가 없는) 메서드나 클래스에만 abstract 키워드를 붙일 수 있다.
추상 메서드는
구현부(몸체인 블록) 없이 선언만 작성한 메서드를 말한다.
추상 메서드를 사용하기 위해서는 해당 클래스를 상속 받아 오버라이딩을 통해
추상 메서드를 완전히 구현한 뒤에 사용할 수 있다.
추상 클래스는
클래스 내부에 추상 메서드가 하나라도 존재하는 클래스를 말한다.
(추상 클래스 내부에 모든 메서드가 추상 메서드일 필요는 없다.)
예시 코드
abstract class Animal { // 추상 클래스 (내부에 추상 메서드가 포함한 클래스)
abstract void sound(); // 추상 메서드 (구현부가 없는 메서드)
}
추상 클래스는
아직 구현이 미완성된 추상 메서드가 존재하니 불완전한 클래스다.
그래서 객체로 생성이 불가능하여
꼭 추상 클래스를 상속하여 해당 자식 클래스에서 오버라이딩을 통해 완전한 클래스로 구현한 다음에
해당 자식 클래스를 객체로 생성하여 사용해야 한다.
class Dog extends Animal {
@Override
void sound() {
System.out.println("moung");
}
}
Animal aaa = new Animal(); // 에러!! 추상 클래스 Animal를 객체로 생성 불가능
Dog dog = new Dog(); // 가능
추상 클래스, 메서드를 사용하는 이유는 무엇인가?
여러 클래스에게 공통적으로 사용할 수 있는 템플릿같은 클래스를 정의하기 위해서다.
즉, 여러 클래스에서 공통으로 사용할 정보 틀을 만들어만 놓고
해당 추상 클래스를 통해 상속 받은 자식 클래스들이 자기 입맛에 알맞게 구현하여 사용하기 위함이다.
위 추상 클래스 Animal 처럼 모든 동물 클래스들은 모두 sound() 메서드를 작성해야 하지만
그 내용은 전부 다를 것이므로 해당 sound() 메서드를 추상 메서드로 작성하여
자식 클래스가 직접 내용을 작성하도록 하는 것이다.
추상 클래스 정리
- 일반 클래스를 설계도에 비유를 한다면, 추상 클래스는 미완성 설계도다.
- 내부에 추상 메서드가 존재한다고 알려주는 역할
- 상속을 통해 자식 클래스에 의해서만 완성된 일반 클래스로 변환 가능
추상 클래스의 역할을 정리하자면
자식 클래스를 위해 기본 틀을 잡아주는 역할로
보통 여러 클래스가 공통으로 필요한 내용들을 가지고 틀을 만들어
다른 클래스들이 일일이 작성하지 않고 상속을 받아 활용할 수 있게 하는 클래스다.
추상 메서드 정리
- 선언부만 작성하고 구현부(블록)는 작성하지 않은 메서드 (즉, 중괄호와 내용이 없는 메서드)
구현부를 미완성으로 구현하지 않는 이유는
상속 받는 클래스에 따라 내용(구현부)이 달라질 수 있어
애초에 구현하지 않고 선언부만 작성하여 틀만 잡아 놓은 것이다.
--
접근 제어자와 기타 제어자의 조합
--
접근 제어자와 기타 제어자는 같은 것이 아니 별개의 제어자로
동시에 사용이 가능하다.
접근 제어자와 기타 제어자 기본 형식
접근제어자 기타제어자 [타입, 반환타입, class] [변수명, 메서드명, 클래스명];
기타제어자 접근제어자 [타입, 반환타입, class] [변수명, 메서드명, 클래스명];
접근 제어자와 기타 제어자의 작성 순서는 상관없지만
일반적으로 접근 제어자를 앞에 작성한다.
(접근제어자 기타제어자 ...)
다만 특정 접근 제어자와 기타 제어자를 같이 사용하면 충돌이 일어날 수 있어 주의하여 사용해야 한다.
예시
클래스에 final과 abstract를 동시에 작성
final 클래스는 상속(확장)이 불가능하지만
abstract 클래스는 상속을 통해 재정의를 해줘야 한다.
메서드에 private과 abstract를 동시에 작성
private 메서드는 자식 클래스에서 접근이 불가능하지만
abstract 메서드는 자식 클래스에서 재정의를 해줘야 한다.
메서드에 static과 abstract를 동시에 작성
static 메서드는 클래스 차원에서 동작하여 객체 없이 호출되므로 상속의 영향을 받지 않지만
abstract는 상속하여 자식 클래스에서 재정의로 구현을 해줘야 한다.
간단하게 static 메서드는 구현된 메서드에서만 사용할 수 있다.
메서드에 private과 final을 동시에 작성 (사용은 할 수 있지만 불요한 상황)
private 메서드는 애초에 자식클래스에게 상속하지 않아서 재정의(오버라이딩)를 못한다.
그래서 final 키워드를 굳이 사용하지 않아도 내용이 수정될 일이 없다.
--
'Language > Java' 카테고리의 다른 글
인터페이스 (1) | 2024.10.22 |
---|---|
다형성 (예시 : A opt = new B()) (0) | 2024.10.21 |
package와 import (+ static import) (1) | 2024.10.19 |
[클래스] 변수와 메서드 (+ 초기화 블록) (0) | 2024.10.18 |
상속 (+ super, super(), 포함 관계) (0) | 2024.10.17 |